-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
144 additions
and
0 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#!/usr/bin/env python3 | ||
"""Convert original cache file(simple dict) to data class v1.""" | ||
import argparse | ||
import logging | ||
import pickle | ||
import shutil | ||
import sys | ||
from dataclasses import dataclass, field | ||
|
||
|
||
@dataclass | ||
class CachedData: | ||
"""CachedData represents locally cached data and state.""" | ||
|
||
items: dict = field(default_factory=dict) | ||
|
||
|
||
def main(): | ||
"""Open cache file, convert it and overwrite it. | ||
Backup file is created in the process. Manual cleanup is required after | ||
migration. | ||
""" | ||
logging.basicConfig(stream=sys.stdout) | ||
logger = logging.getLogger('migrate-to-dataclass') | ||
args = parse_args() | ||
if args.verbosity: | ||
logger.setLevel(logging.DEBUG) | ||
|
||
logger.info("Read cache from file '%s'.", args.cache) | ||
with open(args.cache, 'rb') as fhandle: | ||
cache = pickle.load(fhandle) | ||
|
||
if not isinstance(cache, dict): | ||
logger.error( | ||
"Cache file '%s' has invalid format, dict is expected.", args.cache | ||
) | ||
sys.exit(1) | ||
|
||
bak_file = '{}.bak'.format(args.cache) | ||
logger.info("Create backup file '%s' from '%s'.", bak_file, args.cache) | ||
shutil.copy2(args.cache, bak_file) | ||
|
||
new_cache = CachedData() | ||
for key, value in cache.items(): | ||
new_cache.items[key] = value | ||
|
||
logger.info("Write converted cache into file '%s'.", args.cache) | ||
with open(args.cache, 'wb') as fhandle: | ||
pickle.dump(new_cache, fhandle, pickle.HIGHEST_PROTOCOL) | ||
|
||
logger.info("Migration complete and '%s' can be removed.", bak_file) | ||
|
||
|
||
def parse_args() -> argparse.Namespace: | ||
"""Return parsed CLI args.""" | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument( | ||
'-v', '--verbose', | ||
dest='verbosity', action='store_true', default=False, | ||
help='Increase logging verbosity.' | ||
) | ||
parser.add_argument( | ||
'--cache', | ||
dest='cache', type=str, default=None, required=True, | ||
help='File which contains cache.' | ||
) | ||
return parser.parse_args() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#!/usr/bin/env python3 | ||
"""Unit tests for convert_cache_to_dataclass_v1.py.""" | ||
import io | ||
import os | ||
import pickle | ||
import sys | ||
from unittest.mock import patch | ||
|
||
import pytest | ||
|
||
import migrations.convert_cache_to_dataclass_v1 as migration # noqa:I202 | ||
|
||
|
||
@pytest.fixture | ||
def fixture_bak_cleanup(): | ||
"""Cleanup bak file which is created during migration.""" | ||
bak_fnames = [] | ||
|
||
def _fixture_back_cleanup(bak_fname): | ||
bak_fnames.append(bak_fname) | ||
return bak_fname | ||
|
||
yield _fixture_back_cleanup | ||
|
||
for bak_fname in bak_fnames: | ||
print("teardown of '{}'".format(bak_fname)) | ||
os.remove(bak_fname) | ||
|
||
|
||
def test_migration(fixture_cache_file, fixture_bak_cleanup): | ||
"""Test migration under ideal conditions.""" | ||
bak_file = '{}.bak'.format(fixture_cache_file) | ||
_ = fixture_bak_cleanup(bak_file) | ||
expected_cache = migration.CachedData( | ||
items={ | ||
'test1': 1234, | ||
'test2': 0, | ||
} | ||
) | ||
|
||
test_data = { | ||
'test1': 1234, | ||
'test2': 0, | ||
} | ||
with open(fixture_cache_file, 'wb') as fhandle: | ||
pickle.dump(test_data, fhandle, pickle.HIGHEST_PROTOCOL) | ||
|
||
exception = None | ||
args = [ | ||
'./convert_cache_to_dataclass_v1.py', | ||
'--cache', | ||
fixture_cache_file, | ||
] | ||
|
||
saved_stdout = sys.stdout | ||
out = io.StringIO() | ||
sys.stdout = out | ||
|
||
with patch.object(sys, 'argv', args): | ||
try: | ||
migration.main() | ||
except Exception as exc: | ||
exception = exc | ||
finally: | ||
sys.stdout = saved_stdout | ||
|
||
assert exception is None | ||
assert os.path.exists(bak_file) is True | ||
|
||
with open(fixture_cache_file, 'rb') as fhandle: | ||
migrated_cache = pickle.load(fhandle) | ||
assert migrated_cache == expected_cache |