From 51d8cfcca54e79c58cd4c9057243e1d1fc141b6a Mon Sep 17 00:00:00 2001 From: Bit0r Date: Wed, 12 Jun 2024 10:33:07 +0800 Subject: [PATCH 1/7] Add support for accessing nested items in BoxList using numpy-style tuple indexing. (#266) --- box/box_list.py | 8 ++++++++ test/test_box_list.py | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/box/box_list.py b/box/box_list.py index 048b014..1850471 100644 --- a/box/box_list.py +++ b/box/box_list.py @@ -65,6 +65,14 @@ def __getitem__(self, item): if len(list_pos.group()) == len(item): return value return value.__getitem__(item[len(list_pos.group()) :].lstrip(".")) + if isinstance(item, tuple): + result = self + for idx in item: + if isinstance(result, list): + result = result[idx] + else: + raise BoxTypeError(f"Cannot numpy-style indexing on {type(result).__name__}.") + return result return super().__getitem__(item) def __delitem__(self, key): diff --git a/test/test_box_list.py b/test/test_box_list.py index 536520f..1b7bfa3 100644 --- a/test/test_box_list.py +++ b/test/test_box_list.py @@ -35,6 +35,10 @@ def test_box_list(self): assert new_list[-1].item == 22 new_list.append([{"bad_item": 33}]) assert new_list[-1][0].bad_item == 33 + new_list[-1].append([{"bad_item": 33}]) + assert new_list[-1, -1, 0].bad_item == 33 + bx = Box({0: {1: {2: {3: 3}}}, (0, 1, 2, 3): 4}) + assert bx[0, 1, 2, 3] == 4 assert repr(new_list).startswith("BoxList(") for x in new_list.to_list(): assert not isinstance(x, (BoxList, Box)) From 0d6e4b75a8c02ff31ef021eb37184e6baefc00c3 Mon Sep 17 00:00:00 2001 From: Muspi Merol Date: Wed, 12 Jun 2024 10:36:54 +0800 Subject: [PATCH 2/7] Fixing #251 support for circular references in lists (#259) --- box/box_list.py | 7 ++++--- test/test_box_list.py | 8 +++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/box/box_list.py b/box/box_list.py index 1850471..e87c879 100644 --- a/box/box_list.py +++ b/box/box_list.py @@ -40,16 +40,17 @@ def __new__(cls, *args, **kwargs): # This is required for pickling to work correctly obj.box_options = {"box_class": box.Box} obj.box_options.update(kwargs) - obj.box_org_ref = 0 + obj.box_org_ref = None return obj def __init__(self, iterable: Optional[Iterable] = None, box_class: Type[box.Box] = box.Box, **box_options): self.box_options = box_options self.box_options["box_class"] = box_class - self.box_org_ref = id(iterable) if iterable else 0 + self.box_org_ref = iterable if iterable: for x in iterable: self.append(x) + self.box_org_ref = None if box_options.get("frozen_box"): def frozen(*args, **kwargs): @@ -109,7 +110,7 @@ def _convert(self, p_object): elif isinstance(p_object, box.Box): p_object._box_config.update(self.box_options) if isinstance(p_object, list) and not self._is_intact_type(p_object): - p_object = self.__class__(p_object, **self.box_options) + p_object = self if p_object is self or p_object is self.box_org_ref else self.__class__(p_object, **self.box_options) elif isinstance(p_object, BoxList): p_object.box_options.update(self.box_options) return p_object diff --git a/test/test_box_list.py b/test/test_box_list.py index 1b7bfa3..e22c3a5 100644 --- a/test/test_box_list.py +++ b/test/test_box_list.py @@ -232,10 +232,8 @@ def test_no_recursion_errors(self): a.list_of_dicts.append([{"example2": 2}]) assert a["list_of_dicts"][1] == [{"example2": 2}] - def test_no_circular_references(self): - if sys.version_info >= (3, 12) and sys.platform == "win32": - pytest.skip("Windows fatal exception: stack overflow on github actions") + def test_circular_references(self): circular_list = [] circular_list.append(circular_list) - with pytest.raises(RecursionError): - BoxList(circular_list) + circular_box = BoxList(circular_list) + assert circular_box[0] == circular_box From fa12326d01738f23a018efac07d450019e07f425 Mon Sep 17 00:00:00 2001 From: Gabriel Tkacz <55806524+gtkacz@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:38:17 -0300 Subject: [PATCH 3/7] Altering __repr__ methods to accurately represent subclass names (#270) Co-authored-by: Gabriel Tkacz --- AUTHORS.rst | 1 + CHANGES.rst | 5 +++++ box/box.py | 2 +- box/box_list.py | 2 +- box/config_box.py | 2 +- box/shorthand_box.py | 4 ++-- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index b67a735..e0f80c0 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -30,6 +30,7 @@ Code contributions: - Michał Górny (mgorny) - Serge Lu (Serge45) - Eric Prestat (ericpre) +- Gabriel Mitelman Tkacz (gtkacz) diff --git a/CHANGES.rst b/CHANGES.rst index 0272697..3029993 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,11 @@ Changelog ========= +Version 7.1.2 +------------- + +* Fixing #261 altering all `__repr__` methods so that subclassing will output the correct class name + Version 7.1.1 ------------- diff --git a/box/box.py b/box/box.py index 158a55e..191903e 100644 --- a/box/box.py +++ b/box/box.py @@ -777,7 +777,7 @@ def popitem(self): return key, self.pop(key) def __repr__(self) -> str: - return f"Box({self})" + return f"{self.__class__.__name__}({self})" def __str__(self) -> str: return str(self.to_dict()) diff --git a/box/box_list.py b/box/box_list.py index e87c879..fd296d6 100644 --- a/box/box_list.py +++ b/box/box_list.py @@ -142,7 +142,7 @@ def _dotted_helper(self) -> List[str]: return keys def __repr__(self): - return f"BoxList({self.to_list()})" + return f"{self.__class__.__name__}({self.to_list()})" def __str__(self): return str(self.to_list()) diff --git a/box/config_box.py b/box/config_box.py index 0202ca3..4c48877 100644 --- a/box/config_box.py +++ b/box/config_box.py @@ -124,7 +124,7 @@ def getfloat(self, item, default=None): return self.float(item, default) def __repr__(self): - return "ConfigBox({0})".format(str(self.to_dict())) + return f"{self.__class__.__name__}({str(self.to_dict())})" def copy(self): return ConfigBox(super().copy()) diff --git a/box/shorthand_box.py b/box/shorthand_box.py index 99dfc8d..a82edbd 100644 --- a/box/shorthand_box.py +++ b/box/shorthand_box.py @@ -44,7 +44,7 @@ def toml(self) -> str: return self.to_toml() def __repr__(self): - return f"SBox({self})" + return f"{self.__class__.__name__}({self})" def copy(self) -> "SBox": return SBox(super(SBox, self).copy()) @@ -66,4 +66,4 @@ def __new__(cls, *args, **kwargs): return obj def __repr__(self) -> str: - return f"DDBox({self})" + return f"{self.__class__.__name__}({self})" From f31f53c17dad0ed600486ee4a6c2010ca193e4a8 Mon Sep 17 00:00:00 2001 From: YISH Date: Wed, 12 Jun 2024 10:38:53 +0800 Subject: [PATCH 4/7] Fix type 'int' not iterable (#268) --- box/box.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/box/box.py b/box/box.py index 191903e..6729616 100644 --- a/box/box.py +++ b/box/box.py @@ -415,7 +415,8 @@ def __contains__(self, item): except BoxError: return False else: - return children in self[first_item] + it = self[first_item] + return isinstance(it, Iterable) and children in it def keys(self, dotted: Union[bool] = False): if not dotted: From db5a0246298add3eb9fff034c0928a06c90bc57d Mon Sep 17 00:00:00 2001 From: Chris Griffith Date: Tue, 11 Jun 2024 21:55:23 -0500 Subject: [PATCH 5/7] Bump to 7.2.0 Add tests for Cython --- .github/workflows/pythonpublish.yml | 23 +++++++++++------------ .github/workflows/tests.yml | 26 +++++++++++++------------- .pre-commit-config.yaml | 10 +++++----- AUTHORS.rst | 4 +++- CHANGES.rst | 8 ++++++-- box/__init__.py | 2 +- box/box_list.py | 6 +++++- 7 files changed, 44 insertions(+), 35 deletions(-) diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index e24267a..791b92a 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' - name: Install Dependencies run: | @@ -39,13 +39,13 @@ jobs: strategy: matrix: os: [macos-11, windows-latest] - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -63,11 +63,11 @@ jobs: deploy-cython-manylinux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.11 - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - name: Set up Python 3.12 + uses: actions/setup-python@v5 with: - python-version: "3.11" + python-version: "3.12" - name: Build wheels run: | @@ -75,7 +75,7 @@ jobs: pip install cibuildwheel setuptools wheel python -m cibuildwheel --output-dir dist env: - CIBW_BUILD: cp38-manylinux_x86_64 cp39-manylinux_x86_64 cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp311-macosx_x86_64 + CIBW_BUILD: cp38-manylinux_x86_64 cp39-manylinux_x86_64 cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 CIBW_BEFORE_BUILD: pip install Cython==3.0.0 CIBW_BEFORE_TEST: pip install -r requirements.txt -r requirements-test.txt setuptools wheel twine CIBW_TEST_COMMAND: pytest {package}/test -vv @@ -87,4 +87,3 @@ jobs: run: | pip install twine twine upload dist/*-manylinux*.whl - twine upload dist/*-macosx*.whl diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index db506f9..d83c48b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,13 +13,13 @@ jobs: package-checks: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12-dev", "pypy-3.8"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13-dev", "pypy-3.8"] os: [ubuntu-latest, macos-11, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - uses: actions/cache@v3 @@ -58,7 +58,7 @@ jobs: Remove-item box -recurse -force python -m pytest -vv - name: Upload wheel artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: python_box path: dist/*.whl @@ -66,11 +66,11 @@ jobs: package-manylinux-checks: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.11 - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - name: Set up Python 3.12 + uses: actions/setup-python@v5 with: - python-version: "3.11" + python-version: "3.12" - uses: actions/cache@v3 with: @@ -83,13 +83,13 @@ jobs: pip install cibuildwheel python -m cibuildwheel --output-dir dist env: - CIBW_BUILD: cp38-manylinux_x86_64 cp39-manylinux_x86_64 cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp311-macosx_x86_64 + CIBW_BUILD: cp38-manylinux_x86_64 cp39-manylinux_x86_64 cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 CIBW_BEFORE_BUILD: pip install Cython==3.0.0 CIBW_BEFORE_TEST: pip install -r requirements.txt -r requirements-test.txt setuptools wheel twine CIBW_TEST_COMMAND: pytest {package}/test -vv - name: Upload wheel artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: python_box path: dist/*-manylinux*.whl @@ -97,13 +97,13 @@ jobs: test: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] os: [ubuntu-latest, macos-11, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - uses: actions/cache@v3 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eb3c1f0..b91d368 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.6.0 hooks: # Identify invalid files - id: check-ast @@ -20,8 +20,8 @@ repos: - id: fix-encoding-pragma - id: fix-byte-order-marker # General quality checks - - id: mixed-line-ending - args: [--fix=lf] +# - id: mixed-line-ending +# args: [--fix=lf] - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - id: check-executables-have-shebangs @@ -29,7 +29,7 @@ repos: exclude: ^test/data/.+ - repo: https://github.com/ambv/black - rev: 23.7.0 + rev: 24.4.2 hooks: - id: black args: [--config=.black.toml] @@ -51,7 +51,7 @@ repos: always_run: true - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.4.1' + rev: 'v1.10.0' hooks: - id: mypy types: [python] diff --git a/AUTHORS.rst b/AUTHORS.rst index e0f80c0..c0b068d 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -31,7 +31,9 @@ Code contributions: - Serge Lu (Serge45) - Eric Prestat (ericpre) - Gabriel Mitelman Tkacz (gtkacz) - +- Muspi Merol (CNSeniorious000) +- YISH (mokeyish) +- Bit0r Suggestions and bug reporting: diff --git a/CHANGES.rst b/CHANGES.rst index 3029993..f2db4c8 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,10 +1,14 @@ Changelog ========= -Version 7.1.2 +Version 7.2.0 ------------- -* Fixing #261 altering all `__repr__` methods so that subclassing will output the correct class name +* Adding #266 support for accessing nested items in BoxList using numpy-style tuple indexing (thanks to Bit0r) +* Adding tests and Cython releases for Python 3.12 +* Fixing #251 support for circular references in lists (thanks to Muspi Merol) +* Fixing #261 altering all `__repr__` methods so that subclassing will output the correct class name (thanks to Gabriel Tkacz) +* Fixing #267 Fix type 'int' not iterable (thanks to YISH) Version 7.1.1 ------------- diff --git a/box/__init__.py b/box/__init__.py index 10b4ce6..adc6199 100644 --- a/box/__init__.py +++ b/box/__init__.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- __author__ = "Chris Griffith" -__version__ = "7.1.1" +__version__ = "7.2.0" from box.box import Box from box.box_list import BoxList diff --git a/box/box_list.py b/box/box_list.py index fd296d6..3535f22 100644 --- a/box/box_list.py +++ b/box/box_list.py @@ -110,7 +110,11 @@ def _convert(self, p_object): elif isinstance(p_object, box.Box): p_object._box_config.update(self.box_options) if isinstance(p_object, list) and not self._is_intact_type(p_object): - p_object = self if p_object is self or p_object is self.box_org_ref else self.__class__(p_object, **self.box_options) + p_object = ( + self + if p_object is self or p_object is self.box_org_ref + else self.__class__(p_object, **self.box_options) + ) elif isinstance(p_object, BoxList): p_object.box_options.update(self.box_options) return p_object From 1e36a59cccc46b94ffcfaac7d03620fe01930816 Mon Sep 17 00:00:00 2001 From: Chris Griffith Date: Tue, 11 Jun 2024 23:20:07 -0500 Subject: [PATCH 6/7] Fix tests for new artifact upload naming --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d83c48b..2be9fce 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -60,7 +60,7 @@ jobs: - name: Upload wheel artifact uses: actions/upload-artifact@v4 with: - name: python_box + name: python_box_${{matrix.os}}_${{ matrix.python-version }} path: dist/*.whl package-manylinux-checks: @@ -91,7 +91,7 @@ jobs: - name: Upload wheel artifact uses: actions/upload-artifact@v4 with: - name: python_box + name: python_box_manylinux path: dist/*-manylinux*.whl test: From e791547e953960936a45151bf2735b2c4ed03eb1 Mon Sep 17 00:00:00 2001 From: Chris Griffith Date: Tue, 11 Jun 2024 23:25:22 -0500 Subject: [PATCH 7/7] Removing 3.13 as it's currently breaking --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2be9fce..389b419 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: package-checks: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13-dev", "pypy-3.8"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.8"] os: [ubuntu-latest, macos-11, windows-latest] runs-on: ${{ matrix.os }} steps: