This commit is contained in:
Jeffrey Paul 2018-01-28 04:44:03 -06:00
parent df5ed9c047
commit 95767ae684
14 changed files with 649 additions and 2 deletions

118
.gitignore vendored Normal file
View File

@ -0,0 +1,118 @@
README.rst
.vagrant
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit tests / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# IPython Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
envfile
# virtualenv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject
# Vim
Session.vim
# Pycharm
.idea
# sqlite db for testing
local.db
/tests/fast-test.sh
/tests/fastest-test.sh
/tests/sbds-install.sh
/tests/test.sh
/tests/sync.sh
/tests/failed_blocks/
tests/failed_blocks/
/envdir/
/sbds.egg-info/
/envd/
/tests/envdir-to-envfile.sh
/deploy/
/test.py
.DS_Store

34
Dockerfile Normal file
View File

@ -0,0 +1,34 @@
FROM phusion/baseimage:0.9.19
# Standard stuff
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
# Stuff for building steem-python
ARG BUILD_ROOT=/build
# Now we install the essentials
RUN \
apt-get update && \
apt-get install -y python3-pip
# This updates the distro-provided pip
RUN pip3 install --upgrade pip
RUN mkdir ${BUILD_ROOT}
COPY Makefile ${BUILD_ROOT}/
COPY Pipfile ${BUILD_ROOT}/
COPY Pipfile.lock ${BUILD_ROOT}/
WORKDIR ${BUILD_ROOT}
RUN pip3 install --upgrade pip && \
pip3 install --upgrade pipenv && \
pipenv install --three --dev && \
pipenv install .
COPY . ${BUILD_ROOT}
# run tests
RUN pipenv run py.test

4
Makefile Normal file
View File

@ -0,0 +1,4 @@
default: test
test:
pipenv run pytest

28
Pipfile Normal file
View File

@ -0,0 +1,28 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
attrdict = "*"
appdirs = "*"
[dev-packages]
"pep8" = "*"
pytest = "*"
"pytest-pep8" = "*"
pytest-pylint = "*"
yapf = "*"
"autopep8" = "*"
"flake8" = "*"
"pytest-flake8" = "*"
[requires]
python_version = "3.6"

243
Pipfile.lock generated Normal file
View File

@ -0,0 +1,243 @@
{
"_meta": {
"hash": {
"sha256": "0cff184f2ce33ae5643e32fe505945779e8c9ae2e91b46c1c38f5938bf42050e"
},
"host-environment-markers": {
"implementation_name": "cpython",
"implementation_version": "3.6.4",
"os_name": "posix",
"platform_machine": "x86_64",
"platform_python_implementation": "CPython",
"platform_release": "17.3.0",
"platform_system": "Darwin",
"platform_version": "Darwin Kernel Version 17.3.0: Thu Nov 9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64",
"python_full_version": "3.6.4",
"python_version": "3.6",
"sys_platform": "darwin"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.6"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"appdirs": {
"hashes": [
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e",
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"
],
"version": "==1.4.3"
},
"attrdict": {
"hashes": [
"sha256:86aeb6d3809e0344409f8148d7cac9eabce5f0b577c160b5e90d10df3f8d2ad3"
],
"version": "==2.0.0"
},
"six": {
"hashes": [
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
],
"version": "==1.11.0"
}
},
"develop": {
"apipkg": {
"hashes": [
"sha256:65d2aa68b28e7d31233bb2ba8eb31cda40e4671f8ac2d6b241e358c9652a74b9",
"sha256:2e38399dbe842891fe85392601aab8f40a8f4cc5a9053c326de35a1cc0297ac6"
],
"version": "==1.4"
},
"astroid": {
"hashes": [
"sha256:db5cfc9af6e0b60cd07c19478fb54021fc20d2d189882fbcbc94fc69a8aecc58",
"sha256:f0a0e386dbca9f93ea9f3ea6f32b37a24720502b7baa9cb17c3976a680d43a06"
],
"version": "==1.6.1"
},
"attrs": {
"hashes": [
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450",
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9"
],
"version": "==17.4.0"
},
"autopep8": {
"hashes": [
"sha256:c7be71ab0cb2f50c9c22c82f0c9acaafc6f57492c3fbfee9790c415005c2b9a5"
],
"version": "==1.3.4"
},
"execnet": {
"hashes": [
"sha256:fc155a6b553c66c838d1a22dba1dc9f5f505c43285a878c6f74a79c024750b83",
"sha256:a7a84d5fa07a089186a329528f127c9d73b9de57f1a1131b82bb5320ee651f6a"
],
"version": "==1.5.0"
},
"flake8": {
"hashes": [
"sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37",
"sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0"
],
"version": "==3.5.0"
},
"isort": {
"hashes": [
"sha256:cd5d3fc2c16006b567a17193edf4ed9830d9454cbeb5a42ac80b36ea00c23db4",
"sha256:79f46172d3a4e2e53e7016e663cc7a8b538bec525c36675fcfd2767df30b3983"
],
"version": "==4.2.15"
},
"lazy-object-proxy": {
"hashes": [
"sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019",
"sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39",
"sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c",
"sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e",
"sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b",
"sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6",
"sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b",
"sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d",
"sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff",
"sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd",
"sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f",
"sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514",
"sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92",
"sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35",
"sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff",
"sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252",
"sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7",
"sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b",
"sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f",
"sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4",
"sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577",
"sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d",
"sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109",
"sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2",
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
"sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d",
"sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5",
"sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088",
"sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a"
],
"version": "==1.3.1"
},
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"pep8": {
"hashes": [
"sha256:b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee",
"sha256:fe249b52e20498e59e0b5c5256aa52ee99fc295b26ec9eaa85776ffdb9fe6374"
],
"version": "==1.7.1"
},
"pluggy": {
"hashes": [
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
],
"version": "==0.6.0"
},
"py": {
"hashes": [
"sha256:8cca5c229d225f8c1e3085be4fcf306090b00850fefad892f9d96c7b6e2f310f",
"sha256:ca18943e28235417756316bfada6cd96b23ce60dd532642690dcfdaba988a76d"
],
"version": "==1.5.2"
},
"pycodestyle": {
"hashes": [
"sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9",
"sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766"
],
"version": "==2.3.1"
},
"pyflakes": {
"hashes": [
"sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
"sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805"
],
"version": "==1.6.0"
},
"pylint": {
"hashes": [
"sha256:156839bedaa798febee72893beef00c650c2e7abafb5586fc7a6a56be7f80412",
"sha256:4fe3b99da7e789545327b75548cee6b511e4faa98afe268130fea1af4b5ec022"
],
"version": "==1.8.2"
},
"pytest": {
"hashes": [
"sha256:b84878865558194630c6147f44bdaef27222a9f153bbd4a08908b16bf285e0b1",
"sha256:53548280ede7818f4dc2ad96608b9f08ae2cc2ca3874f2ceb6f97e3583f25bc4"
],
"version": "==3.3.2"
},
"pytest-cache": {
"hashes": [
"sha256:be7468edd4d3d83f1e844959fd6e3fd28e77a481440a7118d430130ea31b07a9"
],
"version": "==1.0"
},
"pytest-flake8": {
"hashes": [
"sha256:e67686645860009cf1f9a5016e110234b4a2c4584711d62ba753ed651ab9ab28",
"sha256:e716072d07a557defdd5c4141984569731e292961370a5663c1697283aa16200"
],
"version": "==0.9.1"
},
"pytest-pep8": {
"hashes": [
"sha256:032ef7e5fa3ac30f4458c73e05bb67b0f036a8a5cb418a534b3170f89f120318"
],
"version": "==1.0.6"
},
"pytest-pylint": {
"hashes": [
"sha256:9b8ca25823b2f39e89d8170453f5282e57b973395060e838ced5f8c09271ca65",
"sha256:2efaf761472637df9a8f4a3f4fac37f8ce433d70957c5f5767c4be322a42a3d2",
"sha256:9f38725b22967a56724115c9df0a93dda37fea71dd5495fb1354b82e3d938d0d",
"sha256:85da6403c69eb715b9703df640818f337603f2cac947f932b033588851aaaf16",
"sha256:b85763dc36757bfb736b07fecb4f67a0892dcb00868e01f150c7424f608bd62e",
"sha256:ec63f7c4c05331654ab54fda8e68b8a11512009d506a8e35ee9b6d40a359356d",
"sha256:2bb26948f0355d14b274742153a6b4daa51e6d60481143bfd7f025699a27210d"
],
"version": "==0.7.1"
},
"six": {
"hashes": [
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
],
"version": "==1.11.0"
},
"wrapt": {
"hashes": [
"sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
],
"version": "==1.10.11"
},
"yapf": {
"hashes": [
"sha256:a0bbc8ed274609f9c7575a5d69056fa393e26a778b3e070a72f4998b8e90c3cd",
"sha256:bd19f246be7193ad2acdc04702b92315f1ae28d49c82f6671afdeefe9d32f468"
],
"version": "==0.20.1"
}
}
}

40
README.markdown Normal file
View File

@ -0,0 +1,40 @@
# jsondict
This is a python package called jsondict that wraps a dict to
provide dumb json file backed persistence.
It also returns a default of `None` for missing keys instead of KeyError,
because an exception for an undefined key is annoying, so it's sort of like
a defaultdict.
It's not general purpose, and it's not for large amounts of data. It's
just sort of like a standard dictionary that you don't need to worry about
reading/saving to disk. It's naive and inefficient but perfect for
application configs and whatnot. Don't be silly and put more than a few
kilobytes in this, the whole file is written out every update and the whole
file is re-read and re-parsed every read.
# Installation
```
pip3 install --upgrade pipenv
git clone https://github.com/sneak/jsondict.git
cd jsondict
pipenv install --three .
```
# Other Info
Right now it's only tested on python3. Python2 support is desired.
# Author
Jeffrey Paul <sneak@sneak.berlin>
# See Also
* [attrdict](https://github.com/bcj/AttrDict)
# License
MIT

View File

@ -1,2 +0,0 @@
# jsondict
dumb json persistence for a python dictionary

11
circle.yml Normal file
View File

@ -0,0 +1,11 @@
machine:
services:
- docker
dependencies:
override:
- echo "Ignore CircleCI detected dependencies"
test:
override:
- docker build -t sneak/persistentattrdict .

63
jsondict/__init__.py Normal file
View File

@ -0,0 +1,63 @@
from attrdict import AttrDict
import json
import os.path
import os
import tempfile
class JsonDict(object):
def __init__(self,persistence=None):
# TODO: either filename or file-like object
# for now, just filename
self._persistence = persistence
self._wrapped = dict()
def __len__(self):
self._reread()
return len(self._wrapped)
def keys(self):
self._reread()
return self._wrapped.keys()
def values(self):
self._reread()
return self._wrapped.values()
def __setitem__(self, key, item):
self._wrapped[key] = item
self._commit()
return item
def __delitem__(self, key):
del self._wrapped[key]
self._commit()
def __getitem__(self, key):
self._reread()
if key in self._wrapped:
return self._wrapped[key]
else:
return None
def _commit(self):
serialized = json.dumps(self._wrapped)
atomic_write(self._persistence, serialized)
def _reread(self):
with open(self._persistence, 'rb') as fd:
self._wrapped = json.load(fd)
#def PersistentAppAttrDict(appname):
#configfilename = appdirs.user_data_dir(appname,appname) + "appconfig.json"
#open
def atomic_write(fn,content):
filedir = os.path.dirname(os.path.abspath(fn))
if not os.path.exists(filedir):
os.makedirs(filedir)
(tempfd, tempfn) = tempfile.mkstemp(dir=filedir)
tempfh = os.fdopen(tempfd, 'w')
tempfh.write(content)
tempfh.close()
os.rename(tempfn,fn)

18
setup.cfg Normal file
View File

@ -0,0 +1,18 @@
[metadata]
description-file=README.markdown
[aliases]
test=pytest
[tool:pytest]
norecursedirs=dist docs build .tox deploy
addopts = --pep8 --flake8
testpaths = tests
[yapf]
indent_width = 4
column_limit = 77
based_on_style = pep8
spaces_before_comment = 2
split_before_logical_operator = true
dedent_closing_brackets = true
i18n_comment = NOQA

36
setup.py Normal file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
from pipenv.project import Project
from pipenv.utils import convert_deps_to_pip
from setuptools import setup, find_packages
import sys
pfile = Project(chdir=False).parsed_pipfile
requirements = convert_deps_to_pip(pfile['packages'], r=False)
test_requirements = convert_deps_to_pip(pfile['dev-packages'], r=False)
setup(
name='jsondict',
version='0.0.1',
description='dumb json persistence for a dict with defaults',
long_description=open('README.markdown','r').read(),
keywords=['persistence', 'json', 'datastructure'],
license='MIT',
url='https://github.com/sneak/jsondict',
maintainer='Jeffrey Paul',
maintainer_email='sneak@sneak.berlin',
packages=find_packages(),
setup_requires=[
'pytest-runner',
'pipenv',
],
tests_require=test_requirements,
install_requires=requirements,
classifiers=[
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
'Development Status :: 4 - Beta'
])

3
tests/__init__.py Normal file
View File

@ -0,0 +1,3 @@
from logging import getLogger
getLogger('flake8').propagate = False

11
tests/test_import.py Normal file
View File

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
from jsondict import JsonDict # noqa
# pylint: disable=unused-import,unused-variable
def test_import():
_ = JsonDict() # noqa

40
tests/test_pdd.py Normal file
View File

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
from jsondict import JsonDict, atomic_write
import json
import unittest
class Testcases(unittest.TestCase):
def test_atomic_write(self):
ts = "this is my test string"
tfn = '/tmp/pad_test.txt'
atomic_write(tfn, ts)
with open(tfn, 'r') as fh:
self.assertEqual(fh.read(), ts)
def test_persistence(self):
tfn = '/tmp/pad_test.json'
mypdd = JsonDict(persistence=tfn)
mypdd['testattr'] = 'loldongs'
with open(tfn, 'r') as fh:
x = json.load(fh)
self.assertEqual(x['testattr'], 'loldongs')
del mypdd['testattr']
self.assertEqual(mypdd['testattr'], None)
def test_read(self):
tfn = '/tmp/pad_test.json'
mypdd = JsonDict(persistence=tfn)
mypdd['testattr'] = 'loldongs'
with open(tfn, 'w') as fh:
json.dump({'testattr': 'notloldongs'}, fh)
self.assertNotEqual(mypdd['testattr'], 'loldongs')
self.assertEqual(mypdd['nonexist'], None)