From 08a704ed6fed7b053251d1611d76809111bf5d13 Mon Sep 17 00:00:00 2001 From: Jordan Matelsky Date: Mon, 11 Sep 2017 15:22:34 -0400 Subject: [PATCH] jsonque init --- .gitignore | 2 ++ README.md | 29 +++++++++++++++- jsonque/__init__.py | 83 +++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 0 setup.py | 52 ++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 jsonque/__init__.py create mode 100644 requirements.txt create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a60b85 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc diff --git a/README.md b/README.md index 26a8abb..3678462 100644 --- a/README.md +++ b/README.md @@ -1 +1,28 @@ -# neuromorpholib +# jsonque + +Query JSON in memory as though it were a Mongo database. + + +```python +data = jsonque.jsonque([{ + "_id": "ABC", + "name": "Arthur Dent", + "age": 42, + "current_planet": "earth" +}, { + "_id": "DE2", + "name": "Penny Lane", + "age": 19, + "current_planet": "earth" +}, { + "_id": "123", + "name": "Ford Prefect", + "age": 240, + "current_planet": "Brontitall" +}]) + +teenage_earthlings = data.query({ + "current_planet": {"$eq": "earth"}, + "age": { "$lte": 20, "$gte": 10 } +}) +``` diff --git a/jsonque/__init__.py b/jsonque/__init__.py new file mode 100644 index 0000000..e70ce17 --- /dev/null +++ b/jsonque/__init__.py @@ -0,0 +1,83 @@ +import json +import copy + + +__version__ = "0.0.1" + + +class jsonque: + """ + A JSON query class that subsets the behavior of MongoDB queries. + + data = jsonque.jsonque([{ + "_id": "ABC", + "name": "Arthur Dent", + "age": 42, + "current_planet": "earth" + }, { + "_id": "DE2", + "name": "Penny Lane", + "age": 19, + "current_planet": "earth" + }, { + "_id": "123", + "name": "Ford Prefect", + "age": 240, + "current_planet": "Brontitall" + }]) + + teenage_earthlings = data.query({ + "current_planet": {"$eq": "earth"}, + "age": { "$lte": 20, "$gte": 10 } + }) + """ + + OPERATORS = { + "$eq": lambda x, y: x == y, + "$neq": lambda x, y: x != y, + "$lt": lambda x, y: x < y, + "$lte": lambda x, y: x <= y, + "$gt": lambda x, y: x > y, + "$gte": lambda x, y: x >= y, + "$in": lambda x, y: y in x, + "$nin": lambda x, y: y not in x, + # TODO: Add operators as useful. + } + + def __init__(self, data): + """ + Create a new jsonque object. Pass `data`, which must be a + string or a list. If a list, each item should be a dictionary. + If a string, it can either be a JSON string (from Python's + json.dumps or JS's JSON.stringify) or a filename that points + to a .json file on disk. + """ + if isinstance(data, str): + try: + data = json.loads(data) + except json.JSONDecodeError as ex: + data = json.loads(open(data, 'r').read()) + elif not isinstance(data, list): + raise ValueError("'data' argument must be a string or a list.") + + self.data = data + + def query(self, qr): + """ + Query the records for a desired trait. qr should be a dict + where all keys are included in all records. + """ + filtered_data = [] + for record in self.data: + include = True + for key, qual in qr.items(): + for op, val in qual.items(): + if op not in self.OPERATORS: + raise ValueError( + "'{}' is not a valid operator.".format(op) + ) + if not self.OPERATORS[op](record[key], val): + include = False + if include: + filtered_data.append(record) + return filtered_data diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..9c0434a --- /dev/null +++ b/setup.py @@ -0,0 +1,52 @@ +from setuptools import setup, find_packages +from codecs import open +from os import path +from jsonque import __version__ + +# to update +# python setup.py sdist +# python setup.py bdist_wheel +# twine upload dist/* + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + +# get the dependencies and installs +with open(path.join(here, 'requirements.txt'), encoding='utf-8') as f: + all_reqs = f.read().split('\n') + +install_requires = [x.strip() for x in all_reqs if 'git+' not in x] +dependency_links = [ + x.strip().replace('git+', '') for x in all_reqs if x.startswith('git+') +] + +setup( + name='jsonque', + version=__version__, + description='Query JSON in memory as though it were a Mongo database.', + long_description=long_description, + download_url='https://github.com/j6k4m8/jsonque/tarball/' + __version__, + license='Apache 2.0', + classifiers=[ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + ], + keywords=[ + "json", + "mongo", + "mongodb", + "query", + "ql" + ], + packages=find_packages(exclude=['docs', 'tests*']), + include_package_data=True, + author='Jordan Matelsky', + install_requires=install_requires, + dependency_links=dependency_links, + author_email='jordan@matelsky.com' +)