diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index aab82b8..67de9fc 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: "3.10" - name: install dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 244d398..1b511fa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,22 +9,19 @@ jobs: fail-fast: false matrix: include: - - python: 3.8 + - python: "3.11" toxenv: flake8 os: ubuntu-latest - - python: 3.8 + - python: "3.11" toxenv: mypy os: ubuntu-latest - - python: 3.8 + - python: "3.11" toxenv: pylint os: ubuntu-latest - - python: 3.8 + - python: "3.11" toxenv: black os: ubuntu-latest - - python: 3.7 - toxenv: py37 - os: ubuntu-latest - python: 3.8 toxenv: py38 os: ubuntu-latest @@ -37,25 +34,28 @@ jobs: - python: "3.11" toxenv: py311 os: ubuntu-latest - - python: pypy-3.7 - toxenv: pypy37 + - python: "3.12" + toxenv: py312 + os: ubuntu-latest + - python: 'pypy3.9' + toxenv: pypy39 os: ubuntu-latest - - python: 3.8 - toxenv: py38 + - python: "3.11" + toxenv: py311 os: macos-latest - - python: 3.8 - toxenv: py38 + - python: "3.11" + toxenv: py311 os: windows-latest runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - name: install dependencies - run: python -m pip install --upgrade pip tox + run: python -m pip install --upgrade pip tox setuptools wheel - name: run env: TOXENV: ${{ matrix.toxenv }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 33a8949..639c3ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - Functions for ascents and descents now take an optional argument to specify what step size to calculate. - Moved sorting functions from `permuta/bisc/perm_properties.py` to `permuta/patterns/perm.py`. + - If you pass an iterable (that is not a perm) to a contains method, then it will now raise an error. + These should be passed with the splat '*'. ## 2.0.3 - 2021-04-28 ### Added diff --git a/permuta/bisc/bisc.py b/permuta/bisc/bisc.py index 9ecc5c3..29bb2e3 100644 --- a/permuta/bisc/bisc.py +++ b/permuta/bisc/bisc.py @@ -19,7 +19,6 @@ def bisc(A, m, n=None, report=False): - if isinstance(A, list): D = defaultdict(list) for perm in A: @@ -56,7 +55,6 @@ def bisc(A, m, n=None, report=False): def auto_bisc(prop): - L = 8 # Want to sanity check on at least S8, and one above n n = 4 m = 2 @@ -274,7 +272,6 @@ def create_bisc_input(N, prop): A, B = {}, {} for n in range(N + 1): - An, Bn = [], [] for perm in Perm.of_length(n): diff --git a/permuta/patterns/meshpatt.py b/permuta/patterns/meshpatt.py index 724872f..a14b93c 100644 --- a/permuta/patterns/meshpatt.py +++ b/permuta/patterns/meshpatt.py @@ -27,7 +27,7 @@ def __init__( and 0 <= coordinate[0] <= len(self.pattern) and 0 <= coordinate[1] <= len(self.pattern) for coordinate in self.shading - ) + ), "shadings should be 2-tuples with integers between 0 and len(pattern)" @classmethod def unrank(cls, pattern: Perm, number: int) -> "MeshPatt": @@ -327,6 +327,11 @@ def add_decrease(self, pos: Tuple[int, int]) -> "MeshPatt": x, y = pos return self.add_point((x, y)).add_point((x + 1, y)) + def _contains(self, patt: Patt) -> bool: + if isinstance(patt, Patt): + return any(True for _ in patt.occurrences_in(self)) + raise TypeError("patt must be a Patt") + def contains(self, *patts: Patt) -> bool: """Check if self contains all provided patterns. @@ -336,7 +341,7 @@ def contains(self, *patts: Patt) -> bool: >>> MeshPatt(Perm((0,)), [(0, 1)]).contains(MeshPatt(Perm((0,)), [])) True """ - return all(patt in self for patt in patts) + return all(self._contains(patt) for patt in patts) def avoids(self, *patts: Patt) -> bool: """Check if self avoids all provided patterns. @@ -351,7 +356,7 @@ def avoids(self, *patts: Patt) -> bool: >>> MeshPatt(Perm((0,)), [(0, 1)]).avoids(MeshPatt(Perm((0,)), [])) False """ - return all(patt not in self for patt in patts) + return all(not self._contains(patt) for patt in patts) def occurrences_in(self, patt: Patt, *args, **kwargs) -> Iterator[Tuple[int, ...]]: """ @@ -689,7 +694,7 @@ def rank(self) -> int: '0b1011101001100101' """ n, res = len(self), 0 - for (x, y) in self.shading: + for x, y in self.shading: res |= 1 << (x * (n + 1) + y) return res @@ -845,5 +850,5 @@ def __ge__(self, other: object) -> bool: def __contains__(self, patt: object) -> bool: if isinstance(patt, Patt): - return any(True for _ in patt.occurrences_in(self)) - return False + return self._contains(patt) + raise TypeError("patt must be a Patt") diff --git a/permuta/patterns/patt.py b/permuta/patterns/patt.py index 7796277..d0292e4 100644 --- a/permuta/patterns/patt.py +++ b/permuta/patterns/patt.py @@ -11,11 +11,11 @@ class Patt(abc.ABC): def avoided_by(self, *patts: "Patt") -> bool: """Check if self is avoided by all the provided patterns.""" - return all(self not in patt for patt in patts) + return all(not patt.contains(self) for patt in patts) def contained_in(self, *patts: "Patt") -> bool: """Check if self is a pattern of all the provided patterns.""" - return all(self in patt for patt in patts) + return all(patt.contains(self) for patt in patts) def count_occurrences_in(self, patt: "Patt") -> int: """Count the number of occurrences of self in the pattern.""" @@ -36,5 +36,10 @@ def get_perm(self) -> "Perm": """Get the permutation part of the pattern""" @abc.abstractmethod - def __contains__(self, patt: object) -> bool: + def _contains(self, patt: "Patt") -> bool: """Does pattern contains another?""" + + contains = _contains + + def __contains__(self, patt: "Patt") -> bool: + return self._contains(patt) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 1c24a84..2f5ab7e 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -2496,7 +2496,12 @@ def contains(self, *patts: "Patt") -> bool: >>> Perm((5, 3, 0, 4, 2, 1)).contains(pattern2, pattern3) False """ - return all(patt in self for patt in patts) + return all(self._contains(patt) for patt in patts) + + def _contains(self, patt: "Patt") -> bool: + if isinstance(patt, Patt): + return any(True for _ in patt.occurrences_in(self)) + raise TypeError("patt must be a Patt") def avoids(self, *patts: "Patt") -> bool: """Check if self avoids patts. @@ -2519,7 +2524,7 @@ def avoids(self, *patts: "Patt") -> bool: >>> Perm((5, 3, 0, 4, 2, 1)).avoids(pattern3, pattern4) True """ - return all(patt not in self for patt in patts) + return all(not self._contains(patt) for patt in patts) def avoids_set(self, patts: Iterable["Patt"]) -> bool: """Check if self avoids patts for an iterable of patterns. @@ -3027,5 +3032,5 @@ def __len__(self) -> int: def __contains__(self, patt: object) -> bool: if isinstance(patt, Patt): - return any(True for _ in patt.occurrences_in(self)) - return False + return self._contains(patt) + raise TypeError("patt must be a Patt") diff --git a/pyproject.toml b/pyproject.toml index 01c7757..c459f89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.black] -target-version = ['py37'] +target-version = ['py310'] include = '\.pyi?$' exclude = ''' diff --git a/tox.ini b/tox.ini index db5a6fe..e6940f9 100644 --- a/tox.ini +++ b/tox.ini @@ -6,21 +6,20 @@ [tox] envlist = flake8, mypy, pylint, black - py{37,38,39, 310, 311}, - pypy37 + py{39, 310, 311, 312}, + pypy39 [default] -basepython=python3.8 +basepython=python3.11 [testenv] description = run test basepython = - py37: python3.7 - py38: python3.8 py39: python3.9 py310: python3.10 py311: python3.11 - pypy37: pypy3 + py312: python3.12 + pypy39: pypy3.9 deps = pytest==7.2.0 pytest-timeout==2.1.0