Repository: web2py/web2py

Issue:
Cron does not work in Git master
Attempt to enable  cron with -Y leads to following stack trace:

 python2.7 web2py.py -Y  -i 0.0.0.0
web2py Web Framework
Created by Massimo Di Pierro, Copyright 2007-2017
Version 2.14.6-stable+timestamp.2016.05.09.19.18.48
Database drivers available: sqlite3, imaplib, pyodbc, pymysql, pg8000
Traceback (most recent call last):
  File "web2py.py", line 33, in <module>
    gluon.widget.start(cron=True)
  File "/home/alexiade/build/homely/web2py_git/gluon/widget.py", line 1184, in start
    newcron.hardcron(options.folder).start()
  File "/home/alexiade/build/homely/web2py_git/gluon/newcron.py", line 85, in __init__
    crondance(self.path, 'hard', startup=True)
  File "/home/alexiade/build/homely/web2py_git/gluon/newcron.py", line 284, in crondance
    token = Token(cron_path)
  File "/home/alexiade/build/homely/web2py_git/gluon/newcron.py", line 119, in __init__
    fileutils.write_file(self.path, '', 'wb')

Removing gluon. prefix from the relevant import in newcron.py fixes it...



Discussion:

Resolving patch:
diff --git a/gluon/newcron.py b/gluon/newcron.py
--- a/gluon/newcron.py
+++ b/gluon/newcron.py
@@ -19,13 +19,14 @@
 import re
 import datetime
 import platform
-import gluon.fileutils
 from functools import reduce
 try:
     import cPickle as pickle
 except:
     import pickle
 from gluon.settings import global_settings
+from gluon import fileutils
+from gluon._compat import to_bytes
 from pydal.contrib import portalocker
 
 logger = logging.getLogger("web2py.cron")
@@ -116,7 +117,7 @@ class Token(object):
     def __init__(self, path):
         self.path = os.path.join(path, 'cron.master')
         if not os.path.exists(self.path):
-            fileutils.write_file(self.path, '', 'wb')
+            fileutils.write_file(self.path, to_bytes(''), 'wb')
         self.master = None
         self.now = time.time()
 
@@ -139,7 +140,7 @@ def acquire(self, startup=False):
         if portalocker.LOCK_EX is None:
             logger.warning('WEB2PY CRON: Disabled because no file locking')
             return None
-        self.master = open(self.path, 'rb+')
+        self.master = fileutils.open_file(self.path, 'rb+')
         try:
             ret = None
             portalocker.lock(self.master, portalocker.LOCK_EX)
@@ -167,6 +168,7 @@ def release(self):
         """
         Writes into cron.master the time when cron job was completed
         """
+        ret = self.master.closed
         if not self.master.closed:
             portalocker.lock(self.master, portalocker.LOCK_EX)
             logger.debug('WEB2PY CRON: Releasing cron lock')
@@ -177,6 +179,7 @@ def release(self):
                 pickle.dump((self.now, time.time()), self.master)
             portalocker.unlock(self.master)
             self.master.close()
+        return ret
 
 
 def rangetolist(s, period='min'):


Test patch:
diff --git a/gluon/tests/__init__.py b/gluon/tests/__init__.py
--- a/gluon/tests/__init__.py
+++ b/gluon/tests/__init__.py
@@ -22,6 +22,7 @@
 from .test_web import *
 from .test_sqlhtml import *
 from .test_scheduler import *
+from .test_cron import *
 
 if sys.version[:3] == '2.7':
     from .test_is_url import *
diff --git a/gluon/tests/test_cron.py b/gluon/tests/test_cron.py
new file mode 100644
--- /dev/null
+++ b/gluon/tests/test_cron.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+""" Unit tests for cron """
+import unittest, os
+from gluon.newcron import Token, crondance
+
+class TestCron(unittest.TestCase):
+
+
+    def test_Token(self):
+        appname_path = os.path.join(os.getcwd(), 'applications', 'welcome')
+        t = Token(path=appname_path)
+        self.assertNotEqual(t.acquire(), None)
+        self.assertFalse(t.release())
+        self.assertEqual(t.acquire(), None)
+        self.assertTrue(t.release())
+        return
+        
+    def test_crondance(self):
+        #TODO update crondance to return something 
+        crondance(os.getcwd())
+        
+