Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions .github/workflows/pythonpublish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand All @@ -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
Expand All @@ -63,19 +63,19 @@ 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: |
python -m pip install --upgrade pip
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
Expand All @@ -87,4 +87,3 @@ jobs:
run: |
pip install twine
twine upload dist/*-manylinux*.whl
twine upload dist/*-macosx*.whl
30 changes: 15 additions & 15 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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", "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
Expand Down Expand Up @@ -58,19 +58,19 @@ 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
name: python_box_${{matrix.os}}_${{ matrix.python-version }}
path: dist/*.whl

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:
Expand All @@ -83,27 +83,27 @@ 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
name: python_box_manylinux
path: dist/*-manylinux*.whl

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
Expand Down
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -20,16 +20,16 @@ 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
- id: end-of-file-fixer
exclude: ^test/data/.+

- repo: https://github.com/ambv/black
rev: 23.7.0
rev: 24.4.2
hooks:
- id: black
args: [--config=.black.toml]
Expand All @@ -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]
Expand Down
5 changes: 4 additions & 1 deletion AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ Code contributions:
- Michał Górny (mgorny)
- Serge Lu (Serge45)
- Eric Prestat (ericpre)

- Gabriel Mitelman Tkacz (gtkacz)
- Muspi Merol (CNSeniorious000)
- YISH (mokeyish)
- Bit0r


Suggestions and bug reporting:
Expand Down
9 changes: 9 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Changelog
=========

Version 7.2.0
-------------

* 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
-------------

Expand Down
2 changes: 1 addition & 1 deletion box/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions box/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -777,7 +778,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())
Expand Down
21 changes: 17 additions & 4 deletions box/box_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -65,6 +66,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):
Expand Down Expand Up @@ -101,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.__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
Expand Down Expand Up @@ -133,7 +146,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())
Expand Down
2 changes: 1 addition & 1 deletion box/config_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
4 changes: 2 additions & 2 deletions box/shorthand_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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})"
12 changes: 7 additions & 5 deletions test/test_box_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -228,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