Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-tinydb for openSUSE:Factory checked in at 2022-03-22 19:40:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-tinydb (Old) and /work/SRC/openSUSE:Factory/.python-tinydb.new.25692 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-tinydb" Tue Mar 22 19:40:28 2022 rev:12 rq:963919 version:4.7.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-tinydb/python-tinydb.changes 2021-11-21 23:52:40.354158062 +0100 +++ /work/SRC/openSUSE:Factory/.python-tinydb.new.25692/python-tinydb.changes 2022-03-22 19:40:33.383112328 +0100 @@ -1,0 +2,22 @@ +Tue Mar 22 08:34:06 UTC 2022 - Ben Greiner <[email protected]> + +- Update to 4.7.0 + * Feature: Allow inserting Document instances using + Table.insert_multiple (see #455). + * Performance: Only convert document IDs of a table when + returning documents. This improves performance the Table.count + and Table.get operations and also for Table.search when only + returning a few documents (see #460). + * Internal change: Run all Table tests JSONStorage in addition to + MemoryStorage. + * Fix: Make using callables as queries work again (see #454) + * Feature: Add map() query operation to apply a transformation to + a document or field when evaluating a query (see PR #445). + * Note: This may break code that queries for a field named map + using the Query APIs property access syntax + * Feature: Add support for typing-extensions v4 +- Disable mypy tests for GNUHealth submission into 15.4 + jsc#SLE-23990 +- This package needs typing-extensions if used with Python 3.6 + +------------------------------------------------------------------- Old: ---- tinydb-4.5.2.tar.gz v4.5.2.tar.gz New: ---- tinydb-4.7.0-gh.tar.gz tinydb-4.7.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-tinydb.spec ++++++ --- /var/tmp/diff_new_pack.Q0Qycx/_old 2022-03-22 19:40:33.955112928 +0100 +++ /var/tmp/diff_new_pack.Q0Qycx/_new 2022-03-22 19:40:33.959112932 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-tinydb # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,10 +16,10 @@ # -%{?!python_module:%define python_module() python-%{**} python3-%{**}} +%{?!python_module:%define python_module() python3-%{**}} %define skip_python2 1 Name: python-tinydb -Version: 4.5.2 +Version: 4.7.0 Release: 0 Summary: A document-oriented database License: MIT @@ -27,14 +27,21 @@ URL: https://github.com/msiemens/tinydb Source: https://files.pythonhosted.org/packages/source/t/tinydb/tinydb-%{version}.tar.gz # https://github.com/msiemens/tinydb/issues/324 -Source1: https://github.com/msiemens/tinydb/archive/refs/tags/v%{version}.tar.gz +Source1: https://github.com/msiemens/tinydb/archive/refs/tags/v%{version}.tar.gz#/tinydb-%{version}-gh.tar.gz BuildRequires: %{python_module PyYAML} -BuildRequires: %{python_module pytest-mypy} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} +#BuildRequires: %%{python_module typing-extensions >= 3.10 if %%python-base < 3.7} +%if 0%{suse_version} < 1550 +# For submission to 15.4, which still has not the boolean rpm requirements support in prjconf +BuildRequires: %{python_module typing-extensions >= 3.10} +%endif BuildRequires: dos2unix BuildRequires: fdupes BuildRequires: python-rpm-macros +%if 0%{?python_version_nodots} < 37 +Requires: python-typing-extensions >= 3.10 +%endif BuildArch: noarch %python_subpackages @@ -45,14 +52,11 @@ external database server. %prep -%setup -q -n tinydb-%{version} -b1 -sed -i '/pytest-cov/d' setup.py +%setup -q -n tinydb-%{version} chmod a-x LICENSE dos2unix LICENSE - -# Disable broken ujson support -# https://github.com/msiemens/tinydb/issues/262 -sed -i 's/ujson/ujson_is_broken/' tinydb/storages.py +# only extract tests, use the sdist for the rest. We could use poetry-core and the github archive only if it wasn't for SLE/Leap +tar -zx -C .. -f %{SOURCE1} tinydb-%{version}/tests %build %python_build @@ -62,12 +66,12 @@ %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -mv pytest.ini{,.notused} %pytest %files %{python_files} %license LICENSE %doc README.rst -%{python_sitelib}/tinydb* +%{python_sitelib}/tinydb +%{python_sitelib}/tinydb-%{version}*-info %changelog ++++++ tinydb-4.5.2.tar.gz -> tinydb-4.7.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/PKG-INFO new/tinydb-4.7.0/PKG-INFO --- old/tinydb-4.5.2/PKG-INFO 2021-09-23 20:07:31.814720000 +0200 +++ new/tinydb-4.7.0/PKG-INFO 2022-02-19 17:17:56.142034500 +0100 @@ -1,20 +1,20 @@ Metadata-Version: 2.1 Name: tinydb -Version: 4.5.2 +Version: 4.7.0 Summary: TinyDB is a tiny, document oriented database optimized for your happiness :) Home-page: https://github.com/msiemens/tinydb License: MIT Keywords: database,nosql Author: Markus Siemens Author-email: [email protected] -Requires-Python: >=3.5,<4.0 +Requires-Python: >=3.6,<4.0 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 @@ -25,7 +25,7 @@ Classifier: Topic :: Database :: Database Engines/Servers Classifier: Topic :: Utilities Classifier: Typing :: Typed -Requires-Dist: typing-extensions (>=3.10.0,<4.0.0); python_version <= "3.7" +Requires-Dist: typing-extensions (>=3.10.0,<5.0.0); python_version <= "3.7" Project-URL: Changelog, https://github.com/msiemens/tinydb/en/latest/changelog.html Project-URL: Documentation, https://tinydb.readthedocs.org/ Project-URL: Issues, https://github.com/msiemens/tinydb/issues @@ -85,7 +85,7 @@ Supported Python Versions ************************* -TinyDB has been tested with Python 3.6 - 3.9 and PyPy3. +TinyDB has been tested with Python 3.6 - 3.10 and PyPy3. Example Code ************ @@ -115,6 +115,10 @@ >>> db.search((User.name == 'John') | (User.name == 'Bob')) [{'name': 'John', 'age': 22}, {'name': 'John', 'age': 37}, {'name': 'Bob', 'age': 42}] + >>> # Apply transformation to field with `map` + >>> db.search((User.age.map(lambda x: x + x) == 44)) + >>> [{'name': 'John', 'age': 22}] + >>> # More possible comparisons: != < > <= >= >>> # More possible checks: where(...).matches(regex), where(...).test(your_test_func) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/README.rst new/tinydb-4.7.0/README.rst --- old/tinydb-4.5.2/README.rst 2021-09-23 20:06:56.807656300 +0200 +++ new/tinydb-4.7.0/README.rst 2022-02-19 17:17:13.947860200 +0100 @@ -52,7 +52,7 @@ Supported Python Versions ************************* -TinyDB has been tested with Python 3.6 - 3.9 and PyPy3. +TinyDB has been tested with Python 3.6 - 3.10 and PyPy3. Example Code ************ @@ -82,6 +82,10 @@ >>> db.search((User.name == 'John') | (User.name == 'Bob')) [{'name': 'John', 'age': 22}, {'name': 'John', 'age': 37}, {'name': 'Bob', 'age': 42}] + >>> # Apply transformation to field with `map` + >>> db.search((User.age.map(lambda x: x + x) == 44)) + >>> [{'name': 'John', 'age': 22}] + >>> # More possible comparisons: != < > <= >= >>> # More possible checks: where(...).matches(regex), where(...).test(your_test_func) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/pyproject.toml new/tinydb-4.7.0/pyproject.toml --- old/tinydb-4.5.2/pyproject.toml 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/pyproject.toml 2022-02-19 17:17:13.947860200 +0100 @@ -1,6 +1,6 @@ [tool.poetry] name = "tinydb" -version = "4.5.2" +version = "4.7.0" description = "TinyDB is a tiny, document oriented database optimized for your happiness :)" authors = ["Markus Siemens <[email protected]>"] license = "MIT" @@ -25,6 +25,7 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Operating System :: OS Independent", @@ -40,18 +41,18 @@ "Issues" = "https://github.com/msiemens/tinydb/issues" [tool.poetry.dependencies] -python = "^3.5" -typing-extensions = { version = "^3.10.0", python = "<=3.7" } +python = "^3.6" +typing-extensions = { version = "^3.10.0 || ^4.0.0", python = "<=3.7" } [tool.poetry.dev-dependencies] -pytest = "^5.2.2" +pytest = "^6.2.5" pytest-codestyle = "^1.4.0" pytest-cov = "^2.8.1" pycodestyle = "^2.5.0" sphinx = "^2.2.1" coveralls = "^1.8.2" pyyaml = "^5.1.2" -pytest-mypy = { version = "^0.4.1", markers = "platform_python_implementation != 'PyPy'" } +pytest-mypy = { version = "^0.8.1", markers = "platform_python_implementation != 'PyPy'" } types-PyYAML = "^5.4.3" typing-extensions = { version = "^3.10.0" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/setup.py new/tinydb-4.7.0/setup.py --- old/tinydb-4.5.2/setup.py 2021-09-23 20:07:31.813995800 +0200 +++ new/tinydb-4.7.0/setup.py 2022-02-19 17:17:56.141590000 +0100 @@ -8,13 +8,13 @@ {'': ['*']} extras_require = \ -{':python_version <= "3.7"': ['typing-extensions>=3.10.0,<4.0.0']} +{':python_version <= "3.7"': ['typing-extensions>=3.10.0,<5.0.0']} setup_kwargs = { 'name': 'tinydb', - 'version': '4.5.2', + 'version': '4.7.0', 'description': 'TinyDB is a tiny, document oriented database optimized for your happiness :)', - 'long_description': ".. image:: https://raw.githubusercontent.com/msiemens/tinydb/master/artwork/logo.png\n :scale: 100%\n :height: 150px\n\n|Build Status| |Coverage| |Version|\n\nQuick Links\n***********\n\n- `Example Code`_\n- `Supported Python Versions`_\n- `Documentation <http://tinydb.readthedocs.org/>`_\n- `Changelog <https://tinydb.readthedocs.io/en/latest/changelog.html>`_\n- `Extensions <https://tinydb.readthedocs.io/en/latest/extensions.html>`_\n- `Contributing`_\n\nIntroduction\n************\n\nTinyDB is a lightweight document oriented database optimized for your happiness :)\nIt's written in pure Python and has no external dependencies. The target are\nsmall apps that would be blown away by a SQL-DB or an external database server.\n\nTinyDB is:\n\n- **tiny:** The current source code has 1800 lines of code (with about 40%\n documentation) and 1600 lines tests.\n\n- **document oriented:** Like MongoDB_, you can store any document\n (represented as ``dict``) in TinyDB.\n\n- **optimized for your happiness:** TinyDB is designed to be simple and\n fun to use by providing a simple and clean API.\n\n- **written in pure Python:** TinyDB neither needs an external server (as\n e.g. `PyMongo <https://api.mongodb.org/python/current/>`_) nor any dependencies\n from PyPI.\n\n- **works on Python 3.6+ and PyPy3:** TinyDB works on all modern versions of Python\n and PyPy.\n\n- **powerfully extensible:** You can easily extend TinyDB by writing new\n storages or modify the behaviour of storages with Middlewares.\n\n- **100% test coverage:** No explanation needed.\n\nTo dive straight into all the details, head over to the `TinyDB docs\n<https://tinydb.readthedocs.io/>`_. You can also discuss everything related\nto TinyDB like general development, extensions or showcase your TinyDB-based\nprojects on the `discussion forum <http://forum.m-siemens.de/.>`_.\n\nSupported Python Versions\n*************************\n\nTinyDB has been tested with Python 3.6 - 3.9 and PyPy3.\n\nExample Code\n************\n\n.. code-block:: python\n\n >>> from tinydb import TinyDB, Query\n >>> db = TinyDB('/path/to/db.json')\n >>> db.insert({'int': 1, 'char': 'a'})\n >>> db.insert({'int': 1, 'char': 'b'})\n\nQuery Language\n==============\n\n.. code-block:: python\n\n >>> User = Query()\n >>> # Search for a field value\n >>> db.search(User.name == 'John')\n [{'name': 'John', 'age': 22}, {'name': 'John', 'age': 37}]\n\n >>> # Combine two queries with logical and\n >>> db.search((User.name == 'John') & (User.age <= 30))\n [{'name': 'John', 'age': 22}]\n\n >>> # Combine two queries with logical or\n >>> db.search((User.name == 'John') | (User.name == 'Bob'))\n [{'name': 'John', 'age': 22}, {'name': 'John', 'age': 37}, {'name': 'Bob', 'age': 42}]\n\n >>> # More possible comparisons: != < > <= >=\n >>> # More possible checks: where(...).matches(regex), where(...).test(your_test_func)\n\nTables\n======\n\n.. c ode-block:: python\n\n >>> table = db.table('name')\n >>> table.insert({'value': True})\n >>> table.all()\n [{'value': True}]\n\nUsing Middlewares\n=================\n\n.. code-block:: python\n\n >>> from tinydb.storages import JSONStorage\n >>> from tinydb.middlewares import CachingMiddleware\n >>> db = TinyDB('/path/to/db.json', storage=CachingMiddleware(JSONStorage))\n\n\nContributing\n************\n\nWhether reporting bugs, discussing improvements and new ideas or writing\nextensions: Contributions to TinyDB are welcome! Here's how to get started:\n\n1. Check for open issues or open a fresh issue to start a discussion around\n a feature idea or a bug\n2. Fork `the repository <https://github.com/msiemens/tinydb/>`_ on Github,\n create a new branch off the `master` branch and start making your changes\n (known as `GitHub Flow <https://guides.github.com/introduction/flow/index.html>`_)\n3. Write a test which shows that the bug was fixed or that the featur e works\n as expected\n4. Send a pull request and bug the maintainer until it gets merged and\n published ???\n\n.. |Build Status| image:: https://img.shields.io/azure-devops/build/msiemens/3e5baa75-12ec-43ac-9728-89823ee8c7e2/2.svg?style=flat-square\n :target: https://dev.azure.com/msiemens/github/_build?definitionId=2\n.. |Coverage| image:: http://img.shields.io/coveralls/msiemens/tinydb.svg?style=flat-square\n :target: https://coveralls.io/r/msiemens/tinydb\n.. |Version| image:: http://img.shields.io/pypi/v/tinydb.svg?style=flat-square\n :target: https://pypi.python.org/pypi/tinydb/\n.. _Buzhug: http://buzhug.sourceforge.net/\n.. _CodernityDB: https://github.com/perchouli/codernitydb\n.. _MongoDB: http://mongodb.org/\n", + 'long_description': ".. image:: https://raw.githubusercontent.com/msiemens/tinydb/master/artwork/logo.png\n :scale: 100%\n :height: 150px\n\n|Build Status| |Coverage| |Version|\n\nQuick Links\n***********\n\n- `Example Code`_\n- `Supported Python Versions`_\n- `Documentation <http://tinydb.readthedocs.org/>`_\n- `Changelog <https://tinydb.readthedocs.io/en/latest/changelog.html>`_\n- `Extensions <https://tinydb.readthedocs.io/en/latest/extensions.html>`_\n- `Contributing`_\n\nIntroduction\n************\n\nTinyDB is a lightweight document oriented database optimized for your happiness :)\nIt's written in pure Python and has no external dependencies. The target are\nsmall apps that would be blown away by a SQL-DB or an external database server.\n\nTinyDB is:\n\n- **tiny:** The current source code has 1800 lines of code (with about 40%\n documentation) and 1600 lines tests.\n\n- **document oriented:** Like MongoDB_, you can store any document\n (represented as ``dict``) in TinyDB.\n\n- **optimized for your happiness:** TinyDB is designed to be simple and\n fun to use by providing a simple and clean API.\n\n- **written in pure Python:** TinyDB neither needs an external server (as\n e.g. `PyMongo <https://api.mongodb.org/python/current/>`_) nor any dependencies\n from PyPI.\n\n- **works on Python 3.6+ and PyPy3:** TinyDB works on all modern versions of Python\n and PyPy.\n\n- **powerfully extensible:** You can easily extend TinyDB by writing new\n storages or modify the behaviour of storages with Middlewares.\n\n- **100% test coverage:** No explanation needed.\n\nTo dive straight into all the details, head over to the `TinyDB docs\n<https://tinydb.readthedocs.io/>`_. You can also discuss everything related\nto TinyDB like general development, extensions or showcase your TinyDB-based\nprojects on the `discussion forum <http://forum.m-siemens.de/.>`_.\n\nSupported Python Versions\n*************************\n\nTinyDB has been tested with Python 3.6 - 3.10 and PyPy3.\n\nExample Code\n************\n\n.. code-block:: python\n\n >>> from tinydb import TinyDB, Query\n >>> db = TinyDB('/path/to/db.json')\n >>> db.insert({'int': 1, 'char': 'a'})\n >>> db.insert({'int': 1, 'char': 'b'})\n\nQuery Language\n==============\n\n.. code-block:: python\n\n >>> User = Query()\n >>> # Search for a field value\n >>> db.search(User.name == 'John')\n [{'name': 'John', 'age': 22}, {'name': 'John', 'age': 37}]\n\n >>> # Combine two queries with logical and\n >>> db.search((User.name == 'John') & (User.age <= 30))\n [{'name': 'John', 'age': 22}]\n\n >>> # Combine two queries with logical or\n >>> db.search((User.name == 'John') | (User.name == 'Bob'))\n [{'name': 'John', 'age': 22}, {'name': 'John', 'age': 37}, {'name': 'Bob', 'age': 42}]\n\n >>> # Apply transformation to field with `map`\n >>> db.search((User.age.map(lambda x: x + x) == 44))\n >>> [{'name': 'John', 'age': 22}]\n\n >>> # More possi ble comparisons: != < > <= >=\n >>> # More possible checks: where(...).matches(regex), where(...).test(your_test_func)\n\nTables\n======\n\n.. code-block:: python\n\n >>> table = db.table('name')\n >>> table.insert({'value': True})\n >>> table.all()\n [{'value': True}]\n\nUsing Middlewares\n=================\n\n.. code-block:: python\n\n >>> from tinydb.storages import JSONStorage\n >>> from tinydb.middlewares import CachingMiddleware\n >>> db = TinyDB('/path/to/db.json', storage=CachingMiddleware(JSONStorage))\n\n\nContributing\n************\n\nWhether reporting bugs, discussing improvements and new ideas or writing\nextensions: Contributions to TinyDB are welcome! Here's how to get started:\n\n1. Check for open issues or open a fresh issue to start a discussion around\n a feature idea or a bug\n2. Fork `the repository <https://github.com/msiemens/tinydb/>`_ on Github,\n create a new branch off the `master` branch and start making your changes\n ( known as `GitHub Flow <https://guides.github.com/introduction/flow/index.html>`_)\n3. Write a test which shows that the bug was fixed or that the feature works\n as expected\n4. Send a pull request and bug the maintainer until it gets merged and\n published ???\n\n.. |Build Status| image:: https://img.shields.io/azure-devops/build/msiemens/3e5baa75-12ec-43ac-9728-89823ee8c7e2/2.svg?style=flat-square\n :target: https://dev.azure.com/msiemens/github/_build?definitionId=2\n.. |Coverage| image:: http://img.shields.io/coveralls/msiemens/tinydb.svg?style=flat-square\n :target: https://coveralls.io/r/msiemens/tinydb\n.. |Version| image:: http://img.shields.io/pypi/v/tinydb.svg?style=flat-square\n :target: https://pypi.python.org/pypi/tinydb/\n.. _Buzhug: http://buzhug.sourceforge.net/\n.. _CodernityDB: https://github.com/perchouli/codernitydb\n.. _MongoDB: http://mongodb.org/\n", 'author': 'Markus Siemens', 'author_email': '[email protected]', 'maintainer': None, @@ -23,7 +23,7 @@ 'packages': packages, 'package_data': package_data, 'extras_require': extras_require, - 'python_requires': '>=3.5,<4.0', + 'python_requires': '>=3.6,<4.0', } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/tinydb/database.py new/tinydb-4.7.0/tinydb/database.py --- old/tinydb-4.5.2/tinydb/database.py 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/tinydb/database.py 2022-02-19 17:17:13.951860400 +0100 @@ -9,7 +9,7 @@ from .utils import with_typehint # The table's base class. This is used to add type hinting from the Table -# class to TinyDB. Currently this supports PyCharm, Pyright/VS Code and MyPy. +# class to TinyDB. Currently, this supports PyCharm, Pyright/VS Code and MyPy. TableBase: Type[Table] = with_typehint(Table) @@ -91,10 +91,10 @@ storage = kwargs.pop('storage', self.default_storage_class) # Prepare the storage - self._storage = storage(*args, **kwargs) # type: Storage + self._storage: Storage = storage(*args, **kwargs) self._opened = True - self._tables = {} # type: Dict[str, Table] + self._tables: Dict[str, Table] = {} def __repr__(self): args = [ @@ -116,7 +116,7 @@ created using the :attr:`~tinydb.database.TinyDB.table_class` class. Otherwise, the previously created table instance wil be returned. - All futher options besides the name are passed to the table class which + All further options besides the name are passed to the table class which by default is :class:`~tinydb.table.Table`. Check its documentation for further parameters you can pass. @@ -154,7 +154,7 @@ # To get a set of table names, we thus construct a set of this main # dict which returns a set of the dict keys which are the table names. # - # Storage.read() may return ``None`` if the database file is empty + # Storage.read() may return ``None`` if the database file is empty, # so we need to consider this case to and return an empty set in this # case. @@ -169,7 +169,7 @@ # to the storage thereby returning to the initial state with no tables. self.storage.write({}) - # After that we need to remeber to empty the ``_tables`` dict so we'll + # After that we need to remember to empty the ``_tables`` dict, so we'll # create new table instances when a table is accessed again. self._tables.clear() @@ -269,6 +269,6 @@ def __iter__(self) -> Iterator[Document]: """ - Return an iterater for the default table's documents. + Return an iterator for the default table's documents. """ return iter(self.table(self.default_table_name)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/tinydb/middlewares.py new/tinydb-4.7.0/tinydb/middlewares.py --- old/tinydb-4.5.2/tinydb/middlewares.py 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/tinydb/middlewares.py 2022-02-19 17:17:13.951860400 +0100 @@ -48,10 +48,10 @@ be the storage (or Middleware) instance. Returning the instance is simple, but we also got the underlying (*real*) StorageClass as an __init__ argument that still is not an instance. - So, we initialize it in __call__ forwarding any arguments we recieve + So, we initialize it in __call__ forwarding any arguments we receive from TinyDB (``TinyDB(arg1, kwarg1=value, storage=...)``). - In case of nested Middlewares, calling the instance as if it was an + In case of nested Middlewares, calling the instance as if it was a class results in calling ``__call__`` what initializes the next nested Middleware that itself will initialize the next Middleware and so on. @@ -63,7 +63,7 @@ def __getattr__(self, name): """ - Forward all unknown attribute calls to the underlying storage so we + Forward all unknown attribute calls to the underlying storage, so we remain as transparent as possible. """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/tinydb/operations.py new/tinydb-4.7.0/tinydb/operations.py --- old/tinydb-4.5.2/tinydb/operations.py 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/tinydb/operations.py 2022-02-19 17:17:13.951860400 +0100 @@ -31,7 +31,7 @@ def subtract(field, n): """ - Substract ``n`` to a given field in the document. + Subtract ``n`` to a given field in the document. """ def transform(doc): doc[field] -= n diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/tinydb/queries.py new/tinydb-4.7.0/tinydb/queries.py --- old/tinydb-4.5.2/tinydb/queries.py 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/tinydb/queries.py 2022-02-19 17:17:13.951860400 +0100 @@ -18,7 +18,7 @@ import re import sys -from typing import Mapping, Tuple, Callable, Any, Union, List +from typing import Mapping, Tuple, Callable, Any, Union, List, Optional from .utils import freeze @@ -44,6 +44,10 @@ boolean that indicates whether the value matches the query, and 2. it must have a stable hash that will be used for query caching. + In addition, to mark a query as non-cacheable (e.g. if it involves + some remote lookup) it needs to have a method called ``is_cacheable`` + that returns ``False``. + This query protocol is used to make MyPy correctly support the query pattern that TinyDB uses. @@ -71,23 +75,26 @@ instance can be used as a key in a dictionary. """ - def __init__(self, test: Callable[[Mapping], bool], hashval: Tuple): + def __init__(self, test: Callable[[Mapping], bool], hashval: Optional[Tuple]): self._test = test self._hash = hashval + def is_cacheable(self) -> bool: + return self._hash is not None + def __call__(self, value: Mapping) -> bool: """ Evaluate the query to check if it matches a specified value. :param value: The value to check. - :return: Wether the value matchs this query. + :return: Whether the value matches this query. """ return self._test(value) def __hash__(self): # We calculate the query hash by using the ``hashval`` object which - # describes this query uniquely so we can calculate a stable hash value - # by simply hashing it + # describes this query uniquely, so we can calculate a stable hash + # value by simply hashing it return hash(self._hash) def __repr__(self): @@ -105,26 +112,32 @@ # We use a frozenset for the hash as the AND operation is commutative # (a & b == b & a) and the frozenset does not consider the order of # elements - return QueryInstance(lambda value: self(value) and other(value), - ('and', frozenset([self._hash, other._hash]))) + if self.is_cacheable() and other.is_cacheable(): + hashval = ('and', frozenset([self._hash, other._hash])) + else: + hashval = None + return QueryInstance(lambda value: self(value) and other(value), hashval) def __or__(self, other: 'QueryInstance') -> 'QueryInstance': # We use a frozenset for the hash as the OR operation is commutative # (a | b == b | a) and the frozenset does not consider the order of # elements - return QueryInstance(lambda value: self(value) or other(value), - ('or', frozenset([self._hash, other._hash]))) + if self.is_cacheable() and other.is_cacheable(): + hashval = ('or', frozenset([self._hash, other._hash])) + else: + hashval = None + return QueryInstance(lambda value: self(value) or other(value), hashval) def __invert__(self) -> 'QueryInstance': - return QueryInstance(lambda value: not self(value), - ('not', self._hash)) + hashval = ('not', self._hash) if self.is_cacheable() else None + return QueryInstance(lambda value: not self(value), hashval) class Query(QueryInstance): """ TinyDB Queries. - Allows to build queries for TinyDB databases. There are two main ways of + Allows building queries for TinyDB databases. There are two main ways of using queries: 1) ORM-like usage: @@ -150,12 +163,12 @@ Queries are executed by calling the resulting object. They expect to get the document to test as the first argument and return ``True`` or - ``False`` depending on whether the documents matches the query or not. + ``False`` depending on whether the documents match the query or not. """ def __init__(self) -> None: # The current path of fields to access when evaluating the object - self._path = () # type: Tuple[str, ...] + self._path: Tuple[Union[str, Callable], ...] = () # Prevent empty queries to be evaluated def notest(_): @@ -182,7 +195,7 @@ query._path = self._path + (item,) # ... and update the query hash - query._hash = ('path', query._path) + query._hash = ('path', query._path) if self.is_cacheable() else None return query @@ -218,7 +231,10 @@ try: # Resolve the path for part in self._path: - value = value[part] + if isinstance(part, str): + value = value[part] + else: + value = part(value) except (KeyError, TypeError): return False else: @@ -227,7 +243,7 @@ return QueryInstance( lambda value: runner(value), - hashval + (hashval if self.is_cacheable() else None) ) def __eq__(self, rhs: Any): @@ -487,6 +503,21 @@ () ) + def map(self, fn: Callable[[Any], Any]) -> 'Query': + """ + Add a function to the query path. Similar to __getattr__ but for + arbitrary functions. + """ + query = type(self)() + + # Now we add the callable to the query path ... + query._path = self._path + (fn,) + + # ... and kill the hash - callable objects can be mutable, so it's + # harmful to cache their results. + query._hash = None + + return query def where(key: str) -> Query: """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/tinydb/storages.py new/tinydb-4.7.0/tinydb/storages.py --- old/tinydb-4.5.2/tinydb/storages.py 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/tinydb/storages.py 2022-02-19 17:17:13.951860400 +0100 @@ -114,7 +114,7 @@ size = self._handle.tell() if not size: - # File is empty so we return ``None`` so TinyDB can properly + # File is empty, so we return ``None`` so TinyDB can properly # initialize the database return None else: @@ -137,7 +137,7 @@ except io.UnsupportedOperation: raise IOError('Cannot write to the database. Access mode is "{0}"'.format(self._mode)) - # Ensure the file has been writtens + # Ensure the file has been written self._handle.flush() os.fsync(self._handle.fileno()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/tinydb/table.py new/tinydb-4.7.0/tinydb/table.py --- old/tinydb-4.5.2/tinydb/table.py 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/tinydb/table.py 2022-02-19 17:17:13.951860400 +0100 @@ -27,7 +27,7 @@ """ A document stored in the database. - This class provides a way to access both a document's content as well as + This class provides a way to access both a document's content and its ID using ``doc.doc_id``. """ @@ -50,7 +50,7 @@ once a threshold is reached. The query cache is updated on every search operation. When writing - data, the whole cache is discareded as the query results may have + data, the whole cache is discarded as the query results may have changed. .. admonition:: Customization @@ -160,8 +160,10 @@ # Now, we update the table and add the document def updater(table: dict): - assert doc_id not in table, 'doc_id '+str(doc_id)+' already exists' - + if doc_id in table: + raise ValueError(f'Document with ID {str(doc_id)} ' + f'already exists') + # By calling ``dict(document)`` we convert the data we got to a # ``dict`` instance even if it was a different class that # implemented the ``Mapping`` interface @@ -176,24 +178,39 @@ """ Insert multiple documents into the table. - :param documents: a Iterable of documents to insert + :param documents: an Iterable of documents to insert :returns: a list containing the inserted documents' IDs """ doc_ids = [] def updater(table: dict): for document in documents: + # Make sure the document implements the ``Mapping`` interface if not isinstance(document, Mapping): raise ValueError('Document is not a Mapping') - # Get the document ID for this document and store it so we - # can return all document IDs later + if isinstance(document, Document): + # Check if document does not override an existing document + if document.doc_id in table: + raise ValueError( + f'Document with ID {str(document.doc_id)} ' + f'already exists' + ) + + # Store the doc_id, so we can return all document IDs + # later. Then save the document with its doc_id and + # skip the rest of the current loop + doc_id = document.doc_id + doc_ids.append(doc_id) + table[doc_id] = dict(document) + continue + + # Generate new document ID for this document + # Store the doc_id, so we can return all document IDs + # later, then save the document with the new doc_id doc_id = self._get_next_id() doc_ids.append(doc_id) - - # Convert the document to a ``dict`` (see Table.insert) and - # store it table[doc_id] = dict(document) # See below for details on ``Table._update`` @@ -229,11 +246,33 @@ if cached_results is not None: return cached_results[:] - # Perform the search by applying the query to all documents - docs = [doc for doc in self if cond(doc)] + # Perform the search by applying the query to all documents. + # Then, only if the document matches the query, convert it + # to the document class and document ID class. + docs = [ + self.document_class(doc, self.document_id_class(doc_id)) + for doc_id, doc in self._read_table().items() + if cond(doc) + ] - # Update the query cache - self._query_cache[cond] = docs[:] + # Only cache cacheable queries. + # + # This weird `getattr` dance is needed to make MyPy happy as + # it doesn't know that a query might have a `is_cacheable` method + # that is not declared in the `QueryLike` protocol due to it being + # optional. + # See: https://github.com/python/mypy/issues/1424 + # + # Note also that by default we expect custom query objects to be + # cacheable (which means they need to have a stable hash value). + # This is to keep consistency with TinyDB's behavior before + # `is_cacheable` was introduced which assumed that all queries + # are cacheable. + is_cacheable: Callable[[], bool] = getattr(cond, 'is_cacheable', + lambda: True) + if is_cacheable(): + # Update the query cache + self._query_cache[cond] = docs[:] return docs @@ -256,7 +295,7 @@ if doc_id is not None: # Retrieve a document specified by its ID table = self._read_table() - raw_doc = table.get(doc_id, None) + raw_doc = table.get(str(doc_id), None) if raw_doc is None: return None @@ -266,9 +305,16 @@ elif cond is not None: # Find a document specified by a query - for doc in self: + # The trailing underscore in doc_id_ is needed so MyPy + # doesn't think that `doc_id_` (which is a string) needs + # to have the same type as `doc_id` which is this function's + # parameter and is an optional `int`. + for doc_id_, doc in self._read_table().items(): if cond(doc): - return doc + return self.document_class( + doc, + self.document_id_class(doc_id_) + ) return None @@ -499,8 +545,8 @@ # been removed. When removing documents identified by a set of # document IDs, it's this list of document IDs we need to return # later. - # We convert the document ID iterator into a list so we can both - # use the document IDs to remove the specified documents as well as + # We convert the document ID iterator into a list, so we can both + # use the document IDs to remove the specified documents and # to return the list of affected document IDs removed_ids = list(doc_ids) @@ -577,20 +623,7 @@ Count the total number of documents in this table. """ - # Using self._read_table() will convert all documents into - # the document class. But for counting the number of documents - # this conversion is not necessary, thus we read the storage - # directly here - - tables = self._storage.read() - - if tables is None: - return 0 - - try: - return len(tables[self.name]) - except KeyError: - return 0 + return len(self._read_table()) def __iter__(self) -> Iterator[Document]: """ @@ -602,7 +635,7 @@ # Iterate all documents and their IDs for doc_id, doc in self._read_table().items(): # Convert documents to the document class - yield self.document_class(doc, doc_id) + yield self.document_class(doc, self.document_id_class(doc_id)) def _get_next_id(self): """ @@ -639,14 +672,13 @@ return next_id - def _read_table(self) -> Dict[int, Mapping]: + def _read_table(self) -> Dict[str, Mapping]: """ Read the table data from the underlying storage. - Here we read the data from the underlying storage and convert all - IDs to the document ID class. Documents themselves are NOT yet - transformed into the document class, we may not want to convert - *all* documents when returning only one document for example. + Documents and doc_ids are NOT yet transformed, as + we may not want to convert *all* documents when returning + only one document for example. """ # Retrieve the tables from the storage @@ -663,19 +695,14 @@ # The table does not exist yet, so it is empty return {} - # Convert all document IDs to the correct document ID class and return - # the table data dict - return { - self.document_id_class(doc_id): doc - for doc_id, doc in table.items() - } + return table def _update_table(self, updater: Callable[[Dict[int, Mapping]], None]): """ - Perform an table update operation. + Perform a table update operation. The storage interface used by TinyDB only allows to read/write the - complete database data, but not modifying only portions of it. Thus + complete database data, but not modifying only portions of it. Thus, to only update portions of the table data, we first perform a read operation, perform the update on the table data and then write the updated data back to the storage. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/tinydb/utils.py new/tinydb-4.7.0/tinydb/utils.py --- old/tinydb-4.5.2/tinydb/utils.py 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/tinydb/utils.py 2022-02-19 17:17:13.951860400 +0100 @@ -41,18 +41,18 @@ A least-recently used (LRU) cache with a fixed cache size. This class acts as a dictionary but has a limited size. If the number of - entries in the cache exeeds the cache size, the leat-recently accessed - entry will be discareded. + entries in the cache exceeds the cache size, the least-recently accessed + entry will be discarded. This is implemented using an ``OrderedDict``. On every access the accessed entry is moved to the front by re-inserting it into the ``OrderedDict``. When adding an entry and the cache size is exceeded, the last entry will - be discareded. + be discarded. """ def __init__(self, capacity=None): self.capacity = capacity - self.cache = OrderedDict() # type: OrderedDict[K, V] + self.cache: OrderedDict[K, V] = OrderedDict() @property def lru(self) -> List[K]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tinydb-4.5.2/tinydb/version.py new/tinydb-4.7.0/tinydb/version.py --- old/tinydb-4.5.2/tinydb/version.py 2021-09-23 20:06:56.811656200 +0200 +++ new/tinydb-4.7.0/tinydb/version.py 2022-02-19 17:17:13.951860400 +0100 @@ -1 +1 @@ -__version__ = '4.5.2' +__version__ = '4.7.0'
