浏览代码

Fix KeyError when starting celery beat (#3481)

The shelve module does not accept byte literals as keys on Py3, and
does not accept unicode literals as keys on Py2, so instead the
"informal" string is used for both.

There is a description about informal strings here:
https://docs.python.org/3/library/stdtypes.html#str
Alli 8 年之前
父节点
当前提交
d87f9db737
共有 3 个文件被更改,包括 20 次插入19 次删除
  1. 1 0
      CONTRIBUTORS.txt
  2. 13 13
      celery/beat.py
  3. 6 6
      t/unit/app/test_beat.py

+ 1 - 0
CONTRIBUTORS.txt

@@ -218,3 +218,4 @@ Adriano Martins de Jesus, 2016/06/22
 Kevin Richardson, 2016/06/29
 Kevin Richardson, 2016/06/29
 Andrew Stewart, 2016/07/04
 Andrew Stewart, 2016/07/04
 Xin Li, 2016/08/03
 Xin Li, 2016/08/03
+Alli Witheford, 2016/09/29

+ 13 - 13
celery/beat.py

@@ -433,55 +433,55 @@ class PersistentScheduler(Scheduler):
 
 
         for _ in (1, 2):
         for _ in (1, 2):
             try:
             try:
-                self._store[b'entries']
+                self._store[str(b'entries')]
             except KeyError:
             except KeyError:
                 # new schedule db
                 # new schedule db
                 try:
                 try:
-                    self._store[b'entries'] = {}
+                    self._store[str(b'entries')] = {}
                 except KeyError as exc:
                 except KeyError as exc:
                     self._store = self._destroy_open_corrupted_schedule(exc)
                     self._store = self._destroy_open_corrupted_schedule(exc)
                     continue
                     continue
             else:
             else:
-                if b'__version__' not in self._store:
+                if str(b'__version__') not in self._store:
                     warning('DB Reset: Account for new __version__ field')
                     warning('DB Reset: Account for new __version__ field')
                     self._store.clear()   # remove schedule at 2.2.2 upgrade.
                     self._store.clear()   # remove schedule at 2.2.2 upgrade.
-                elif b'tz' not in self._store:
+                elif str(b'tz') not in self._store:
                     warning('DB Reset: Account for new tz field')
                     warning('DB Reset: Account for new tz field')
                     self._store.clear()   # remove schedule at 3.0.8 upgrade
                     self._store.clear()   # remove schedule at 3.0.8 upgrade
-                elif b'utc_enabled' not in self._store:
+                elif str(b'utc_enabled') not in self._store:
                     warning('DB Reset: Account for new utc_enabled field')
                     warning('DB Reset: Account for new utc_enabled field')
                     self._store.clear()   # remove schedule at 3.0.9 upgrade
                     self._store.clear()   # remove schedule at 3.0.9 upgrade
             break
             break
 
 
         tz = self.app.conf.timezone
         tz = self.app.conf.timezone
-        stored_tz = self._store.get(b'tz')
+        stored_tz = self._store.get(str(b'tz'))
         if stored_tz is not None and stored_tz != tz:
         if stored_tz is not None and stored_tz != tz:
             warning('Reset: Timezone changed from %r to %r', stored_tz, tz)
             warning('Reset: Timezone changed from %r to %r', stored_tz, tz)
             self._store.clear()   # Timezone changed, reset db!
             self._store.clear()   # Timezone changed, reset db!
         utc = self.app.conf.enable_utc
         utc = self.app.conf.enable_utc
-        stored_utc = self._store.get(b'utc_enabled')
+        stored_utc = self._store.get(str(b'utc_enabled'))
         if stored_utc is not None and stored_utc != utc:
         if stored_utc is not None and stored_utc != utc:
             choices = {True: 'enabled', False: 'disabled'}
             choices = {True: 'enabled', False: 'disabled'}
             warning('Reset: UTC changed from %s to %s',
             warning('Reset: UTC changed from %s to %s',
                     choices[stored_utc], choices[utc])
                     choices[stored_utc], choices[utc])
             self._store.clear()   # UTC setting changed, reset db!
             self._store.clear()   # UTC setting changed, reset db!
-        entries = self._store.setdefault(b'entries', {})
+        entries = self._store.setdefault(str(b'entries'), {})
         self.merge_inplace(self.app.conf.beat_schedule)
         self.merge_inplace(self.app.conf.beat_schedule)
         self.install_default_entries(self.schedule)
         self.install_default_entries(self.schedule)
         self._store.update({
         self._store.update({
-            b'__version__': __version__,
-            b'tz': tz,
-            b'utc_enabled': utc,
+            str(b'__version__'): __version__,
+            str(b'tz'): tz,
+            str(b'utc_enabled'): utc,
         })
         })
         self.sync()
         self.sync()
         debug('Current schedule:\n' + '\n'.join(
         debug('Current schedule:\n' + '\n'.join(
             repr(entry) for entry in values(entries)))
             repr(entry) for entry in values(entries)))
 
 
     def get_schedule(self):
     def get_schedule(self):
-        return self._store[b'entries']
+        return self._store[str(b'entries')]
 
 
     def set_schedule(self, schedule):
     def set_schedule(self, schedule):
-        self._store[b'entries'] = schedule
+        self._store[str(b'entries')] = schedule
     schedule = property(get_schedule, set_schedule)
     schedule = property(get_schedule, set_schedule)
 
 
     def sync(self):
     def sync(self):

+ 6 - 6
t/unit/app/test_beat.py

@@ -398,17 +398,17 @@ class test_PersistentScheduler:
         s.setup_schedule()
         s.setup_schedule()
         s._remove_db.assert_called_with()
         s._remove_db.assert_called_with()
 
 
-        s._store = {b'__version__': 1}
+        s._store = {str(b'__version__'): 1}
         s.setup_schedule()
         s.setup_schedule()
 
 
         s._store.clear = Mock()
         s._store.clear = Mock()
         op = s.persistence.open = Mock()
         op = s.persistence.open = Mock()
         op.return_value = s._store
         op.return_value = s._store
-        s._store[b'tz'] = 'FUNKY'
+        s._store[str(b'tz')] = 'FUNKY'
         s.setup_schedule()
         s.setup_schedule()
         op.assert_called_with(s.schedule_filename, writeback=True)
         op.assert_called_with(s.schedule_filename, writeback=True)
         s._store.clear.assert_called_with()
         s._store.clear.assert_called_with()
-        s._store[b'utc_enabled'] = False
+        s._store[str(b'utc_enabled')] = False
         s._store.clear = Mock()
         s._store.clear = Mock()
         s.setup_schedule()
         s.setup_schedule()
         s._store.clear.assert_called_with()
         s._store.clear.assert_called_with()
@@ -417,10 +417,10 @@ class test_PersistentScheduler:
         s = create_persistent_scheduler()[0](
         s = create_persistent_scheduler()[0](
             schedule_filename='schedule', app=self.app,
             schedule_filename='schedule', app=self.app,
         )
         )
-        s._store = {b'entries': {}}
+        s._store = {str(b'entries'): {}}
         s.schedule = {'foo': 'bar'}
         s.schedule = {'foo': 'bar'}
         assert s.schedule == {'foo': 'bar'}
         assert s.schedule == {'foo': 'bar'}
-        assert s._store[b'entries'] == s.schedule
+        assert s._store[str(b'entries')] == s.schedule
 
 
 
 
 class test_Service:
 class test_Service:
@@ -439,7 +439,7 @@ class test_Service:
         assert isinstance(schedule, dict)
         assert isinstance(schedule, dict)
         assert isinstance(s.scheduler, beat.Scheduler)
         assert isinstance(s.scheduler, beat.Scheduler)
         scheduled = list(schedule.keys())
         scheduled = list(schedule.keys())
-        for task_name in keys(sh[b'entries']):
+        for task_name in keys(sh[str(b'entries')]):
             assert task_name in scheduled
             assert task_name in scheduled
 
 
         s.sync()
         s.sync()