Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-lexicon for openSUSE:Factory checked in at 2021-09-21 21:12:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-lexicon (Old) and /work/SRC/openSUSE:Factory/.python-lexicon.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-lexicon" Tue Sep 21 21:12:24 2021 rev:4 rq:919616 version:2.0.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-lexicon/python-lexicon.changes 2018-12-24 11:39:14.217566842 +0100 +++ /work/SRC/openSUSE:Factory/.python-lexicon.new.1899/python-lexicon.changes 2021-09-21 21:13:04.738634314 +0200 @@ -1,0 +2,17 @@ +Fri Sep 17 03:43:56 UTC 2021 - Steve Kowalik <steven.kowa...@suse.com> + +- Update to 2.0.1: + * Fix up some project metadata. + * Dropped support for Python <3.6 + * Added a _version submodule and imported its dunder-attributes into + the top level module + * Migrated CI to CircleCI (from Travis) + * Migrated tests to pytest(-relaxed) + * Moved changelog to stub Sphinx project for Releases plugin + * Changed README to ReStructured Text (from Markdown) +- Dropped patch add_test_init.patch, no longer required. +- Added patch add-pytest-ini.patch: + * Add the pytest.ini file that isn't included in the source distribution + so the testsuite works. + +------------------------------------------------------------------- Old: ---- add_test_init.patch lexicon-1.0.0.tar.gz New: ---- add-pytest-ini.patch lexicon-2.0.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-lexicon.spec ++++++ --- /var/tmp/diff_new_pack.GVA39X/_old 2021-09-21 21:13:05.326634979 +0200 +++ /var/tmp/diff_new_pack.GVA39X/_new 2021-09-21 21:13:05.330634984 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-lexicon # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,15 +18,13 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-lexicon -Version: 1.0.0 +Version: 2.0.1 Release: 0 Summary: Python dict subclass(es) with aliasing and attribute access License: BSD-2-Clause -Group: Development/Languages/Python URL: https://github.com/bitprophet/lexicon Source: https://files.pythonhosted.org/packages/source/l/lexicon/lexicon-%{version}.tar.gz -# PATCH-FIX-UPSTREAM: add_test_init.patch # fix execution of tests -Patch0: https://github.com/bitprophet/lexicon/pull/10.patch#/add_test_init.patch +Patch0: add-pytest-ini.patch BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros @@ -35,8 +33,7 @@ Conflicts: python-dns-lexicon BuildArch: noarch # SECTION tests -BuildRequires: %{python_module six} -BuildRequires: %{python_module spec} +BuildRequires: %{python_module pytest-relaxed} # /SECTION tests %python_subpackages @@ -49,7 +46,7 @@ %prep %setup -q -n lexicon-%{version} -%patch0 -p1 +%autopatch -p1 %build %python_build @@ -59,10 +56,10 @@ %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -%python_expand spec-%{$python_bin_suffix} +%pytest %files %{python_files} -%doc README.md +%doc README.rst %license LICENSE %{python_sitelib}/* ++++++ add-pytest-ini.patch ++++++ Index: lexicon-2.0.1/pytest.ini =================================================================== --- /dev/null +++ lexicon-2.0.1/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +testpaths = tests +python_files = * ++++++ lexicon-1.0.0.tar.gz -> lexicon-2.0.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/LICENSE new/lexicon-2.0.1/LICENSE --- old/lexicon-1.0.0/LICENSE 2016-01-01 21:26:33.000000000 +0100 +++ new/lexicon-2.0.1/LICENSE 2020-01-11 00:51:19.000000000 +0100 @@ -1,4 +1,4 @@ -Copyright (c) 2016 Jeff Forcier. +Copyright (c) 2020 Jeff Forcier. All rights reserved. Redistribution and use in source and binary forms, with or without diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/MANIFEST.in new/lexicon-2.0.1/MANIFEST.in --- old/lexicon-1.0.0/MANIFEST.in 2014-05-02 00:57:22.000000000 +0200 +++ new/lexicon-2.0.1/MANIFEST.in 2021-07-09 00:28:33.000000000 +0200 @@ -1,5 +1,6 @@ include LICENSE -include README.md +include README.rst +recursive-include docs *.rst *.py include dev-requirements.txt recursive-include tests * recursive-exclude tests *.pyc *.pyo diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/PKG-INFO new/lexicon-2.0.1/PKG-INFO --- old/lexicon-1.0.0/PKG-INFO 2016-02-17 23:10:28.000000000 +0100 +++ new/lexicon-2.0.1/PKG-INFO 2021-09-10 20:38:28.000000000 +0200 @@ -1,96 +1,127 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: lexicon -Version: 1.0.0 +Version: 2.0.1 Summary: Powerful dict subclass(es) with aliasing & attribute access -Home-page: https://github.com/bitprophet/lexicon +Home-page: https://github.com/bitprophet/lexicon#what Author: Jeff Forcier Author-email: j...@bitprophet.org License: BSD -Description: ## WHAT - - Lexicon is a simple Python 2.6+ and 3.3+ compatible collection of `dict` - subclasses providing extra power: - - * `AliasDict`, a dictionary supporting both simple and complex key aliasing: - * Alias a single key to another key, so that e.g. `mydict['bar']` points to - `mydict['foo']`, for both reads and writes. - * Alias a single key to a list of other keys, for writing only, e.g. with - `active_groups = AliasDict({'ops': True, 'biz': True, 'dev': True, - 'product': True})` one can make an alias `'tech'` mapping to `('ops', - 'dev')` and then e.g. `active_groups['tech'] = False`. - * Aliasing is recursive: an alias pointing to another alias will behave as - if it points to the other alias' target. - * `AttributeDict`, supporting attribute read & write access, e.g. - `mydict = AttributeDict({'foo': 'bar'})` exhibits `mydict.foo` and - `mydict.foo = 'new value'`. - * `Lexicon`, a subclass of both of the above which exhibits both sets of +Project-URL: Source, https://github.com/bitprophet/lexicon +Project-URL: Changelog, https://github.com/bitprophet/lexicon/blob/main/docs/changelog.rst +Project-URL: CI, https://app.circleci.com/pipelines/github/bitprophet/lexicon +Description: |version| |python| |license| |ci| |coverage| + + .. |version| image:: https://img.shields.io/pypi/v/lexicon + :target: https://pypi.org/project/lexicon/ + :alt: PyPI - Package Version + .. |python| image:: https://img.shields.io/pypi/pyversions/lexicon + :target: https://pypi.org/project/lexicon/ + :alt: PyPI - Python Version + .. |license| image:: https://img.shields.io/pypi/l/lexicon + :target: https://github.com/bitprophet/lexicon/blob/main/LICENSE + :alt: PyPI - License + .. |ci| image:: https://img.shields.io/circleci/build/github/bitprophet/lexicon/main + :target: https://app.circleci.com/pipelines/github/bitprophet/lexicon + :alt: CircleCI + .. |coverage| image:: https://img.shields.io/codecov/c/gh/bitprophet/lexicon + :target: https://app.codecov.io/gh/bitprophet/lexicon + :alt: Codecov + + WHAT + ==== + + Lexicon is a simple collection of Python ``dict`` subclasses providing extra + power: + + - ``AliasDict``, a dictionary supporting both simple and complex key aliasing: + + - Alias a single key to another key, so that e.g. ``mydict['bar']`` points + to ``mydict['foo']``, for both reads and writes. + - Alias a single key to a list of other keys, for writing only, e.g. with + ``active_groups = AliasDict({'ops': True, 'biz': True, 'dev': True, + 'product': True})`` one can make an alias ``'tech'`` mapping to ``('ops', + 'dev')`` and then e.g. ``active_groups['tech'] = False``. + - Aliasing is recursive: an alias pointing to another alias will behave as + if it points to the other alias' target. + + - ``AttributeDict``, supporting attribute read & write access, e.g. ``mydict = + AttributeDict({'foo': 'bar'})`` exhibits ``mydict.foo`` and ``mydict.foo = + 'new value'``. + - ``Lexicon``, a subclass of both of the above which exhibits both sets of behavior. - ## HOW + HOW + === - * `pip install lexicon` - * `from lexicon import Lexicon` (or one of the superclasses) - * Use as needed. - - You can install the [development - version](https://github.com/bitprophet/lexicon/tarball/master#egg=lexicon-dev) - via `pip install lexicon==dev`. + - ``pip install lexicon`` + - ``from lexicon import Lexicon`` (or one of the superclasses) + - Use as needed. If you have a clone of the source repository, you can run the tests like so: - * `pip install -r dev-requirements.txt` - * `spec` + - ``pip install -r dev-requirements.txt`` + - ``inv test`` - ## API + API + === - ### `AliasDict` + ``AliasDict`` + ------------- - In all examples, `'myalias'` is the alias and `'realkey'` is the "real", + In all examples, ``'myalias'`` is the alias and ``'realkey'`` is the "real", unaliased key. - * `alias(from_'myalias', to='realkey')`: Alias `myalias` to `realkey` so - `d['myalias']` behaves exactly like `d['realkey']` for both reads and writes. - * `from_` is the first keyword argument, but typically it can be omitted - and still reads fine. See below examples for this usage. - See below for details on how an alias affects other dict operations. - * `alias('myalias', to=('realkey', 'otherrealkey'))`: Alias `myalias` to - both `realkey` and `otherrealkey`. As you might expect, this only works well - for writes, as there is never any guarantee that all targets of the alias - will contain the same value. - * `unalias('myalias')`: Removes the `myalias` alias; any subsequent - reads/writes to `myalias` will behave as normal for a regular `dict`. - * `'myalias' in d` (aka `__contains__`): Returns True when given an alias, so - if `myalias` is an alias to some other key, dictionary membership tests will - behave as if `myalias` is set. - * `del d['myalias']` (aka `__delitem__`): This effectively becomes `del - d['realkey']` -- to remove the alias itself, use `unalias()`. - * `del d['realkey']`: Deletes the real key/value pair (i.e. it calls - `dict.__del__`) but doesn't touch any aliases pointing to `realkey`. - * As a result, "dangling" aliases pointing to nonexistent keys will raise - `KeyError` on access, but will continue working if the target key is - repopulated later. + - ``alias(from_'myalias', to='realkey')``: Alias ``myalias`` to ``realkey`` so + ``d['myalias']`` behaves exactly like ``d['realkey']`` for both reads and + writes. + + - ``from_`` is the first keyword argument, but typically it can be omitted + and still reads fine. See below examples for this usage. See below for + details on how an alias affects other dict operations. + + - ``alias('myalias', to=('realkey', 'otherrealkey'))``: Alias ``myalias`` to + both ``realkey`` and ``otherrealkey``. As you might expect, this only works + well for writes, as there is never any guarantee that all targets of the + alias will contain the same value. + - ``unalias('myalias')``: Removes the ``myalias`` alias; any subsequent + reads/writes to ``myalias`` will behave as normal for a regular ``dict``. + - ``'myalias' in d`` (aka ``__contains__``): Returns True when given an alias, + so if ``myalias`` is an alias to some other key, dictionary membership tests + will behave as if ``myalias`` is set. + - ``del d['myalias']`` (aka ``__delitem__``): This effectively becomes ``del + d['realkey']`` -- to remove the alias itself, use ``unalias()``. + - ``del d['realkey']``: Deletes the real key/value pair (i.e. it calls + ``dict.__del__``) but doesn't touch any aliases pointing to ``realkey``. + + - As a result, "dangling" aliases pointing to nonexistent keys will raise + ``KeyError`` on access, but will continue working if the target key is + repopulated later. Caveats: - * Because of the single-key/multi-key duality, `AliasDict` is incapable of - honoring non-string-type keys when aliasing (it must test `isinstance(key, - basestring)` to tell strings apart from non-string iterables). - * `AliasDict` instances may still *use* non-string keys, of course -- it - just can't use them as alias targets. - - ### `AttributeDict` - - * `d.key = 'value'` (aka `__setattr__`): Maps directly to `d['key'] = 'value'`. - * `d.key` (aka `__getattr__`): Maps directly to `d['key']`. - * `del d.key` (aka `__delattr__`): Maps directly to `del d['key']`. - * Collisions between "real" or pre-existing attributes, and + - Because of the single-key/multi-key duality, ``AliasDict`` is incapable of + honoring non-string-type keys when aliasing (it must test ``isinstance(key, + basestring)`` to tell strings apart from non-string iterables). + + - ``AliasDict`` instances may still *use* non-string keys, of course -- it + just can't use them as alias targets. + + ``AttributeDict`` + ----------------- + + - ``d.key = 'value'`` (aka ``__setattr__``): Maps directly to ``d['key'] = + 'value'``. + - ``d.key`` (aka ``__getattr__``): Maps directly to ``d['key']``. + - ``del d.key`` (aka ``__delattr__``): Maps directly to ``del d['key']``. + - Collisions between "real" or pre-existing attributes, and attributes-as-dict-keys, always results in the real attribute winning. Thus - it isn't possible to use attribute access to access e.g. `d['get']`. + it isn't possible to use attribute access to access e.g. ``d['get']``. - ### `Lexicon` + ``Lexicon`` + ----------- - Lexicon subclasses from `AttributeDict` first, then `AliasDict`, with the end - result that attribute access will honor aliases. E.g.: + Lexicon subclasses from ``AttributeDict`` first, then ``AliasDict``, with the + end result that attribute access will honor aliases. E.g.: d = Lexicon() d.alias('myalias', to='realkey') @@ -106,13 +137,12 @@ Classifier: Operating System :: Unix Classifier: Operating System :: POSIX Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules +Description-Content-Type: text/x-rst diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/README.md new/lexicon-2.0.1/README.md --- old/lexicon-1.0.0/README.md 2014-05-02 00:57:22.000000000 +0200 +++ new/lexicon-2.0.1/README.md 1970-01-01 01:00:00.000000000 +0100 @@ -1,90 +0,0 @@ -## WHAT - -Lexicon is a simple Python 2.6+ and 3.3+ compatible collection of `dict` -subclasses providing extra power: - -* `AliasDict`, a dictionary supporting both simple and complex key aliasing: - * Alias a single key to another key, so that e.g. `mydict['bar']` points to - `mydict['foo']`, for both reads and writes. - * Alias a single key to a list of other keys, for writing only, e.g. with - `active_groups = AliasDict({'ops': True, 'biz': True, 'dev': True, - 'product': True})` one can make an alias `'tech'` mapping to `('ops', - 'dev')` and then e.g. `active_groups['tech'] = False`. - * Aliasing is recursive: an alias pointing to another alias will behave as - if it points to the other alias' target. -* `AttributeDict`, supporting attribute read & write access, e.g. - `mydict = AttributeDict({'foo': 'bar'})` exhibits `mydict.foo` and - `mydict.foo = 'new value'`. -* `Lexicon`, a subclass of both of the above which exhibits both sets of - behavior. - -## HOW - -* `pip install lexicon` -* `from lexicon import Lexicon` (or one of the superclasses) -* Use as needed. - -You can install the [development -version](https://github.com/bitprophet/lexicon/tarball/master#egg=lexicon-dev) -via `pip install lexicon==dev`. - -If you have a clone of the source repository, you can run the tests like so: - -* `pip install -r dev-requirements.txt` -* `spec` - -## API - -### `AliasDict` - -In all examples, `'myalias'` is the alias and `'realkey'` is the "real", -unaliased key. - -* `alias(from_'myalias', to='realkey')`: Alias `myalias` to `realkey` so - `d['myalias']` behaves exactly like `d['realkey']` for both reads and writes. - * `from_` is the first keyword argument, but typically it can be omitted - and still reads fine. See below examples for this usage. - See below for details on how an alias affects other dict operations. -* `alias('myalias', to=('realkey', 'otherrealkey'))`: Alias `myalias` to - both `realkey` and `otherrealkey`. As you might expect, this only works well - for writes, as there is never any guarantee that all targets of the alias - will contain the same value. -* `unalias('myalias')`: Removes the `myalias` alias; any subsequent - reads/writes to `myalias` will behave as normal for a regular `dict`. -* `'myalias' in d` (aka `__contains__`): Returns True when given an alias, so - if `myalias` is an alias to some other key, dictionary membership tests will - behave as if `myalias` is set. -* `del d['myalias']` (aka `__delitem__`): This effectively becomes `del - d['realkey']` -- to remove the alias itself, use `unalias()`. -* `del d['realkey']`: Deletes the real key/value pair (i.e. it calls - `dict.__del__`) but doesn't touch any aliases pointing to `realkey`. - * As a result, "dangling" aliases pointing to nonexistent keys will raise - `KeyError` on access, but will continue working if the target key is - repopulated later. - -Caveats: - -* Because of the single-key/multi-key duality, `AliasDict` is incapable of - honoring non-string-type keys when aliasing (it must test `isinstance(key, - basestring)` to tell strings apart from non-string iterables). - * `AliasDict` instances may still *use* non-string keys, of course -- it - just can't use them as alias targets. - -### `AttributeDict` - -* `d.key = 'value'` (aka `__setattr__`): Maps directly to `d['key'] = 'value'`. -* `d.key` (aka `__getattr__`): Maps directly to `d['key']`. -* `del d.key` (aka `__delattr__`): Maps directly to `del d['key']`. -* Collisions between "real" or pre-existing attributes, and - attributes-as-dict-keys, always results in the real attribute winning. Thus - it isn't possible to use attribute access to access e.g. `d['get']`. - -### `Lexicon` - -Lexicon subclasses from `AttributeDict` first, then `AliasDict`, with the end -result that attribute access will honor aliases. E.g.: - - d = Lexicon() - d.alias('myalias', to='realkey') - d.myalias = 'foo' - print d.realkey # prints 'foo' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/README.rst new/lexicon-2.0.1/README.rst --- old/lexicon-1.0.0/README.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/lexicon-2.0.1/README.rst 2021-09-04 17:44:12.000000000 +0200 @@ -0,0 +1,118 @@ +|version| |python| |license| |ci| |coverage| + +.. |version| image:: https://img.shields.io/pypi/v/lexicon + :target: https://pypi.org/project/lexicon/ + :alt: PyPI - Package Version +.. |python| image:: https://img.shields.io/pypi/pyversions/lexicon + :target: https://pypi.org/project/lexicon/ + :alt: PyPI - Python Version +.. |license| image:: https://img.shields.io/pypi/l/lexicon + :target: https://github.com/bitprophet/lexicon/blob/main/LICENSE + :alt: PyPI - License +.. |ci| image:: https://img.shields.io/circleci/build/github/bitprophet/lexicon/main + :target: https://app.circleci.com/pipelines/github/bitprophet/lexicon + :alt: CircleCI +.. |coverage| image:: https://img.shields.io/codecov/c/gh/bitprophet/lexicon + :target: https://app.codecov.io/gh/bitprophet/lexicon + :alt: Codecov + +WHAT +==== + +Lexicon is a simple collection of Python ``dict`` subclasses providing extra +power: + +- ``AliasDict``, a dictionary supporting both simple and complex key aliasing: + + - Alias a single key to another key, so that e.g. ``mydict['bar']`` points + to ``mydict['foo']``, for both reads and writes. + - Alias a single key to a list of other keys, for writing only, e.g. with + ``active_groups = AliasDict({'ops': True, 'biz': True, 'dev': True, + 'product': True})`` one can make an alias ``'tech'`` mapping to ``('ops', + 'dev')`` and then e.g. ``active_groups['tech'] = False``. + - Aliasing is recursive: an alias pointing to another alias will behave as + if it points to the other alias' target. + +- ``AttributeDict``, supporting attribute read & write access, e.g. ``mydict = + AttributeDict({'foo': 'bar'})`` exhibits ``mydict.foo`` and ``mydict.foo = + 'new value'``. +- ``Lexicon``, a subclass of both of the above which exhibits both sets of + behavior. + +HOW +=== + +- ``pip install lexicon`` +- ``from lexicon import Lexicon`` (or one of the superclasses) +- Use as needed. + +If you have a clone of the source repository, you can run the tests like so: + +- ``pip install -r dev-requirements.txt`` +- ``inv test`` + +API +=== + +``AliasDict`` +------------- + +In all examples, ``'myalias'`` is the alias and ``'realkey'`` is the "real", +unaliased key. + +- ``alias(from_'myalias', to='realkey')``: Alias ``myalias`` to ``realkey`` so + ``d['myalias']`` behaves exactly like ``d['realkey']`` for both reads and + writes. + + - ``from_`` is the first keyword argument, but typically it can be omitted + and still reads fine. See below examples for this usage. See below for + details on how an alias affects other dict operations. + +- ``alias('myalias', to=('realkey', 'otherrealkey'))``: Alias ``myalias`` to + both ``realkey`` and ``otherrealkey``. As you might expect, this only works + well for writes, as there is never any guarantee that all targets of the + alias will contain the same value. +- ``unalias('myalias')``: Removes the ``myalias`` alias; any subsequent + reads/writes to ``myalias`` will behave as normal for a regular ``dict``. +- ``'myalias' in d`` (aka ``__contains__``): Returns True when given an alias, + so if ``myalias`` is an alias to some other key, dictionary membership tests + will behave as if ``myalias`` is set. +- ``del d['myalias']`` (aka ``__delitem__``): This effectively becomes ``del + d['realkey']`` -- to remove the alias itself, use ``unalias()``. +- ``del d['realkey']``: Deletes the real key/value pair (i.e. it calls + ``dict.__del__``) but doesn't touch any aliases pointing to ``realkey``. + + - As a result, "dangling" aliases pointing to nonexistent keys will raise + ``KeyError`` on access, but will continue working if the target key is + repopulated later. + +Caveats: + +- Because of the single-key/multi-key duality, ``AliasDict`` is incapable of + honoring non-string-type keys when aliasing (it must test ``isinstance(key, + basestring)`` to tell strings apart from non-string iterables). + + - ``AliasDict`` instances may still *use* non-string keys, of course -- it + just can't use them as alias targets. + +``AttributeDict`` +----------------- + +- ``d.key = 'value'`` (aka ``__setattr__``): Maps directly to ``d['key'] = + 'value'``. +- ``d.key`` (aka ``__getattr__``): Maps directly to ``d['key']``. +- ``del d.key`` (aka ``__delattr__``): Maps directly to ``del d['key']``. +- Collisions between "real" or pre-existing attributes, and + attributes-as-dict-keys, always results in the real attribute winning. Thus + it isn't possible to use attribute access to access e.g. ``d['get']``. + +``Lexicon`` +----------- + +Lexicon subclasses from ``AttributeDict`` first, then ``AliasDict``, with the +end result that attribute access will honor aliases. E.g.: + + d = Lexicon() + d.alias('myalias', to='realkey') + d.myalias = 'foo' + print d.realkey # prints 'foo' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/dev-requirements.txt new/lexicon-2.0.1/dev-requirements.txt --- old/lexicon-1.0.0/dev-requirements.txt 2016-02-17 23:05:59.000000000 +0100 +++ new/lexicon-2.0.1/dev-requirements.txt 2021-09-04 00:16:37.000000000 +0200 @@ -1,12 +1,23 @@ # Development requirements. There are no runtime/install requirements. -# Python 3 compat spec -spec>=0.10.0 -# Ourselves --e . +# Docs (changelog) +releases==1.6.3 +Sphinx>=1.4,<1.7 +# Testing +pytest-relaxed==1.1.5 +# Coverage +pytest-cov==2.11.1 +codecov==2.1.11 # Invoke, invocations for release shenanigans etc --e git+https://github.com/pyinvoke/invoke#egg=invoke --e git+https://github.com/pyinvoke/invocations#egg=invocations +invoke==1.6.0 +invocations==2.2.0 # Release deps -wheel==0.24 -twine==1.5 +wheel==0.36.2 +twine==1.15.0 +readme_renderer==29.0 +# Formatting +black==19.10b0 +# Linting +flake8==3.6.0 +# Ourselves +-e . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/docs/changelog.rst new/lexicon-2.0.1/docs/changelog.rst --- old/lexicon-1.0.0/docs/changelog.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/lexicon-2.0.1/docs/changelog.rst 2021-09-10 20:30:36.000000000 +0200 @@ -0,0 +1,24 @@ +========= +Changelog +========= + +- :release:`2.0.1 <2021-09-10>` +- :support:`- backported` Fix up some project metadata. +- :release:`2.0.0 <2021-09-10>` +- :support:`-` Dropped support for Python <3.6 +- :support:`-` Added a ``_version`` submodule and imported its + dunder-attributes into the top level module +- :support:`-` Migrated CI to CircleCI (from Travis) +- :support:`-` Migrated tests to pytest(-relaxed) +- :support:`-` Moved changelog to stub Sphinx project for Releases plugin +- :support:`-` Changed README to ReStructured Text (from Markdown) +- :release:`1.0.0 <2016-02-17>` +- :feature:`9` Updated ``AttributeDict`` (and by extension, ``Lexicon``) so it + displays keys in the output of ``dir()`` (since they're also attributes). + Thanks to Hugo Oliveira for the initial patch. +- :support:`-` Bumped to 1.0 because clearly this software is pretty stable! +- :release:`0.2.0 <2013-03-07>` +- :bug:`8 major` Python 3 fixes, thanks to Donald Stufft. +- :release:`0.1.2 <2012-07-10>` +- :feature:`- backported` Added ``AliasDict.aliases_of(realkey)`` for reverse + lookup of what, if any, aliases a given real key has. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/docs/conf.py new/lexicon-2.0.1/docs/conf.py --- old/lexicon-1.0.0/docs/conf.py 1970-01-01 01:00:00.000000000 +0100 +++ new/lexicon-2.0.1/docs/conf.py 2021-07-09 23:11:54.000000000 +0200 @@ -0,0 +1,35 @@ +from datetime import datetime +from os import getcwd +from os.path import abspath, join +import sys + + +# Core settings +extensions = [ + "releases", + "sphinx.ext.autodoc", +] +templates_path = ["_templates"] +source_suffix = ".rst" +master_doc = "index" +exclude_patterns = ["_build"] +default_role = "obj" + +project = u"Lexicon" +year = datetime.now().year +copyright = u"%d Jeff Forcier" % year + +# Ensure project directory is on PYTHONPATH for version, autodoc access +sys.path.insert(0, abspath(join(getcwd(), ".."))) + +# Enforce use of Alabaster (even on RTD) and configure it +html_theme = "alabaster" +html_theme_options = { + "description": "Pythonic attribute/alias/etc dict subclasses", + "github_user": "bitprophet", + "github_repo": "lexicon", +} +html_sidebars = {"**": ["about.html", "navigation.html", "searchbox.html"]} + +# Other extension configs +releases_github_path = "bitprophet/lexicon" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/docs/index.rst new/lexicon-2.0.1/docs/index.rst --- old/lexicon-1.0.0/docs/index.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/lexicon-2.0.1/docs/index.rst 2021-07-08 23:48:18.000000000 +0200 @@ -0,0 +1,11 @@ +======= +Lexicon +======= + +This is just a dummy Sphinx project for hosting the changelog. Please see the +top level ``README.rst`` for all non-changelog documentation. + +.. toctree:: + :maxdepth: 1 + + changelog diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/lexicon/__init__.py new/lexicon-2.0.1/lexicon/__init__.py --- old/lexicon-1.0.0/lexicon/__init__.py 2016-02-17 22:27:14.000000000 +0100 +++ new/lexicon-2.0.1/lexicon/__init__.py 2021-07-09 00:11:33.000000000 +0200 @@ -1,3 +1,4 @@ +from ._version import __version_info__, __version__ # noqa from .attribute_dict import AttributeDict from .alias_dict import AliasDict @@ -12,12 +13,12 @@ # NOTE: could tickle AttributeDict.__init__ instead, in case it ever # grows one. dict.__init__(self, *args, **kwargs) - dict.__setattr__(self, 'aliases', {}) + dict.__setattr__(self, "aliases", {}) def __getattr__(self, key): # Intercept deepcopy/etc driven access to self.aliases when not # actually set. (Only a problem for us, due to abovementioned combo of # Alias and Attribute Dicts, so not solvable in a parent alone.) - if key == 'aliases' and key not in self.__dict__: + if key == "aliases" and key not in self.__dict__: self.__dict__[key] = {} return super(Lexicon, self).__getattr__(key) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/lexicon/_version.py new/lexicon-2.0.1/lexicon/_version.py --- old/lexicon-1.0.0/lexicon/_version.py 1970-01-01 01:00:00.000000000 +0100 +++ new/lexicon-2.0.1/lexicon/_version.py 2021-09-10 20:30:41.000000000 +0200 @@ -0,0 +1,2 @@ +__version_info__ = (2, 0, 1) +__version__ = ".".join(map(str, __version_info__)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/lexicon/alias_dict.py new/lexicon-2.0.1/lexicon/alias_dict.py --- old/lexicon-1.0.0/lexicon/alias_dict.py 2014-05-02 00:57:22.000000000 +0200 +++ new/lexicon-2.0.1/lexicon/alias_dict.py 2021-07-08 23:39:27.000000000 +0200 @@ -1,11 +1,3 @@ -# Normal import -try: - import six -# Horrible, awful hack to work when vendorized -except ImportError: - from .. import six - - class AliasDict(dict): def __init__(self, *args, **kwargs): super(AliasDict, self).__init__(*args, **kwargs) @@ -37,19 +29,17 @@ names.append(key) # 'key' is now a realkey, whose aliases are all keys whose value is # itself. Filter out the original name given. - names.extend([ - k for k,v - in six.iteritems(self.aliases) - if v == key and k != name - ]) + names.extend( + [k for k, v in self.aliases.items() if v == key and k != name] + ) return names def _handle(self, key, value, single, multi, unaliased): # Attribute existence test required to not blow up when deepcopy'd - if key in getattr(self, 'aliases', {}): + if key in getattr(self, "aliases", {}): target = self.aliases[key] # Single-string targets - if isinstance(target, six.string_types): + if isinstance(target, str): return single(self, target, value) # Multi-string targets else: @@ -61,26 +51,31 @@ else: return unaliased(self, key, value) - def _single(self, target): - return isinstance(target, six.string_types) - def __setitem__(self, key, value): - def single(d, target, value): d[target] = value - def unaliased(d, key, value): super(AliasDict, d).__setitem__(key, value) + def single(d, target, value): + d[target] = value + + def unaliased(d, key, value): + super(AliasDict, d).__setitem__(key, value) + return self._handle(key, value, single, None, unaliased) def __getitem__(self, key): - def single(d, target, value): return d[target] - def unaliased(d, key, value): return super(AliasDict, d).__getitem__(key) + def single(d, target, value): + return d[target] + + def unaliased(d, key, value): + return super(AliasDict, d).__getitem__(key) def multi(d, target, value): - msg = "Multi-target aliases have no well-defined value and can't be read." + msg = "Multi-target aliases have no well-defined value and can't be read." # noqa raise ValueError(msg) return self._handle(key, None, single, multi, unaliased) def __contains__(self, key): - def single(d, target, value): return target in d + def single(d, target, value): + return target in d def multi(d, target, value): return all(subkey in self for subkey in self.aliases[key]) @@ -91,7 +86,8 @@ return self._handle(key, None, single, multi, unaliased) def __delitem__(self, key): - def single(d, target, value): del d[target] + def single(d, target, value): + del d[target] def unaliased(d, key, value): return super(AliasDict, d).__delitem__(key) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/lexicon.egg-info/PKG-INFO new/lexicon-2.0.1/lexicon.egg-info/PKG-INFO --- old/lexicon-1.0.0/lexicon.egg-info/PKG-INFO 2016-02-17 23:10:28.000000000 +0100 +++ new/lexicon-2.0.1/lexicon.egg-info/PKG-INFO 2021-09-10 20:38:28.000000000 +0200 @@ -1,96 +1,127 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: lexicon -Version: 1.0.0 +Version: 2.0.1 Summary: Powerful dict subclass(es) with aliasing & attribute access -Home-page: https://github.com/bitprophet/lexicon +Home-page: https://github.com/bitprophet/lexicon#what Author: Jeff Forcier Author-email: j...@bitprophet.org License: BSD -Description: ## WHAT - - Lexicon is a simple Python 2.6+ and 3.3+ compatible collection of `dict` - subclasses providing extra power: - - * `AliasDict`, a dictionary supporting both simple and complex key aliasing: - * Alias a single key to another key, so that e.g. `mydict['bar']` points to - `mydict['foo']`, for both reads and writes. - * Alias a single key to a list of other keys, for writing only, e.g. with - `active_groups = AliasDict({'ops': True, 'biz': True, 'dev': True, - 'product': True})` one can make an alias `'tech'` mapping to `('ops', - 'dev')` and then e.g. `active_groups['tech'] = False`. - * Aliasing is recursive: an alias pointing to another alias will behave as - if it points to the other alias' target. - * `AttributeDict`, supporting attribute read & write access, e.g. - `mydict = AttributeDict({'foo': 'bar'})` exhibits `mydict.foo` and - `mydict.foo = 'new value'`. - * `Lexicon`, a subclass of both of the above which exhibits both sets of +Project-URL: Source, https://github.com/bitprophet/lexicon +Project-URL: Changelog, https://github.com/bitprophet/lexicon/blob/main/docs/changelog.rst +Project-URL: CI, https://app.circleci.com/pipelines/github/bitprophet/lexicon +Description: |version| |python| |license| |ci| |coverage| + + .. |version| image:: https://img.shields.io/pypi/v/lexicon + :target: https://pypi.org/project/lexicon/ + :alt: PyPI - Package Version + .. |python| image:: https://img.shields.io/pypi/pyversions/lexicon + :target: https://pypi.org/project/lexicon/ + :alt: PyPI - Python Version + .. |license| image:: https://img.shields.io/pypi/l/lexicon + :target: https://github.com/bitprophet/lexicon/blob/main/LICENSE + :alt: PyPI - License + .. |ci| image:: https://img.shields.io/circleci/build/github/bitprophet/lexicon/main + :target: https://app.circleci.com/pipelines/github/bitprophet/lexicon + :alt: CircleCI + .. |coverage| image:: https://img.shields.io/codecov/c/gh/bitprophet/lexicon + :target: https://app.codecov.io/gh/bitprophet/lexicon + :alt: Codecov + + WHAT + ==== + + Lexicon is a simple collection of Python ``dict`` subclasses providing extra + power: + + - ``AliasDict``, a dictionary supporting both simple and complex key aliasing: + + - Alias a single key to another key, so that e.g. ``mydict['bar']`` points + to ``mydict['foo']``, for both reads and writes. + - Alias a single key to a list of other keys, for writing only, e.g. with + ``active_groups = AliasDict({'ops': True, 'biz': True, 'dev': True, + 'product': True})`` one can make an alias ``'tech'`` mapping to ``('ops', + 'dev')`` and then e.g. ``active_groups['tech'] = False``. + - Aliasing is recursive: an alias pointing to another alias will behave as + if it points to the other alias' target. + + - ``AttributeDict``, supporting attribute read & write access, e.g. ``mydict = + AttributeDict({'foo': 'bar'})`` exhibits ``mydict.foo`` and ``mydict.foo = + 'new value'``. + - ``Lexicon``, a subclass of both of the above which exhibits both sets of behavior. - ## HOW + HOW + === - * `pip install lexicon` - * `from lexicon import Lexicon` (or one of the superclasses) - * Use as needed. - - You can install the [development - version](https://github.com/bitprophet/lexicon/tarball/master#egg=lexicon-dev) - via `pip install lexicon==dev`. + - ``pip install lexicon`` + - ``from lexicon import Lexicon`` (or one of the superclasses) + - Use as needed. If you have a clone of the source repository, you can run the tests like so: - * `pip install -r dev-requirements.txt` - * `spec` + - ``pip install -r dev-requirements.txt`` + - ``inv test`` - ## API + API + === - ### `AliasDict` + ``AliasDict`` + ------------- - In all examples, `'myalias'` is the alias and `'realkey'` is the "real", + In all examples, ``'myalias'`` is the alias and ``'realkey'`` is the "real", unaliased key. - * `alias(from_'myalias', to='realkey')`: Alias `myalias` to `realkey` so - `d['myalias']` behaves exactly like `d['realkey']` for both reads and writes. - * `from_` is the first keyword argument, but typically it can be omitted - and still reads fine. See below examples for this usage. - See below for details on how an alias affects other dict operations. - * `alias('myalias', to=('realkey', 'otherrealkey'))`: Alias `myalias` to - both `realkey` and `otherrealkey`. As you might expect, this only works well - for writes, as there is never any guarantee that all targets of the alias - will contain the same value. - * `unalias('myalias')`: Removes the `myalias` alias; any subsequent - reads/writes to `myalias` will behave as normal for a regular `dict`. - * `'myalias' in d` (aka `__contains__`): Returns True when given an alias, so - if `myalias` is an alias to some other key, dictionary membership tests will - behave as if `myalias` is set. - * `del d['myalias']` (aka `__delitem__`): This effectively becomes `del - d['realkey']` -- to remove the alias itself, use `unalias()`. - * `del d['realkey']`: Deletes the real key/value pair (i.e. it calls - `dict.__del__`) but doesn't touch any aliases pointing to `realkey`. - * As a result, "dangling" aliases pointing to nonexistent keys will raise - `KeyError` on access, but will continue working if the target key is - repopulated later. + - ``alias(from_'myalias', to='realkey')``: Alias ``myalias`` to ``realkey`` so + ``d['myalias']`` behaves exactly like ``d['realkey']`` for both reads and + writes. + + - ``from_`` is the first keyword argument, but typically it can be omitted + and still reads fine. See below examples for this usage. See below for + details on how an alias affects other dict operations. + + - ``alias('myalias', to=('realkey', 'otherrealkey'))``: Alias ``myalias`` to + both ``realkey`` and ``otherrealkey``. As you might expect, this only works + well for writes, as there is never any guarantee that all targets of the + alias will contain the same value. + - ``unalias('myalias')``: Removes the ``myalias`` alias; any subsequent + reads/writes to ``myalias`` will behave as normal for a regular ``dict``. + - ``'myalias' in d`` (aka ``__contains__``): Returns True when given an alias, + so if ``myalias`` is an alias to some other key, dictionary membership tests + will behave as if ``myalias`` is set. + - ``del d['myalias']`` (aka ``__delitem__``): This effectively becomes ``del + d['realkey']`` -- to remove the alias itself, use ``unalias()``. + - ``del d['realkey']``: Deletes the real key/value pair (i.e. it calls + ``dict.__del__``) but doesn't touch any aliases pointing to ``realkey``. + + - As a result, "dangling" aliases pointing to nonexistent keys will raise + ``KeyError`` on access, but will continue working if the target key is + repopulated later. Caveats: - * Because of the single-key/multi-key duality, `AliasDict` is incapable of - honoring non-string-type keys when aliasing (it must test `isinstance(key, - basestring)` to tell strings apart from non-string iterables). - * `AliasDict` instances may still *use* non-string keys, of course -- it - just can't use them as alias targets. - - ### `AttributeDict` - - * `d.key = 'value'` (aka `__setattr__`): Maps directly to `d['key'] = 'value'`. - * `d.key` (aka `__getattr__`): Maps directly to `d['key']`. - * `del d.key` (aka `__delattr__`): Maps directly to `del d['key']`. - * Collisions between "real" or pre-existing attributes, and + - Because of the single-key/multi-key duality, ``AliasDict`` is incapable of + honoring non-string-type keys when aliasing (it must test ``isinstance(key, + basestring)`` to tell strings apart from non-string iterables). + + - ``AliasDict`` instances may still *use* non-string keys, of course -- it + just can't use them as alias targets. + + ``AttributeDict`` + ----------------- + + - ``d.key = 'value'`` (aka ``__setattr__``): Maps directly to ``d['key'] = + 'value'``. + - ``d.key`` (aka ``__getattr__``): Maps directly to ``d['key']``. + - ``del d.key`` (aka ``__delattr__``): Maps directly to ``del d['key']``. + - Collisions between "real" or pre-existing attributes, and attributes-as-dict-keys, always results in the real attribute winning. Thus - it isn't possible to use attribute access to access e.g. `d['get']`. + it isn't possible to use attribute access to access e.g. ``d['get']``. - ### `Lexicon` + ``Lexicon`` + ----------- - Lexicon subclasses from `AttributeDict` first, then `AliasDict`, with the end - result that attribute access will honor aliases. E.g.: + Lexicon subclasses from ``AttributeDict`` first, then ``AliasDict``, with the + end result that attribute access will honor aliases. E.g.: d = Lexicon() d.alias('myalias', to='realkey') @@ -106,13 +137,12 @@ Classifier: Operating System :: Unix Classifier: Operating System :: POSIX Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules +Description-Content-Type: text/x-rst diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/lexicon.egg-info/SOURCES.txt new/lexicon-2.0.1/lexicon.egg-info/SOURCES.txt --- old/lexicon-1.0.0/lexicon.egg-info/SOURCES.txt 2016-02-17 23:10:28.000000000 +0100 +++ new/lexicon-2.0.1/lexicon.egg-info/SOURCES.txt 2021-09-10 20:38:28.000000000 +0200 @@ -1,16 +1,19 @@ LICENSE MANIFEST.in -README.md +README.rst dev-requirements.txt setup.cfg setup.py +docs/changelog.rst +docs/conf.py +docs/index.rst lexicon/__init__.py +lexicon/_version.py lexicon/alias_dict.py lexicon/attribute_dict.py lexicon.egg-info/PKG-INFO lexicon.egg-info/SOURCES.txt lexicon.egg-info/dependency_links.txt -lexicon.egg-info/requires.txt lexicon.egg-info/top_level.txt tests/alias_dict.py tests/attribute_dict.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/lexicon.egg-info/requires.txt new/lexicon-2.0.1/lexicon.egg-info/requires.txt --- old/lexicon-1.0.0/lexicon.egg-info/requires.txt 2016-02-17 23:10:28.000000000 +0100 +++ new/lexicon-2.0.1/lexicon.egg-info/requires.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -six diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/setup.cfg new/lexicon-2.0.1/setup.cfg --- old/lexicon-1.0.0/setup.cfg 2016-02-17 23:10:28.000000000 +0100 +++ new/lexicon-2.0.1/setup.cfg 2021-09-10 20:38:28.000000000 +0200 @@ -1,8 +1,10 @@ [bdist_wheel] universal = 1 +[metadata] +license_file = LICENSE + [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/setup.py new/lexicon-2.0.1/setup.py --- old/lexicon-1.0.0/setup.py 2016-02-17 22:39:42.000000000 +0100 +++ new/lexicon-2.0.1/setup.py 2021-09-10 20:31:50.000000000 +0200 @@ -1,48 +1,51 @@ #!/usr/bin/env python import os -import sys -# Support setuptools or distutils -try: - from setuptools import setup -except ImportError: - from distutils.core import setup +from setuptools import setup -long_description = open(os.path.join(os.path.dirname(__file__), 'README.md')).read() +# Version info -- read without importing +_locals = {} +with open("lexicon/_version.py") as fp: + exec(fp.read(), None, _locals) +version = _locals["__version__"] + +# Readme +with open(os.path.join(os.path.dirname(__file__), "README.rst")) as fd: + long_description = fd.read() setup( - name='lexicon', - version="1.0.0", - description='Powerful dict subclass(es) with aliasing & attribute access', - license='BSD', - + name="lexicon", + version=version, + description="Powerful dict subclass(es) with aliasing & attribute access", + license="BSD", long_description=long_description, - author='Jeff Forcier', - author_email='j...@bitprophet.org', - url='https://github.com/bitprophet/lexicon', - + long_description_content_type="text/x-rst", + author="Jeff Forcier", + author_email="j...@bitprophet.org", + url="https://github.com/bitprophet/lexicon#what", + project_urls={ + "Source": "https://github.com/bitprophet/lexicon", + "Changelog": "https://github.com/bitprophet/lexicon/blob/main/docs/changelog.rst", + "CI": "https://app.circleci.com/pipelines/github/bitprophet/lexicon", + }, packages=["lexicon"], - install_requires=["six"], - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Unix', - 'Operating System :: POSIX', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Topic :: Software Development', - 'Topic :: Software Development :: Libraries', - 'Topic :: Software Development :: Libraries :: Python Modules', + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Unix", + "Operating System :: POSIX", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules", ], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/tests/alias_dict.py new/lexicon-2.0.1/tests/alias_dict.py --- old/lexicon-1.0.0/tests/alias_dict.py 2016-02-17 22:26:09.000000000 +0100 +++ new/lexicon-2.0.1/tests/alias_dict.py 2021-07-08 23:39:27.000000000 +0200 @@ -1,118 +1,133 @@ import copy -import six -from spec import Spec, eq_, ok_, raises, skip +from pytest import raises from lexicon import AliasDict -class AliasDict_(Spec): +class AliasDict_: class alias: def allows_aliasing_of_single_target_key(self): ad = AliasDict() - ad.alias(from_='myalias', to='realkey') - ad['realkey'] = 'value' - eq_(ad['myalias'], 'value') + ad.alias(from_="myalias", to="realkey") + ad["realkey"] = "value" + assert ad["myalias"] == "value" def allows_aliasing_of_multiple_target_keys(self): ad = AliasDict() - ad.alias(from_='myalias', to=('key1', 'key2')) - ad['key1'] = ad['key2'] = False - assert not ad['key1'] - ad['myalias'] = True - assert ad['key1'] and ad['key2'] + ad.alias(from_="myalias", to=("key1", "key2")) + ad["key1"] = ad["key2"] = False + assert not ad["key1"] + ad["myalias"] = True + assert ad["key1"] and ad["key2"] class unalias: def unsets_aliases(self): ad = AliasDict() - ad['realkey'] = 'value' - ad.alias('myalias', to='realkey') - eq_(ad['myalias'], 'value') - ad.unalias('myalias') - assert 'myalias' not in ad + ad["realkey"] = "value" + ad.alias("myalias", to="realkey") + assert ad["myalias"] == "value" + ad.unalias("myalias") + assert "myalias" not in ad - @raises(KeyError) def raises_KeyError_on_nonexistent_alias(self): ad = AliasDict() - ad.unalias('lol no') + with raises(KeyError): + ad.unalias("lol no") class aliases_of: def setup(self): self.ad = AliasDict() def returns_list_of_aliases_for_given_real_key(self): - eq_(self.ad.aliases_of('realkey'), []) - self.ad.alias('myalias', to='realkey') - eq_(self.ad.aliases_of('realkey'), ['myalias']) - self.ad.unalias('myalias') - eq_(self.ad.aliases_of('realkey'), []) + assert self.ad.aliases_of("realkey") == [] + self.ad.alias("myalias", to="realkey") + assert self.ad.aliases_of("realkey") == ["myalias"] + self.ad.unalias("myalias") + assert self.ad.aliases_of("realkey") == [] def returns_empty_list_for_unaliased_keys(self): - self.ad['realkey'] = 5 - eq_(self.ad.aliases_of('realkey'), []) + self.ad["realkey"] = 5 + assert self.ad.aliases_of("realkey") == [] def returns_multi_item_list_for_multiple_aliases(self): - self.ad.alias('alias1', to='realkey') - self.ad.alias('alias2', to='realkey') - eq_(set(self.ad.aliases_of('realkey')), set(['alias1', 'alias2'])) + self.ad.alias("alias1", to="realkey") + self.ad.alias("alias2", to="realkey") + assert set(self.ad.aliases_of("realkey")), set( + ["alias1" == "alias2"] + ) def returns_list_of_aliases_for_alias(self): - self.ad.alias('myalias', to='realkey') - result = set(self.ad.aliases_of('myalias')) - expected = set(['realkey']) - eq_(result, expected) + self.ad.alias("myalias", to="realkey") + result = set(self.ad.aliases_of("myalias")) + expected = set(["realkey"]) + assert result == expected - def membership_tests(self): + def single_membership_tests(self): ad = AliasDict() - ad.alias('myalias', to='realkey') - ad['realkey'] = 'value' - assert 'myalias' in ad + ad.alias("myalias", to="realkey") + ad["realkey"] = "value" + assert "myalias" in ad + + def multi_membership_test(self): + ad = AliasDict() + ad.alias("multi-alias", to=("key1", "key2")) + # No targets actually exist: false + assert "multi-alias" not in ad + # One target exists: still false + ad["key1"] = 5 + assert "multi-alias" not in ad + # All exist: true + ad["key2"] = 5 + assert "multi-alias" in ad def key_deletion(self): ad = AliasDict() - ad.alias('myalias', to='realkey') - ad['realkey'] = 'value' - assert 'realkey' in ad - del ad['myalias'] - assert 'realkey' not in ad - assert 'myalias' not in ad + ad.alias("myalias", to="realkey") + ad["realkey"] = "value" + assert "realkey" in ad + del ad["myalias"] + assert "realkey" not in ad + assert "myalias" not in ad - @raises(ValueError) def access_to_multi_target_aliases_is_undefined(self): ad = AliasDict() - ad.alias('myalias', to=('key1', 'key2')) - ad['key1'] = ad['key2'] = 5 - ad['myalias'] + ad.alias("myalias", to=("key1", "key2")) + ad["key1"] = ad["key2"] = 5 + with raises(ValueError): + ad["myalias"] class dangling_aliases: "dangling aliases" - @raises(KeyError) + def raise_KeyError_on_access(self): ad = AliasDict() - ad.alias('myalias', to='realkey') - assert 'realkey' not in ad - ad['myalias'] + ad.alias("myalias", to="realkey") + assert "realkey" not in ad + with raises(KeyError): + ad["myalias"] - @raises(KeyError) def caused_by_removal_of_target_key(self): - # TODO: this test probably false-passes if any line but the last raises - # KeyError by accident... + # TODO: this test probably false-passes if any line but the last + # raises KeyError by accident... ad = AliasDict() - ad.alias('myalias', to='realkey') - ad['realkey'] = 'value' - assert 'realkey' in ad - eq_(ad['myalias'], 'value') - del ad['realkey'] - ad['myalias'] + ad.alias("myalias", to="realkey") + ad["realkey"] = "value" + assert "realkey" in ad + assert ad["myalias"] == "value" + del ad["realkey"] + with raises(KeyError): + ad["myalias"] class recursive_aliasing: "recursive aliasing" + def _recursive_aliases(self): ad = AliasDict() - ad.alias('alias1', to='realkey') - ad.alias('alias2', to='alias1') - ad['alias2'] = 'value' - assert ad['alias1'] == ad['alias2'] == ad['realkey'] == 'value' + ad.alias("alias1", to="realkey") + ad.alias("alias2", to="alias1") + ad["alias2"] = "value" + assert ad["alias1"] == ad["alias2"] == ad["realkey"] == "value" return ad def works_in_base_case(self): @@ -120,46 +135,44 @@ def unalias_is_not_recursive(self): ad = self._recursive_aliases() - ad.unalias('alias2') - assert 'alias1' in ad - eq_(ad['alias1'], 'value') + ad.unalias("alias2") + assert "alias1" in ad + assert ad["alias1"] == "value" def deletion_is_recursive(self): ad = self._recursive_aliases() - del ad['alias2'] - assert 'realkey' not in ad - ad['realkey'] = 'newvalue' - assert 'alias1' in ad - eq_(ad['alias1'], 'newvalue') + del ad["alias2"] + assert "realkey" not in ad + ad["realkey"] = "newvalue" + assert "alias1" in ad + assert ad["alias1"] == "newvalue" def deepcopy_copies_aliases_correctly(self): - a1 = AliasDict({'key1': 'val1', 'key2': 'val2'}) - a1.alias('myalias', to='key1') - eq_(a1['myalias'], 'val1') + a1 = AliasDict({"key1": "val1", "key2": "val2"}) + a1.alias("myalias", to="key1") + assert a1["myalias"] == "val1" a2 = copy.deepcopy(a1) - assert 'key1' in a2 - eq_(a2['key2'], 'val2') - a1.unalias('myalias') - assert 'myalias' not in a1 - assert 'myalias' in a2 - eq_(a2['myalias'], 'val1') + assert "key1" in a2 + assert a2["key2"] == "val2" + a1.unalias("myalias") + assert "myalias" not in a1 + assert "myalias" in a2 + assert a2["myalias"] == "val1" class aliases_are_not_real_keys: "aliases are not real keys" def setup(self): - self.a = AliasDict({'key1': 'val1', 'key2': 'val2'}) - self.a.alias('myalias', 'key1') + self.a = AliasDict({"key1": "val1", "key2": "val2"}) + self.a.alias("myalias", "key1") def keys_returns_only_real_keys(self): "keys() only returns real keys, not aliases" - assert 'myalias' not in self.a.keys() - assert 'key1' in self.a.keys() - assert 'key2' in self.a.keys() + assert "myalias" not in self.a.keys() + assert "key1" in self.a.keys() + assert "key2" in self.a.keys() def items_returns_only_real_keys(self): "items() and iteritems() only return real keys, not aliases" - assert ('key1', 'val1') in self.a.items() - assert ('key2', 'val2') in six.iteritems(self.a) - assert ('myalias', 'val1') not in self.a.items() - assert ('myalias', 'val1') not in six.iteritems(self.a) + assert ("key1", "val1") in self.a.items() + assert ("myalias", "val1") not in self.a.items() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/tests/attribute_dict.py new/lexicon-2.0.1/tests/attribute_dict.py --- old/lexicon-1.0.0/tests/attribute_dict.py 2016-02-17 22:27:54.000000000 +0100 +++ new/lexicon-2.0.1/tests/attribute_dict.py 2021-07-08 23:39:27.000000000 +0200 @@ -1,46 +1,43 @@ import copy -import six -from spec import Spec, eq_, ok_ - from lexicon import AttributeDict -class AttributeDict_(Spec): +class AttributeDict_: def allows_attribute_reads(self): ad = AttributeDict() - ad['foo'] = 'bar' - eq_(ad['foo'], ad.foo) + ad["foo"] = "bar" + assert ad["foo"] == ad.foo def allows_attribute_writes(self): ad = AttributeDict() - ad['foo'] = 'bar' - eq_(ad['foo'], 'bar') - ad.foo = 'notbar' - eq_(ad['foo'], 'notbar') + ad["foo"] = "bar" + assert ad["foo"] == "bar" + ad.foo = "notbar" + assert ad["foo"] == "notbar" def honors_attribute_deletion(self): ad = AttributeDict() - ad['foo'] = 'bar' - eq_(ad.foo, 'bar') + ad["foo"] = "bar" + assert ad.foo == "bar" del ad.foo - assert 'foo' not in ad + assert "foo" not in ad def ensures_real_attributes_win(self): ad = AttributeDict() - ad['get'] = 'not-a-method' + ad["get"] = "not-a-method" assert callable(ad.get) - assert not isinstance(ad.get, six.string_types) + assert not isinstance(ad.get, str) def ensure_deepcopy_works(self): ad = AttributeDict() - ad['foo'] = 'bar' - eq_(ad.foo, 'bar') + ad["foo"] = "bar" + assert ad.foo == "bar" ad2 = copy.deepcopy(ad) - ad2.foo = 'biz' + ad2.foo = "biz" assert ad2.foo != ad.foo def dir_shows_keys(self): ad = AttributeDict() - ad['foo'] = 'bar' - assert 'foo' in dir(ad) + ad["foo"] = "bar" + assert "foo" in dir(ad) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lexicon-1.0.0/tests/lexicon_.py new/lexicon-2.0.1/tests/lexicon_.py --- old/lexicon-1.0.0/tests/lexicon_.py 2016-02-17 22:27:54.000000000 +0100 +++ new/lexicon-2.0.1/tests/lexicon_.py 2021-07-08 23:39:27.000000000 +0200 @@ -1,47 +1,45 @@ import copy -from spec import Spec, eq_ - from lexicon import Lexicon -class Lexicon_(Spec): +class Lexicon_: def attributes_work(self): - l = Lexicon() - l.foo = 'bar' - eq_(l['foo'], l.foo) + lex = Lexicon() + lex.foo = "bar" + assert lex["foo"] == lex.foo def aliases_work(self): - l = Lexicon() - l.alias('foo', to='bar') - l['bar'] = 'value' - assert l['foo'] == l['bar'] == 'value' + lex = Lexicon() + lex.alias("foo", to="bar") + lex["bar"] = "value" + assert lex["foo"] == lex["bar"] == "value" def aliases_appear_in_attributes(self): - l = Lexicon() - l.alias('foo', to='bar') - l.foo = 'value' - assert l.foo == l.bar == l['foo'] == l['bar'] == 'value' + lex = Lexicon() + lex.alias("foo", to="bar") + lex.foo = "value" + assert lex.foo == lex.bar == lex["foo"] == lex["bar"] == "value" def aliased_real_attributes_do_not_override_real_attributes(self): - l = Lexicon() - l.alias('get', to='notget') - l.notget = 'value' - assert callable(l.get) - assert l.get != 'value' + lex = Lexicon() + lex.alias("get", to="notget") + lex.notget = "value" + assert callable(lex.get) + assert lex.get != "value" def ensure_deepcopy_works(self): - l = Lexicon() - l['foo'] = 'bar' - eq_(l.foo, 'bar') - l2 = copy.deepcopy(l) - l2.foo = 'biz' - assert l2.foo != l.foo + lex = Lexicon() + lex["foo"] = "bar" + assert lex.foo == "bar" + lex2 = copy.deepcopy(lex) + lex2.foo = "biz" + assert lex2.foo != lex.foo def dir_only_shows_real_keys(self): "dir() only shows real keys-as-attrs, not aliases" - a = Lexicon({'key1': 'val1', 'key2': 'val2'}) - a.alias('myalias', 'key1') - assert 'key1' in dir(a) - assert 'key2' in dir(a) - assert 'myalias' not in dir(a) + a = Lexicon({"key1": "val1", "key2": "val2"}) + a.alias("myalias", "key1") + assert "key1" in dir(a) + assert "key2" in dir(a) + assert "myalias" not in dir(a)