Repository: Flexget/Flexget

Issue:
TypeError: the JSON object must be str, not 'NoneType'
### Expected behaviour:
Config file pass check validation
### Actual behaviour:
Config file does not pass check validation.
### Steps to reproduce:
Execute with attached config file

#### Config:
```
tasks:
  test:
    rss: http://mysite.com/myfeed.rss
    all_series: yes
```
  
#### Log:
```
2017-04-11 16:29 VERBOSE  check                         Pre-checked 4 configuration lines
Traceback (most recent call last):
  File "c:\users\will\appdata\local\programs\python\python35\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\users\will\appdata\local\programs\python\python35\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\Will\AppData\Local\Programs\Python\Python35\Scripts\flexget.exe\__main__.py", line 9, in <module>
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\__init__.py", line 42, in main
    manager.start()
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\manager.py", line 326, in start
    self.initialize()
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\manager.py", line 217, in initialize
    fire_event('manager.startup', self)
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\event.py", line 106, in fire_event
    result = event(*args, **kwargs)
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\event.py", line 23, in __call__
    return self.func(*args, **kwargs)
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\utils\simple_persistence.py", line 183, in load_taskless
    SimplePersistence.load()
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\utils\simple_persistence.py", line 145, in load
    cls.class_store[task][skv.plugin][skv.key] = skv.value
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\sqlalchemy\orm\attributes.py", line 293, in __get__
    return self.descriptor.__get__(instance, owner)
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\utils\database.py", line 139, in getter
    return json.loads(getattr(self, name), decode_datetime=True)
  File "c:\users\will\appdata\local\programs\python\python35\lib\site-packages\flexget\utils\json.py", line 112, in loads
    return json.loads(*args, **kwargs)
  File "c:\users\will\appdata\local\programs\python\python35\lib\json\__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'NoneType'
```

### Additional information:

- Flexget Version: 2.10.30
- Python Version: 3.5.3
- Installation method: pip
- OS and version: Windows 10 Pro 64bits v1703 (build 15063.13)

On a clean install, basic test config file does not pass validation. 

<!---
Please verify that the following data is present before submitting your issue:

- Paste or link to a paste service (http://pastebin.com/ for example) of relevant config (preferably full config including templates if present. Remember to redact any personal information! Please make sure the paste does not expire, if possible.
- Paste or link to a paste service of debug level logs of relevant task/s. Use `flexget -L debug execute --tasks <Task_name>`
- Flexget version (Use `flexget -V` to get it).
- Full Python version (`2.7.11` for example). Run `python -V` to get it.
- Installation method (pip, git install, etc.)
- OS and version
- Attach crash log if available
--->

RuntimeError: Cannot shutdown manager that was never initialized.
I'm try to run flexget daemon start -d but I aways get this error:

```
2016-05-14 17:45 INFO     manager                       Database upgrade is required. Attempting now.
2016-05-14 17:45 ERROR    schema                        Failed to upgrade database for plugin simple_persistence: value
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/flexget/db_schema.py", line 150, in upgrade_wrapper
    new_ver = upgrade_func(current_ver, session)
  File "/usr/lib/python2.7/site-packages/flexget/utils/simple_persistence.py", line 42, in upgrade
    for row in session.execute(select([table.c.id, table.c.plugin, table.c.key, table.c.value])):
  File "/usr/lib/python2.7/site-packages/sqlalchemy/util/_collections.py", line 211, in __getattr__
    raise AttributeError(key)
AttributeError: value
Traceback (most recent call last):
  File "/usr/bin/flexget", line 11, in <module>
    sys.exit(main())
  File "/usr/lib/python2.7/site-packages/flexget/__init__.py", line 42, in main
    manager.start()
  File "/usr/lib/python2.7/site-packages/flexget/manager.py", line 309, in start
    self.initialize()
  File "/usr/lib/python2.7/site-packages/flexget/manager.py", line 206, in initialize
    fire_event('manager.upgrade', self)
  File "/usr/lib/python2.7/site-packages/flexget/event.py", line 106, in fire_event
    result = event(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/flexget/event.py", line 23, in __call__
    return self.func(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/flexget/db_schema.py", line 158, in upgrade_wrapper
    manager.shutdown(finish_queue=False)
  File "/usr/lib/python2.7/site-packages/flexget/manager.py", line 858, in shutdown
    raise RuntimeError('Cannot shutdown manager that was never initialized.')
RuntimeError: Cannot shutdown manager that was never initialized.
```



Discussion:
Did you copy db from a python 2 to a python 3 execution? 
It's a clean install : I removed all files (Flexget scripts & config files then uninstalled older Python versions) before installing Python 3.5 and reinstalling Flexget from scratch.
The only important bit is whether you removed the sqlite file as well.
I backed up the complete folder (%UserProfile%\.flexget) before deleting all contents.
so, did you move you db from python 2 to python or didnt you?
Schema upgrade failures should be handled better.

same here.

```
2016-08-28 12:53 VERBOSE  check                         Pre-checked 28 configuration lines
2016-08-28 12:53 INFO     manager                       Database upgrade is required. Attempting now.
2016-08-28 12:53 ERROR    schema                        Failed to upgrade database for plugin simple_persistence: value
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/flexget/db_schema.py", line 150, in upgrade_wrapper
    new_ver = upgrade_func(current_ver, session)
  File "/usr/local/lib/python2.7/dist-packages/flexget/utils/simple_persistence.py", line 42, in upgrade
    for row in session.execute(select([table.c.id, table.c.plugin, table.c.key, table.c.value])):
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/_collections.py", line 212, in __getattr__
    raise AttributeError(key)
AttributeError: value
Traceback (most recent call last):
  File "/usr/local/bin/flexget", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/flexget/__init__.py", line 42, in main
    manager.start()
  File "/usr/local/lib/python2.7/dist-packages/flexget/manager.py", line 311, in start
    self.initialize()
  File "/usr/local/lib/python2.7/dist-packages/flexget/manager.py", line 208, in initialize
    fire_event('manager.upgrade', self)
  File "/usr/local/lib/python2.7/dist-packages/flexget/event.py", line 106, in fire_event
    result = event(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flexget/event.py", line 23, in __call__
    return self.func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flexget/db_schema.py", line 158, in upgrade_wrapper
    manager.shutdown(finish_queue=False)
  File "/usr/local/lib/python2.7/dist-packages/flexget/manager.py", line 874, in shutdown
    raise RuntimeError('Cannot shutdown manager that was never initialized.')
RuntimeError: Cannot shutdown manager that was never initialized.

```

None solution yet? Here another affected :(
I've just remove db-config.sqlite from .flexget/ dir... and now the flexget tries to execute my tasks...

I hope my experience can help other people ;)

Resolving patch:
diff --git a/flexget/plugins/internal/api_trakt.py b/flexget/plugins/internal/api_trakt.py
--- a/flexget/plugins/internal/api_trakt.py
+++ b/flexget/plugins/internal/api_trakt.py
@@ -19,7 +19,6 @@
 from flexget.plugin import get_plugin_by_name
 from flexget.utils import requests
 from flexget.utils.database import json_synonym
-from flexget.utils.simple_persistence import SimplePersistence
 from flexget.utils.tools import TimedDict, split_title_year
 
 Base = db_schema.versioned_base('api_trakt', 7)
@@ -31,8 +30,6 @@
 API_URL = 'https://api.trakt.tv/'
 PIN_URL = 'https://trakt.tv/pin/346'
 USER_CACHE_DURATION = '15 minutes'  # cache duration for sync data eg. history, collection
-# Stores the last time we checked for updates for shows/movies
-updated = SimplePersistence('api_trakt')
 
 
 # Oauth account authentication
diff --git a/flexget/utils/simple_persistence.py b/flexget/utils/simple_persistence.py
--- a/flexget/utils/simple_persistence.py
+++ b/flexget/utils/simple_persistence.py
@@ -37,14 +37,18 @@ def upgrade(ver, session):
         # Upgrade to version 0 was a failed attempt at cleaning bad entries from our table, better attempt in ver 1
         ver = 0
     if ver == 0:
-        # Remove any values that are not loadable.
-        table = table_schema('simple_persistence', session)
-        for row in session.execute(select([table.c.id, table.c.plugin, table.c.key, table.c.value])):
-            try:
-                pickle.loads(row['value'])
-            except Exception as e:
-                log.warning('Couldn\'t load %s:%s removing from db: %s' % (row['plugin'], row['key'], e))
-                session.execute(table.delete().where(table.c.id == row['id']))
+        try:
+            # Remove any values that are not loadable.
+            table = table_schema('simple_persistence', session)
+            for row in session.execute(select([table.c.id, table.c.plugin, table.c.key, table.c.value])):
+                try:
+                    pickle.loads(row['value'])
+                except Exception as e:
+                    log.warning('Couldn\'t load %s:%s removing from db: %s' % (row['plugin'], row['key'], e))
+                    session.execute(table.delete().where(table.c.id == row['id']))
+        except Exception as e:
+            log.warning('Couldn\'t upgrade the simple_persistence table. Commencing nuke. Error: %s', e)
+            raise db_schema.UpgradeImpossible
         ver = 1
     if ver == 1:
         log.info('Creating index on simple_persistence table.')
@@ -120,7 +124,7 @@ def store(self):
         return self.class_store[self.taskname][self.plugin]
 
     def __setitem__(self, key, value):
-        log.debug('setting key %s value %s' % (key, repr(value)))
+        log.debug('setting key %s value %s', key, repr(value))
         self.store[key] = value
 
     def __getitem__(self, key):
@@ -142,7 +146,12 @@ def load(cls, task=None):
         """Load all key/values from `task` into memory from database."""
         with Session() as session:
             for skv in session.query(SimpleKeyValue).filter(SimpleKeyValue.task == task).all():
-                cls.class_store[task][skv.plugin][skv.key] = skv.value
+                try:
+                    cls.class_store[task][skv.plugin][skv.key] = skv.value
+                except TypeError as e:
+                    log.warning('Value stored in simple_persistence cannot be decoded. It will be removed. Error: %s',
+                                str(e))
+                    cls.class_store[task][skv.plugin][skv.key] = DELETE
 
     @classmethod
     def flush(cls, task=None):


Test patch: