Skip to content

Commit de0fb23

Browse files
committed
v2.13.0 - DictObject fixes + Added DictDataClass and copy_class to collections
**New Features** All new features in this commit, were added in the `privex/helpers/collections.py` module. - Added previously missing `geoip` extra to setup.py extensions list. While the `geoip.txt` extra file was added a few versions ago, I forgot to register it in setup.py :) - Added new collections helper function `copy_class`, which is able to deep copy "normal" non-complex classes / types, including slotted classes (classes that use `__slots__`). This allows you to duplicate an existing class, severing any object pointers contained within it's attributes, without having to inherit it or copy and paste it. - `_q_copy` internal function used to deep copy a given object, and assist with determining whether to use copy.deepcopy, or just return a reference based on the optional attribute/item key passed to it. - `_copy_class_dict` internal function - handles deep copying standard classes which use `__dict__` - `_copy_class_slotted` internal function - handles deep copying slotted classes - i.e. those which use `__slots__` instead of the standard and default `__dict__`. - `Dictable` now includes magic methods for getitem and setitem, allowing dataclasses based on `Dictable` to have their attributes accessed and updated as if they were a dictionary. - Added instance method `get` to `Dictable`, which works similarly to the standard `dict.get` with a fallback if the key does not exist. - Brand new `DictDataClass` dataclass base class, based on `Dictable`. This class is designed to massively improve interoperability between dataclasses and dictionaries - smoothing both conversion from dictionaries, and conversions back into dictionaries. It includes 4 different dictionary conversion settings for your dataclass, allowing you to choose per-class how you'd like it to handle converting your dataclass into a `dict` - including the ability to set a list of attribute names which will contain a list of objects such as `Dictable` / `DictDataClass` based dataclasses - which will be converted into lists of dictionaries when the instance is casted into a `dict`. - Added the alias `DictDataclass` for `DictDataClass`, since people (including myself) are bound to get confused about the spelling many times. - Added compatibility code to `collections.py` to prevent the lack of dataclasses on Python 3.6 breaking the entire module. The module displays a warning when it's imported if it detects that dataclasses aren't available, with information on how rectify the issue. It uses `Mocker` to generate the dummy classes `dataclass` and `field`, along with the `dataclasses` module. This will allow classes/methods/functions which use `dataclass` / `field` or the dataclasses module in their type annotations to be interpreted correctly, without throwing a syntax error due to the missing `dataclass` / `field` / `dataclasses` objects. This obviously does not mean `Dictable` or `DictDataClass` will actually function on Python 3.6 properly without a shim library such as the aptly named `dataclasses` PyPi package. The module is just patched with dummy classes/modules so that otherwise missing references to dataclasses don't break the entire `collections` module. **Bug Fixes** - Fixed an issue where if you access or set non-existent items via attributes on a `DictObject` or `OrderedDictObject`, a `KeyError` is raised. This results in problems with code which expects a non-existent attribute to raise `AttributeError` - not `KeyError`. The issue has been fixed on both `DictObject` and `OrderedDictObject` by catching `KeyError`'s and re-raising them as `AttributeError`'s, which would be expected to be raised when accessing an attribute that might not exist. - Fixed a similar issue to above on `Mocker` - where when accessing an item (dict-like key), it would pass through the `AttributeError` from `__getattribute__`. It now converts `AttributeError`'s into appropriate `KeyError` exceptions. - Fixed an issue where `pytest` may refuse to run any tests at all, due to a missing package. This was caused by imports for test module classes within `__init__.py`. Fixed by moving direct test class imports in `tests/__init__.py` into the `if __name__` block, so that test modules are only imported if you're running `tests` as a module using the standard Python `unittest` module. **Unit Testing** - Added unit tests for the new `privex.helpers.collections.copy_class` helper function within the new unit test class `tests.test_collections.TestCopyClass` - Added unit tests for `DictDataClass` in the new unit test class `TestDictDataClass`, with a pytest skipif decorator, ensuring the tests are safely skipped on older Python versions such as Python 3.6 (unless the `dataclasses` backport shim library is installed).
1 parent 19b0d97 commit de0fb23

File tree

5 files changed

+898
-200
lines changed

5 files changed

+898
-200
lines changed

privex/helpers/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def _setup_logging(level=logging.WARNING):
143143
log = _setup_logging()
144144
name = 'helpers'
145145

146-
VERSION = '2.12.0'
146+
VERSION = '2.13.0'
147147

148148

149149

0 commit comments

Comments
 (0)