initial commit

This commit is contained in:
Jeremy Penner 2019-09-22 22:35:04 -04:00
commit a595e437b6
13 changed files with 1091 additions and 0 deletions

2
.flake8 Normal file
View file

@ -0,0 +1,2 @@
[flake8]
max-line-length = 88

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
*__pycache__*
.vscode
*.exe
*.db

0
README.rst Normal file
View file

787
poetry.lock generated Normal file
View file

@ -0,0 +1,787 @@
[[package]]
category = "dev"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
name = "appdirs"
optional = false
python-versions = "*"
version = "1.4.3"
[[package]]
category = "dev"
description = "Disable App Nap on OS X 10.9"
marker = "python_version >= \"3.3\" and sys_platform == \"darwin\" or sys_platform == \"darwin\""
name = "appnope"
optional = false
python-versions = "*"
version = "0.1.0"
[[package]]
category = "dev"
description = "Atomic file writes."
name = "atomicwrites"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.3.0"
[[package]]
category = "dev"
description = "Classes Without Boilerplate"
name = "attrs"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "19.1.0"
[[package]]
category = "dev"
description = "The uncompromising code formatter."
name = "black"
optional = false
python-versions = ">=3.6"
version = "18.9b0"
[package.dependencies]
appdirs = "*"
attrs = ">=17.4.0"
click = ">=6.5"
toml = ">=0.9.4"
[[package]]
category = "dev"
description = "An easy safelist-based HTML-sanitizing tool."
name = "bleach"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "3.1.0"
[package.dependencies]
six = ">=1.9.0"
webencodings = "*"
[[package]]
category = "dev"
description = "Composable command line interface toolkit"
name = "click"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "7.0"
[[package]]
category = "dev"
description = "Cross-platform colored terminal text."
marker = "python_version >= \"3.3\" and sys_platform == \"win32\" or sys_platform == \"win32\""
name = "colorama"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.4.1"
[[package]]
category = "dev"
description = "Better living through Python with decorators"
name = "decorator"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
version = "4.4.0"
[[package]]
category = "dev"
description = "XML bomb protection for Python stdlib modules"
name = "defusedxml"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.6.0"
[[package]]
category = "dev"
description = "Discover and load entry points from installed packages."
name = "entrypoints"
optional = false
python-versions = ">=2.7"
version = "0.3"
[[package]]
category = "dev"
description = "the modular source code checker: pep8, pyflakes and co"
name = "flake8"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "3.7.8"
[package.dependencies]
entrypoints = ">=0.3.0,<0.4.0"
mccabe = ">=0.6.0,<0.7.0"
pycodestyle = ">=2.5.0,<2.6.0"
pyflakes = ">=2.1.0,<2.2.0"
[[package]]
category = "dev"
description = "Read metadata from Python packages"
marker = "python_version < \"3.8\""
name = "importlib-metadata"
optional = false
python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3"
version = "0.23"
[package.dependencies]
zipp = ">=0.5"
[[package]]
category = "dev"
description = "IPython Kernel for Jupyter"
name = "ipykernel"
optional = false
python-versions = ">=3.4"
version = "5.1.2"
[package.dependencies]
ipython = ">=5.0.0"
jupyter-client = "*"
tornado = ">=4.2"
traitlets = ">=4.1.0"
[[package]]
category = "dev"
description = "IPython: Productive Interactive Computing"
name = "ipython"
optional = false
python-versions = ">=3.3"
version = "6.2.1"
[package.dependencies]
appnope = "*"
colorama = "*"
decorator = "*"
jedi = ">=0.10"
pexpect = "*"
pickleshare = "*"
prompt-toolkit = ">=1.0.4,<2.0.0"
pygments = "*"
setuptools = ">=18.5"
simplegeneric = ">0.8"
traitlets = ">=4.2"
[[package]]
category = "dev"
description = "Vestigial utilities from IPython"
name = "ipython-genutils"
optional = false
python-versions = "*"
version = "0.2.0"
[[package]]
category = "dev"
description = "IPython HTML widgets for Jupyter"
name = "ipywidgets"
optional = false
python-versions = "*"
version = "7.5.1"
[package.dependencies]
ipykernel = ">=4.5.1"
nbformat = ">=4.2.0"
traitlets = ">=4.3.1"
widgetsnbextension = ">=3.5.0,<3.6.0"
[package.dependencies.ipython]
python = ">=3.3"
version = ">=4.0.0"
[[package]]
category = "dev"
description = "An autocompletion tool for Python that can be used for text editors."
name = "jedi"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.15.1"
[package.dependencies]
parso = ">=0.5.0"
[[package]]
category = "dev"
description = "A small but fast and easy to use stand-alone template engine written in pure python."
name = "jinja2"
optional = false
python-versions = "*"
version = "2.10.1"
[package.dependencies]
MarkupSafe = ">=0.23"
[[package]]
category = "dev"
description = "An implementation of JSON Schema validation for Python"
name = "jsonschema"
optional = false
python-versions = "*"
version = "3.0.2"
[package.dependencies]
attrs = ">=17.4.0"
pyrsistent = ">=0.14.0"
setuptools = "*"
six = ">=1.11.0"
[[package]]
category = "dev"
description = "Jupyter metapackage. Install all the Jupyter components in one go."
name = "jupyter"
optional = false
python-versions = "*"
version = "1.0.0"
[package.dependencies]
ipykernel = "*"
ipywidgets = "*"
jupyter-console = "*"
nbconvert = "*"
notebook = "*"
qtconsole = "*"
[[package]]
category = "dev"
description = "Jupyter protocol implementation and client libraries"
name = "jupyter-client"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "5.3.3"
[package.dependencies]
jupyter-core = "*"
python-dateutil = ">=2.1"
pywin32 = ">=1.0"
pyzmq = ">=13"
tornado = ">=4.1"
traitlets = "*"
[[package]]
category = "dev"
description = "Jupyter terminal console"
name = "jupyter-console"
optional = false
python-versions = "*"
version = "5.2.0"
[package.dependencies]
ipykernel = "*"
ipython = "*"
jupyter-client = "*"
prompt-toolkit = ">=1.0.0,<2.0.0"
pygments = "*"
[[package]]
category = "dev"
description = "Jupyter core package. A base package on which Jupyter projects rely."
name = "jupyter-core"
optional = false
python-versions = ">=2.7, !=3.0, !=3.1, !=3.2"
version = "4.5.0"
[package.dependencies]
traitlets = "*"
[[package]]
category = "dev"
description = "Safely add untrusted strings to HTML/XML markup."
name = "markupsafe"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "1.1.1"
[[package]]
category = "dev"
description = "McCabe checker, plugin for flake8"
name = "mccabe"
optional = false
python-versions = "*"
version = "0.6.1"
[[package]]
category = "dev"
description = "The fastest markdown parser in pure Python"
name = "mistune"
optional = false
python-versions = "*"
version = "0.8.4"
[[package]]
category = "dev"
description = "More routines for operating on iterables, beyond itertools"
name = "more-itertools"
optional = false
python-versions = ">=3.4"
version = "7.2.0"
[[package]]
category = "dev"
description = "Converting Jupyter Notebooks"
name = "nbconvert"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "5.6.0"
[package.dependencies]
bleach = "*"
defusedxml = "*"
entrypoints = ">=0.2.2"
jinja2 = ">=2.4"
jupyter-core = "*"
mistune = ">=0.8.1,<2"
nbformat = ">=4.4"
pandocfilters = ">=1.4.1"
pygments = "*"
testpath = "*"
traitlets = ">=4.2"
[[package]]
category = "dev"
description = "The Jupyter Notebook format"
name = "nbformat"
optional = false
python-versions = "*"
version = "4.4.0"
[package.dependencies]
ipython-genutils = "*"
jsonschema = ">=2.4,<2.5.0 || >2.5.0"
jupyter-core = "*"
traitlets = ">=4.1"
[[package]]
category = "dev"
description = "A web-based notebook environment for interactive computing"
name = "notebook"
optional = false
python-versions = ">=3.5"
version = "6.0.1"
[package.dependencies]
Send2Trash = "*"
ipykernel = "*"
ipython-genutils = "*"
jinja2 = "*"
jupyter-client = ">=5.3.1"
jupyter-core = ">=4.4.0"
nbconvert = "*"
nbformat = "*"
prometheus-client = "*"
pyzmq = ">=17"
terminado = ">=0.8.1"
tornado = ">=5.0"
traitlets = ">=4.2.1"
[[package]]
category = "dev"
description = "Utilities for writing pandoc filters in python"
name = "pandocfilters"
optional = false
python-versions = "*"
version = "1.4.2"
[[package]]
category = "dev"
description = "A Python Parser"
name = "parso"
optional = false
python-versions = "*"
version = "0.5.1"
[[package]]
category = "dev"
description = "Pexpect allows easy control of interactive console applications."
marker = "python_version >= \"3.3\" and sys_platform != \"win32\" or sys_platform != \"win32\""
name = "pexpect"
optional = false
python-versions = "*"
version = "4.7.0"
[package.dependencies]
ptyprocess = ">=0.5"
[[package]]
category = "dev"
description = "Tiny 'shelve'-like database with concurrency support"
name = "pickleshare"
optional = false
python-versions = "*"
version = "0.7.5"
[[package]]
category = "main"
description = "Python Imaging Library (Fork)"
name = "pillow"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "6.1.0"
[[package]]
category = "dev"
description = "plugin and hook calling mechanisms for python"
name = "pluggy"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.13.0"
[package.dependencies]
[package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12"
[[package]]
category = "dev"
description = "Python client for the Prometheus monitoring system."
name = "prometheus-client"
optional = false
python-versions = "*"
version = "0.7.1"
[[package]]
category = "main"
description = "Library for building powerful interactive command lines in Python"
name = "prompt-toolkit"
optional = false
python-versions = "*"
version = "1.0.14"
[package.dependencies]
six = ">=1.9.0"
wcwidth = "*"
[[package]]
category = "dev"
description = "Run a subprocess in a pseudo terminal"
marker = "sys_platform != \"win32\" or os_name != \"nt\" or python_version >= \"3.3\" and sys_platform != \"win32\""
name = "ptyprocess"
optional = false
python-versions = "*"
version = "0.6.0"
[[package]]
category = "dev"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
name = "py"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.8.0"
[[package]]
category = "dev"
description = "Python style guide checker"
name = "pycodestyle"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.5.0"
[[package]]
category = "dev"
description = "passive checker of Python programs"
name = "pyflakes"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.1.1"
[[package]]
category = "main"
description = "Pygments is a syntax highlighting package written in Python."
name = "pygments"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.4.2"
[[package]]
category = "main"
description = "A Python module for collection of common interactive command line user interfaces, based on Inquirer.js"
name = "pyinquirer"
optional = false
python-versions = "*"
version = "1.0.3"
[package.dependencies]
Pygments = ">=2.2.0"
prompt_toolkit = "1.0.14"
regex = ">=2016.11.21"
[[package]]
category = "main"
description = "Pure Python implementation of the Sane API (using ctypes) and abstration layer"
name = "pyinsane"
optional = false
python-versions = "*"
version = "1.4.0"
[package.dependencies]
Pillow = "*"
[[package]]
category = "dev"
description = "Persistent/Functional/Immutable data structures"
name = "pyrsistent"
optional = false
python-versions = "*"
version = "0.15.4"
[package.dependencies]
six = "*"
[[package]]
category = "dev"
description = "pytest: simple powerful testing with Python"
name = "pytest"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "3.10.1"
[package.dependencies]
atomicwrites = ">=1.0"
attrs = ">=17.4.0"
colorama = "*"
more-itertools = ">=4.0.0"
pluggy = ">=0.7"
py = ">=1.5.0"
setuptools = "*"
six = ">=1.10.0"
[[package]]
category = "dev"
description = "Extensions to the standard Python datetime module"
name = "python-dateutil"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "2.8.0"
[package.dependencies]
six = ">=1.5"
[[package]]
category = "dev"
description = "Python for Window Extensions"
marker = "sys_platform == \"win32\""
name = "pywin32"
optional = false
python-versions = "*"
version = "225"
[[package]]
category = "dev"
description = "Python bindings for the winpty library"
marker = "os_name == \"nt\""
name = "pywinpty"
optional = false
python-versions = "*"
version = "0.5.5"
[[package]]
category = "dev"
description = "Python bindings for 0MQ"
name = "pyzmq"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*"
version = "18.1.0"
[[package]]
category = "dev"
description = "Jupyter Qt console"
name = "qtconsole"
optional = false
python-versions = "*"
version = "4.5.5"
[package.dependencies]
ipykernel = ">=4.1"
ipython-genutils = "*"
jupyter-client = ">=4.1"
jupyter-core = "*"
pygments = "*"
traitlets = "*"
[[package]]
category = "main"
description = "Alternative regular expression module, to replace re."
name = "regex"
optional = false
python-versions = "*"
version = "2019.08.19"
[[package]]
category = "dev"
description = "Send file to trash natively under Mac OS X, Windows and Linux."
name = "send2trash"
optional = false
python-versions = "*"
version = "1.5.0"
[[package]]
category = "dev"
description = "Simple generic functions (similar to Python's own len(), pickle.dump(), etc.)"
name = "simplegeneric"
optional = false
python-versions = "*"
version = "0.8.1"
[[package]]
category = "main"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
version = "1.12.0"
[[package]]
category = "dev"
description = "Terminals served to xterm.js using Tornado websockets"
name = "terminado"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.8.2"
[package.dependencies]
ptyprocess = "*"
pywinpty = ">=0.5"
tornado = ">=4"
[[package]]
category = "dev"
description = "Test utilities for code working with files and commands"
name = "testpath"
optional = false
python-versions = "*"
version = "0.4.2"
[[package]]
category = "dev"
description = "Python Library for Tom's Obvious, Minimal Language"
name = "toml"
optional = false
python-versions = "*"
version = "0.10.0"
[[package]]
category = "dev"
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
name = "tornado"
optional = false
python-versions = ">= 3.5"
version = "6.0.3"
[[package]]
category = "dev"
description = "Traitlets Python config system"
name = "traitlets"
optional = false
python-versions = "*"
version = "4.3.2"
[package.dependencies]
decorator = "*"
ipython-genutils = "*"
six = "*"
[[package]]
category = "main"
description = "Measures number of Terminal column cells of wide-character codes"
name = "wcwidth"
optional = false
python-versions = "*"
version = "0.1.7"
[[package]]
category = "dev"
description = "Character encoding aliases for legacy web content"
name = "webencodings"
optional = false
python-versions = "*"
version = "0.5.1"
[[package]]
category = "dev"
description = "IPython HTML widgets for Jupyter"
name = "widgetsnbextension"
optional = false
python-versions = "*"
version = "3.5.1"
[package.dependencies]
notebook = ">=4.4.1"
[[package]]
category = "dev"
description = "Backport of pathlib-compatible object wrapper for zip files"
marker = "python_version < \"3.8\""
name = "zipp"
optional = false
python-versions = ">=2.7"
version = "0.6.0"
[package.dependencies]
more-itertools = "*"
[metadata]
content-hash = "a0b14789772e6aef430877c07f16231d14758c6a230276d81cb6466f3cd97c02"
python-versions = "^3.7"
[metadata.hashes]
appdirs = ["9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", "d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"]
appnope = ["5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", "8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"]
atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"]
attrs = ["69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", "f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"]
black = ["817243426042db1d36617910df579a54f1afd659adb96fc5032fcf4b36209739", "e030a9a28f542debc08acceb273f228ac422798e5215ba2a791a6ddeaaca22a5"]
bleach = ["213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16", "3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"]
click = ["2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"]
colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"]
decorator = ["86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", "f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6"]
defusedxml = ["6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93", "f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"]
entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"]
flake8 = ["19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548", "8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"]
importlib-metadata = ["aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", "d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"]
ipykernel = ["167c3ef08450f5e060b76c749905acb0e0fbef9365899377a4a1eae728864383", "b503913e0b4cce7ed2de965457dfb2edd633e8234161a60e23f2fe2161345d12"]
ipython = ["51c158a6c8b899898d1c91c6b51a34110196815cc905f9be0fa5878e19355608", "fcc6d46f08c3c4de7b15ae1c426e15be1b7932bcda9d83ce1a4304e8c1129df3"]
ipython-genutils = ["72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", "eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"]
ipywidgets = ["13ffeca438e0c0f91ae583dc22f50379b9d6b28390ac7be8b757140e9a771516", "e945f6e02854a74994c596d9db83444a1850c01648f1574adf144fbbabe05c97"]
jedi = ["786b6c3d80e2f06fd77162a07fed81b8baa22dde5d62896a790a331d6ac21a27", "ba859c74fa3c966a22f2aeebe1b74ee27e2a462f56d3f5f7ca4a59af61bfe42e"]
jinja2 = ["065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", "14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"]
jsonschema = ["5f9c0a719ca2ce14c5de2fd350a64fd2d13e8539db29836a86adc990bb1a068f", "8d4a2b7b6c2237e0199c8ea1a6d3e05bf118e289ae2b9d7ba444182a2959560d"]
jupyter = ["3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7", "5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78", "d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"]
jupyter-client = ["6a6d415c62179728f6d9295b37356d8f6833e9e01c2b6e1901dc555571f57b21", "f406f214f9daa92be110d5b83d62f3451ffc73d3522db7350f0554683533ab18"]
jupyter-console = ["3f928b817fc82cda95e431eb4c2b5eb21be5c483c2b43f424761a966bb808094", "545dedd3aaaa355148093c5609f0229aeb121b4852995c2accfa64fe3e0e55cd"]
jupyter-core = ["2c6e7c1e9f2ac45b5c2ceea5730bc9008d92fe59d0725eac57b04c0edfba24f7", "f4fa22d6cf25f34807c995f22d2923693575c70f02557bcbfbe59bd5ec8d8b84"]
markupsafe = ["00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"]
mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"]
mistune = ["59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e", "88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"]
more-itertools = ["409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", "92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"]
nbconvert = ["427a468ec26e7d68a529b95f578d5cbf018cb4c1f889e897681c2b6d11897695", "48d3c342057a2cf21e8df820d49ff27ab9f25fc72b8f15606bd47967333b2709"]
nbformat = ["b9a0dbdbd45bb034f4f8893cafd6f652ea08c8c1674ba83f2dc55d3955743b0b", "f7494ef0df60766b7cabe0a3651556345a963b74dbc16bc7c18479041170d402"]
notebook = ["660976fe4fe45c7aa55e04bf4bccb9f9566749ff637e9020af3422f9921f9a5d", "b0a290f5cc7792d50a21bec62b3c221dd820bf00efa916ce9aeec4b5354bde20"]
pandocfilters = ["b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"]
parso = ["63854233e1fadb5da97f2744b6b24346d2750b85965e7e399bec1620232797dc", "666b0ee4a7a1220f65d367617f2cd3ffddff3e205f3f16a0284df30e774c2a9c"]
pexpect = ["2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1", "9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb"]
pickleshare = ["87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", "9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"]
pillow = ["0804f77cb1e9b6dbd37601cee11283bba39a8d44b9ddb053400c58e0c0d7d9de", "0ab7c5b5d04691bcbd570658667dd1e21ca311c62dcfd315ad2255b1cd37f64f", "0b3e6cf3ea1f8cecd625f1420b931c83ce74f00c29a0ff1ce4385f99900ac7c4", "0c6ce6ae03a50b0306a683696234b8bc88c5b292d4181ae365b89bd90250ab08", "1454ee7297a81c8308ad61d74c849486efa1badc543453c4b90db0bf99decc1c", "23efd7f83f2ad6036e2b9ef27a46df7e333de1ad9087d341d87e12225d0142b2", "365c06a45712cd723ec16fa4ceb32ce46ad201eb7bbf6d3c16b063c72b61a3ed", "38301fbc0af865baa4752ddae1bb3cbb24b3d8f221bf2850aad96b243306fa03", "3aef1af1a91798536bbab35d70d35750bd2884f0832c88aeb2499aa2d1ed4992", "3c86051d41d1c8b28b9dde08ac93e73aa842991995b12771b0af28da49086bbf", "3fe0ab49537d9330c9bba7f16a5f8b02da615b5c809cdf7124f356a0f182eccd", "406c856e0f6fc330322a319457d9ff6162834050cda2cf1eaaaea4b771d01914", "45a619d5c1915957449264c81c008934452e3fd3604e36809212300b2a4dab68", "49f90f147883a0c3778fd29d3eb169d56416f25758d0f66775db9184debc8010", "504f5334bfd974490a86fef3e3b494cd3c332a8a680d2f258ca03388b40ae230", "51fe9cfcd32c849c6f36ca293648f279fc5097ca8dd6e518b10df3a6a9a13431", "571b5a758baf1cb6a04233fb23d6cf1ca60b31f9f641b1700bfaab1194020555", "5ac381e8b1259925287ccc5a87d9cf6322a2dc88ae28a97fe3e196385288413f", "6052a9e9af4a9a2cc01da4bbee81d42d33feca2bde247c4916d8274b12bb31a4", "6153db744a743c0c8c91b8e3b9d40e0b13a5d31dbf8a12748c6d9bfd3ddc01ad", "6fd63afd14a16f5d6b408f623cc2142917a1f92855f0df997e09a49f0341be8a", "70acbcaba2a638923c2d337e0edea210505708d7859b87c2bd81e8f9902ae826", "70b1594d56ed32d56ed21a7fbb2a5c6fd7446cdb7b21e749c9791eac3a64d9e4", "76638865c83b1bb33bcac2a61ce4d13c17dba2204969dedb9ab60ef62bede686", "7b2ec162c87fc496aa568258ac88631a2ce0acfe681a9af40842fc55deaedc99", "7b403ea842b70c4fa0a4969a5d8d86e932c941095b7cda077ea68f7b98ead30b", "7be698a28175eae5354da94f5f3dc787d5efae6aca7ad1f286a781afde6a27dd", "7cee2cef07c8d76894ebefc54e4bb707dfc7f258ad155bd61d87f6cd487a70ff", "7d16d4498f8b374fc625c4037742fbdd7f9ac383fd50b06f4df00c81ef60e829", "82840783842b27933cc6388800cb547f31caf436f7e23384d456bdf5fc8dfe49", "8755e600b33f4e8c76a590b42acc35d24f4dc801a5868519ce569b9462d77598", "9159285ab4030c6f85e001468cb5886de05e6bd9304e9e7d46b983f7d2fad0cc", "b50bc1780681b127e28f0075dfb81d6135c3a293e0c1d0211133c75e2179b6c0", "b5aa19f1da16b4f5e47b6930053f08cba77ceccaed68748061b0ec24860e510c", "bd0582f831ad5bcad6ca001deba4568573a4675437db17c4031939156ff339fa", "cdd53acd3afb9878a2289a1b55807871f9877c81174ae0d3763e52f907131d25", "cfd40d8a4b59f7567620410f966bb1f32dc555b2b19f82a91b147fac296f645c", "e150c5aed6e67321edc6893faa6701581ca2d393472f39142a00e551bcd249a5", "e3ae410089de680e8f84c68b755b42bc42c0ceb8c03dbea88a5099747091d38e", "e403b37c6a253ebca5d0f2e5624643997aaae529dc96299162418ef54e29eb70", "e9046e559c299b395b39ac7dbf16005308821c2f24a63cae2ab173bd6aa11616", "ef6be704ae2bc8ad0ebc5cb850ee9139493b0fc4e81abcc240fb392a63ebc808", "f8dc19d92896558f9c4317ee365729ead9d7bbcf2052a9a19a3ef17abbb8ac5b"]
pluggy = ["0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", "fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"]
prometheus-client = ["71cd24a2b3eb335cb800c7159f423df1bd4dcd5171b234be15e3f31ec9f622da"]
prompt-toolkit = ["7281b5199235adaef6980942840c43753e4ab20dfe41338da634fb41c194f9d8", "82c7f8e07d7a0411ff5367a5a8ff520f0112b9179f3e599ee8ad2ad9b943d911", "cc66413b1b4b17021675d9f2d15d57e640b06ddfd99bb724c73484126d22622f"]
ptyprocess = ["923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", "d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"]
py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"]
pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"]
pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"]
pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"]
pyinquirer = ["c9a92d68d7727fbd886a7908c08fd9e9773e5dc211bf5cbf836ba90d366dee51"]
pyinsane = ["11df7b8abc0875a00cf2257b736fcf7b7913bd93e0428bf5b7decb9f143df74c"]
pyrsistent = ["34b47fa169d6006b32e99d4b3c4031f155e6e68ebcc107d6454852e8e0ee6533"]
pytest = ["3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec", "e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"]
python-dateutil = ["7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", "c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"]
pywin32 = ["0443e9bb196e72480f50cbddc2cf98fbb858a77d02e281ba79489ea3287b36e9", "09bbe7cdb29eb40ab2e83f7a232eeeedde864be7a0622b70a90f456aad07a234", "0d8e0f47808798d320c983574c36c49db642678902933a210edd40157d206fd0", "0db7c9f4b93528afd080d35912a60be2f86a1d6c49c0a9cf9cedd106eed81ea3", "749e590875051661ecefbd9dfa957a485016de0f25e43f5e70f888ef1e29587b", "779d3e9d4b934f2445d2920c3941416d99af72eb7f7fd57a63576cc8aa540ad6", "7c89d2c11a31c7aaa16dc4d25054d7e0e99d6f6b24193cf62c83850484658c87", "81f7732b662c46274d7d8c411c905d53e71999cba95457a0686467c3ebc745ca", "9db1fb8830bfa99c5bfd335d4482c14db5c6f5028db3b006787ef4200206242b", "bd8d04835db28646d9e07fd0ab7c7b18bd90e89dfdc559e60389179495ef30da", "fc6822a68afd79e97b015985dd455767c72009b81bcd18957068626c43f11e75", "fe6cfc2045931866417740b575231c7e12d69d481643be1493487ad53b089959"]
pywinpty = ["0e01321e53a230233358a6d608a1a8bc86c3882cf82769ba3c62ca387dc9cc51", "333e0bc5fca8ad9e9a1516ebedb2a65da38dc1f399f8b2ea57d6cccec1ff2cc8", "3ca3123aa6340ab31bbf9bd012b92e72f9ec905e4c9ee152cc997403e1778cd3", "44a6dddcf2abf402e22f87e2c9a341f7d0b296afbec3d28184c8de4d7f514ee4", "53d94d574c3d4da2df5b1c3ae728b8d90e4d33502b0388576bbd4ddeb4de0f77", "c3955f162c53dde968f3fc11361658f1d83b683bfe601d4b6f94bb01ea4300bc", "cec9894ecb34de3d7b1ca121dd98433035b9f8949b5095e84b103b349231509c", "dcd45912e2fe2e6f72cee997a4da6ed1ad2056165a277ce5ec7f7ac98dcdf667", "f2bcdd9a2ffd8b223752a971b3d377fb7bfed85f140ec9710f1218d760f2ccb7"]
pyzmq = ["01636e95a88d60118479041c6aaaaf5419c6485b7b1d37c9c4dd424b7b9f1121", "021dba0d1436516092c624359e5da51472b11ba8edffa334218912f7e8b65467", "0463bd941b6aead494d4035f7eebd70035293dd6caf8425993e85ad41de13fa3", "05fd51edd81eed798fccafdd49c936b6c166ffae7b32482e4d6d6a2e196af4e6", "1fadc8fbdf3d22753c36d4172169d184ee6654f8d6539e7af25029643363c490", "22efa0596cf245a78a99060fe5682c4cd00c58bb7614271129215c889062db80", "260c70b7c018905ec3659d0f04db735ac830fe27236e43b9dc0532cf7c9873ef", "2762c45e289732d4450406cedca35a9d4d71e449131ba2f491e0bf473e3d2ff2", "2fc6cada8dc53521c1189596f1898d45c5f68603194d3a6453d6db4b27f4e12e", "343b9710a61f2b167673bea1974e70b5dccfe64b5ed10626798f08c1f7227e72", "41bf96d5f554598a0632c3ec28e3026f1d6591a50f580df38eff0b8067efb9e7", "856b2cdf7a1e2cbb84928e1e8db0ea4018709b39804103d3a409e5584f553f57", "85b869abc894672de9aecdf032158ea8ad01e2f0c3b09ef60e3687fb79418096", "93f44739db69234c013a16990e43db1aa0af3cf5a4b8b377d028ff24515fbeb3", "98fa3e75ccb22c0dc99654e3dd9ff693b956861459e8c8e8734dd6247b89eb29", "9a22c94d2e93af8bebd4fcf5fa38830f5e3b1ff0d4424e2912b07651eb1bafb4", "a7d3f4b4bbb5d7866ae727763268b5c15797cbd7b63ea17f3b0ec1067da8994b", "b645a49376547b3816433a7e2d2a99135c8e651e50497e7ecac3bd126e4bea16", "cf0765822e78cf9e45451647a346d443f66792aba906bc340f4e0ac7870c169c", "dc398e1e047efb18bfab7a8989346c6921a847feae2cad69fedf6ca12fb99e2c", "dd5995ae2e80044e33b5077fb4bc2b0c1788ac6feaf15a6b87a00c14b4bdd682", "e03fe5e07e70f245dc9013a9d48ae8cc4b10c33a1968039c5a3b64b5d01d083d", "ea09a306144dff2795e48439883349819bef2c53c0ee62a3c2fae429451843bb", "f4e37f33da282c3c319849877e34f97f0a3acec09622ec61b7333205bdd13b52", "fa4bad0d1d173dee3e8ef3c3eb6b2bb6c723fc7a661eeecc1ecb2fa99860dd45"]
qtconsole = ["40d5d8e00d070ea266dbf6f0da74c4b9597b8b8d67cd8233c3ffd8debf923703", "b91e7412587e6cfe1644696538f73baf5611e837be5406633218443b2827c6d9"]
regex = ["1e9f9bc44ca195baf0040b1938e6801d2f3409661c15fe57f8164c678cfc663f", "587b62d48ca359d2d4f02d486f1f0aa9a20fbaf23a9d4198c4bed72ab2f6c849", "835ccdcdc612821edf132c20aef3eaaecfb884c9454fdc480d5887562594ac61", "93f6c9da57e704e128d90736430c5c59dd733327882b371b0cae8833106c2a21", "a46f27d267665016acb3ec8c6046ec5eae8cf80befe85ba47f43c6f5ec636dcd", "c5c8999b3a341b21ac2c6ec704cfcccbc50f1fedd61b6a8ee915ca7fd4b0a557", "d4d1829cf97632673aa49f378b0a2c3925acd795148c5ace8ef854217abbee89", "d96479257e8e4d1d7800adb26bf9c5ca5bab1648a1eddcac84d107b73dc68327", "f20f4912daf443220436759858f96fefbfc6c6ba9e67835fd6e4e9b73582791a", "f2b37b5b2c2a9d56d9e88efef200ec09c36c7f323f9d58d0b985a90923df386d", "fe765b809a1f7ce642c2edeee351e7ebd84391640031ba4b60af8d91a9045890"]
send2trash = ["60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2", "f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b"]
simplegeneric = ["dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173"]
six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"]
terminado = ["d9d012de63acb8223ac969c17c3043337c2fcfd28f3aea1ee429b345d01ef460", "de08e141f83c3a0798b050ecb097ab6259c3f0331b2f7b7750c9075ced2c20c2"]
testpath = ["46c89ebb683f473ffe2aab0ed9f12581d4d078308a3cb3765d79c6b2317b0109", "b694b3d9288dbd81685c5d2e7140b81365d46c29f5db4bc659de5aa6b98780f8"]
toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"]
tornado = ["349884248c36801afa19e342a77cc4458caca694b0eda633f5878e458a44cb2c", "398e0d35e086ba38a0427c3b37f4337327231942e731edaa6e9fd1865bbd6f60", "4e73ef678b1a859f0cb29e1d895526a20ea64b5ffd510a2307b5998c7df24281", "559bce3d31484b665259f50cd94c5c28b961b09315ccd838f284687245f416e5", "abbe53a39734ef4aba061fca54e30c6b4639d3e1f59653f0da37a0003de148c7", "c845db36ba616912074c5b1ee897f8e0124df269468f25e4fe21fe72f6edd7a9", "c9399267c926a4e7c418baa5cbe91c7d1cf362d505a1ef898fde44a07c9dd8a5"]
traitlets = ["9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", "c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9"]
wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"]
webencodings = ["a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", "b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"]
widgetsnbextension = ["079f87d87270bce047512400efd70238820751a11d2d8cb137a5a5bdbaf255c7", "bd314f8ceb488571a5ffea6cc5b9fc6cba0adaf88a9d2386b93a489751938bcd"]
zipp = ["3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", "f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"]

19
pyproject.toml Normal file
View file

@ -0,0 +1,19 @@
[tool.poetry]
name = "romtool"
version = "0.1.0"
description = "Ad-hoc tools for automating tedious preservation tasks"
authors = ["Jeremy Penner <jeremy@sporktania.com>"]
[tool.poetry.dependencies]
python = "^3.7"
PyInquirer = "^1.0"
pyinsane = "^1.4"
[tool.poetry.dev-dependencies]
pytest = "^3.0"
flake8 = "^3.7"
black = {version = "^18.3-alpha.0", allows-prereleases = true}
jupyter = "^1.0"
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

10
romtool/__init__.py Normal file
View file

@ -0,0 +1,10 @@
__version__ = "0.1.0"
from cuebin import CueBin
# from file import restore, backup
import glob
for cuefile in glob.glob("D:\\ROMs\\PC\\*.cue"):
CueBin(cuefile).fixAll()
# restore(cuefile)

5
romtool/config.py Normal file
View file

@ -0,0 +1,5 @@
config = {"dryrun": False}
def isDryRun():
return config["dryrun"]

47
romtool/cuebin.py Normal file
View file

@ -0,0 +1,47 @@
import re
import os
from file import replaceTextFile, realpath
class CueBin(object):
def __init__(self, cuePath):
self.cuePath = os.path.abspath(cuePath)
def directoryPath(self):
return os.path.dirname(self.cuePath)
def cueName(self):
return os.path.basename(self.cuePath)
def binName(self):
with open(self.cuePath, "rt") as f:
m = re.match(r'FILE +"(.*)" +BINARY', f.read())
if m:
return m.group(1)
def idealBinName(self):
binName = os.path.splitext(self.cueName())[0] + ".bin"
binPath = realpath(os.path.join(self.directoryPath(), binName))
if binPath is not None:
binName = os.path.basename(binPath)
return binName
def replaceBinName(self, binName=None):
if binName is None:
binName = self.idealBinName()
if not os.path.exists(os.path.join(self.directoryPath(), binName)):
raise binName + " does not exist"
replaceTextFile(
self.cuePath,
lambda line: re.sub(
r'FILE +".*" +BINARY', 'FILE "' + binName + '" BINARY', line
),
f"to point to {binName}",
)
def fixBinName(self):
if self.idealBinName() != self.binName():
self.replaceBinName()
def fixAll(self):
self.fixBinName()

68
romtool/file.py Normal file
View file

@ -0,0 +1,68 @@
import glob
import re
import os
import shutil
from config import isDryRun
# path - full path to file or directory
# name - just the filename / directory name
if isDryRun():
print("Dry run - No files will be changed")
def realpath(path):
r = glob.glob(re.sub(r"([^:/\\])(?=[/\\]|$)", r"[\1]", path))
return r and r[0] or path
def ensuredir(path):
dirpath = os.path.dirname(path)
if not isDryRun() and not os.path.exists(dirpath):
os.makedirs(dirpath)
def backupPaths(path):
dirPath, name = os.path.split(path)
dstPath = os.path.join(dirPath, "backup", name)
yield dstPath
i = 1
while os.path.exists(dstPath):
i += 1
dstPath = os.path.join(dirPath, "backup", str(i), name)
yield dstPath
def firstBackup(path):
paths = list(backupPaths(path))[:-1]
return paths[0] if len(paths) > 0 else None
def nextBackup(path):
return list(backupPaths(path))[-1]
def backup(path):
dstPath = nextBackup(path)
print(f"Backing up {path} to {dstPath}")
if not isDryRun():
ensuredir(dstPath)
shutil.copyfile(path, dstPath)
return dstPath
def restore(path):
srcPath = firstBackup(path)
if srcPath is not None:
print(f"Restoring {path} from {srcPath}")
if not isDryRun():
shutil.copyfile(srcPath, path)
def replaceTextFile(path, lineReplacer, reason):
print(f"Replacing {path}: {reason}")
if not isDryRun():
with open(backup(path), "rt") as src:
with open(path, "wt") as dst:
lines = [lineReplacer(line) for line in src.readlines()]
dst.writelines(lines)

136
romtool/itemdb.py Normal file
View file

@ -0,0 +1,136 @@
import atexit
import sqlite3
import os
from config import isDryRun
from file import backup
class DB(object):
SCHEMA_VERSION = 1
def __init__(self, path):
self.path = path if not isDryRun() else backup(path)
self.conn = sqlite3.connect(self.path)
self.conn.row_factory = sqlite3.Row
atexit.register(self.close)
def close(self):
if self.conn:
self.conn.close()
if isDryRun():
os.remove(self.path)
self.conn = None
def exec(self, *args):
return self.conn.execute(*args)
def upgrade(self):
self.exec(
"""CREATE TABLE IF NOT EXISTS schema_version
(version INTEGER)"""
)
vrow = self.exec("SELECT version FROM schema_version").fetchone()
v = vrow[0] if vrow else 0
if v < self.SCHEMA_VERSION:
backup(self.path)
if v < 1:
self.exec(
"""CREATE TABLE item (
id text PRIMARY KEY,
title text,
description text,
updatedon text,
lastsynctime text,
version integer DEFAULT 1,
scanned integer DEFAULT 0)"""
)
self.exec(
"""CREATE TABLE h_item (
id text,
title text,
description text,
updatedon text,
lastsynctime text,
version integer,
scanned integer)"""
)
self.exec(
"""CREATE TRIGGER historize_item BEFORE UPDATE ON item
WHEN OLD.version = NEW.version BEGIN
INSERT INTO h_item SELECT * FROM item WHERE id = OLD.id;
END;"""
)
self.exec(
"""CREATE TRIGGER increment_item_version AFTER UPDATE ON item
WHEN OLD.version = NEW.version BEGIN
UPDATE item SET
version = version + 1,
updatedon = datetime('now')
WHERE id = NEW.id;
END;"""
)
self.exec("DELETE FROM schema_version")
self.exec(
"INSERT INTO schema_version (version) VALUES (?)",
(self.SCHEMA_VERSION,),
)
self.conn.commit()
def get(self, id):
return self.exec("SELECT * FROM item WHERE id = ?", (id,)).fetchone()
def update(self, item):
if self.get(item["id"]):
self.exec(
"""UPDATE item
SET title = :title, description = :description
WHERE id = :id""",
item,
)
else:
self.exec(
"""INSERT INTO item
(id, title, description, updatedon)
VALUES (:id, :title, :description, datetime('now'))""",
item,
)
self.conn.commit()
def markSynced(self, id):
self.exec("UPDATE item SET lastsynctime = datetime('now') WHERE id = ?", (id,))
self.conn.commit()
def markScanned(self, id):
self.exec("UPDATE item SET scanned = 1 WHERE id = ?", (id,))
self.conn.commit()
def connect():
db = DB("items.db")
db.upgrade()
return db
def testdb():
try:
os.remove("test.db")
except OSError:
pass
db = DB("test.db")
db.upgrade()
item = {
"id": "testbloop",
"title": "Test Bloop",
"description": "Test of the bloop",
}
db.update(item)
item["title"] = "Tested Bloop"
db.update(item)
db.markScanned(item["id"])
db.markSynced(item["id"])
print(dict(db.get(item["id"])))
if __name__ == "__main__":
testdb()

7
romtool/menu.py Normal file
View file

@ -0,0 +1,7 @@
from PyInquirer import prompt
def prompt1(q):
q = q.copy()
q["name"] = "response"
return prompt([q])["response"]

0
tests/__init__.py Normal file
View file

5
tests/test_romtool.py Normal file
View file

@ -0,0 +1,5 @@
from romtool import __version__
def test_version():
assert __version__ == '0.1.0'