Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-orderly-set for openSUSE:Factory checked in at 2026-04-04 19:07:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-orderly-set (Old) and /work/SRC/openSUSE:Factory/.python-orderly-set.new.21863 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-orderly-set" Sat Apr 4 19:07:29 2026 rev:4 rq:1344503 version:5.5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-orderly-set/python-orderly-set.changes 2025-06-03 17:58:05.400927080 +0200 +++ /work/SRC/openSUSE:Factory/.python-orderly-set.new.21863/python-orderly-set.changes 2026-04-04 19:09:15.069636088 +0200 @@ -1,0 +2,7 @@ +Fri Apr 3 16:57:06 UTC 2026 - Dirk Müller <[email protected]> + +- update to 5.5.0: + * Switching from setup.py to pyproject.toml + * Adding RoughMaxSizeSet + +------------------------------------------------------------------- Old: ---- orderly_set-5.4.1.tar.gz New: ---- orderly_set-5.5.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-orderly-set.spec ++++++ --- /var/tmp/diff_new_pack.aJkeGj/_old 2026-04-04 19:09:17.245725308 +0200 +++ /var/tmp/diff_new_pack.aJkeGj/_new 2026-04-04 19:09:17.281726784 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-orderly-set # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,17 +18,15 @@ %{?sle15_python_module_pythons} Name: python-orderly-set -Version: 5.4.1 +Version: 5.5.0 Release: 0 Summary: Orderly set License: MIT URL: https://github.com/seperman/orderly-set Source: https://files.pythonhosted.org/packages/source/o/orderly-set/orderly_set-%{version}.tar.gz -BuildRequires: %{python_module base >= 3.8} +BuildRequires: %{python_module flit-core} BuildRequires: %{python_module pip} BuildRequires: %{python_module pytest} -BuildRequires: %{python_module setuptools} -BuildRequires: %{python_module wheel} BuildRequires: fdupes BuildRequires: python-rpm-macros BuildArch: noarch ++++++ orderly_set-5.4.1.tar.gz -> orderly_set-5.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.bumpversion.cfg new/orderly_set-5.5.0/.bumpversion.cfg --- old/orderly_set-5.4.1/.bumpversion.cfg 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.bumpversion.cfg 2025-07-10 22:08:59.852169500 +0200 @@ -0,0 +1,11 @@ +[bumpversion] +current_version = 5.5.0 +commit = False +tag = False +tag_name = {new_version} + +[bumpversion:file:pyproject.toml] + +[bumpversion:file:orderly_set/__init__.py] + +[bumpversion:file:README.md] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.codecov.yml new/orderly_set-5.5.0/.codecov.yml --- old/orderly_set-5.4.1/.codecov.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.codecov.yml 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,3 @@ +comment: + layout: "diff" + require_changes: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.coveragerc new/orderly_set-5.5.0/.coveragerc --- old/orderly_set-5.4.1/.coveragerc 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.coveragerc 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,3 @@ +[run] +branch = True +source = orderly_set.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.flake8 new/orderly_set-5.5.0/.flake8 --- old/orderly_set-5.4.1/.flake8 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.flake8 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 100 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.github/FUNDING.yml new/orderly_set-5.5.0/.github/FUNDING.yml --- old/orderly_set-5.4.1/.github/FUNDING.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.github/FUNDING.yml 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,2 @@ +github: [seperman] +ko_fi: seperman diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.github/ISSUE_TEMPLATE/bug_report.md new/orderly_set-5.5.0/.github/ISSUE_TEMPLATE/bug_report.md --- old/orderly_set-5.4.1/.github/ISSUE_TEMPLATE/bug_report.md 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.github/ISSUE_TEMPLATE/bug_report.md 2024-08-29 20:05:38.653357700 +0200 @@ -0,0 +1,26 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**OS, Orderly-set version and Python version (please complete the following information):** + - OS: [e.g. Ubuntu] + - Version [e.g. 20LTS] + - Python Version [e.g. 3.9.12] + - orderly-set Version [e.g. 5.8.0] + +**Additional context** +Add any other context about the problem here. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.github/ISSUE_TEMPLATE/feature_request.md new/orderly_set-5.5.0/.github/ISSUE_TEMPLATE/feature_request.md --- old/orderly_set-5.4.1/.github/ISSUE_TEMPLATE/feature_request.md 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.github/ISSUE_TEMPLATE/feature_request.md 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.github/workflows/main.yaml new/orderly_set-5.5.0/.github/workflows/main.yaml --- old/orderly_set-5.4.1/.github/workflows/main.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.github/workflows/main.yaml 2025-01-31 20:06:18.608871000 +0100 @@ -0,0 +1,55 @@ +name: Unit Tests + +on: + push: + branches: [ "master", "dev" ] + pull_request: + branches: [ "master", "dev" ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13"] + architecture: ["x64"] + steps: + - uses: actions/checkout@v4 + - name: Setup Python ${{ matrix.python-version }} on ${{ matrix.architecture }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.architecture }} + - name: Cache pip + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + - name: Upgrade setuptools + if: matrix.python-version == 3.12 + run: | + # workaround for 3.12, SEE: https://github.com/pypa/setuptools/issues/3661#issuecomment-1813845177 + pip install --upgrade setuptools + - name: Install dependencies + run: pip install -r requirements-dev.txt + - name: Test with pytest and get the coverage + if: matrix.python-version == 3.12 + run: | + pytest --cov-report=xml --cov=orderly_set tests/ + - name: Test with pytest and no coverage report + if: matrix.python-version != 3.12 + run: | + pytest + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + if: matrix.python-version == 3.12 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + file: ./coverage.xml + token: ${{ secrets.CODECOV_TOKEN }} + env_vars: OS,PYTHON + fail_ci_if_error: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.gitignore new/orderly_set-5.5.0/.gitignore --- old/orderly_set-5.4.1/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.gitignore 2025-07-10 21:39:52.053143000 +0200 @@ -0,0 +1,17 @@ +*.pyc +*~ +.DS_Store +.*.swp +*.egg-info +dist/ +.tox/ +.coverage +.pytest_cache +htmlcov +.eggs +.venv +.python-version +build +.idea +coverage.xml +.envrc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.mailmap new/orderly_set-5.5.0/.mailmap --- old/orderly_set-5.4.1/.mailmap 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.mailmap 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,9 @@ +# Elia has used different names and e-mail addresses in the course of this project. Map them all to her current name and e-mail. +Elia Robyn Lake <[email protected]> <[email protected]> +Elia Robyn Lake <[email protected]> <[email protected]> +Elia Robyn Lake <[email protected]> <[email protected]> +Elia Robyn Lake <[email protected]> <[email protected]> +Elia Robyn Lake <[email protected]> <[email protected]> +Elia Robyn Lake <[email protected]> <[email protected]> +Elia Robyn Lake <[email protected]> <[email protected]> + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/.pre-commit-config.yaml new/orderly_set-5.5.0/.pre-commit-config.yaml --- old/orderly_set-5.4.1/.pre-commit-config.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/.pre-commit-config.yaml 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,15 @@ +files: 'orderly_set/' +repos: +- repo: https://github.com/psf/black + rev: 22.3.0 + hooks: + - id: black +- repo: https://github.com/pycqa/flake8 + rev: 5.0.4 + hooks: + - id: flake8 +- repo: https://github.com/pycqa/isort + rev: 5.10.1 + hooks: + - id: isort + args: ["--profile", "black"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/CHANGELOG.md new/orderly_set-5.5.0/CHANGELOG.md --- old/orderly_set-5.4.1/CHANGELOG.md 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/CHANGELOG.md 2025-04-11 20:28:56.551575400 +0200 @@ -0,0 +1,89 @@ +# Changelog + +Significant changes in major and minor releases of this library: + +## Version 5.4.0 (2025) + +- index() is not compatible with pandas anymore. Instead use indexes when you need to get the indexes for multiple items. + +## Version 5.3.2 (2025) + +- Better support for freezing sets. + +## Version 5.3.1 (2025) + +- Additional type hints + +## Version 5.3.0 (2025) + +- Added freeze() to make stable sets immutable + +## Version 5.2.x (2024) + +- Added Sorted Set and Orderly Set + +## Version 5.2 (February 2022) + +- Major refactor +- Added a StableSet implementation, as a base class for OrderedSet. +- Added Many functions to OrderedSet, to be more complete and more compatible with other implementations. + - popitem(last: bool = True), similar to `dict.popitem` (note minor incompatibility with another implementation (`orderedset`) that have the `last` keyword in the `pop` function) + - move_to_end(key), similar to `dict.move_to_end` + - __le__, __lt__, __ge__, __gt__ - to improve subset/superset testing +- Minimum Python version is 3.8 (because __reversed__) +- Fix: OrderedSet.update now raised a TypeError instead of a ValueError when the type of the input is incorrect +- Added many new tests, and all the tests from 2 other implementations. + +## Version 4.1 (January 2022) + +- Packaged using flit. Wheels now exist, and setuptools is no longer required. +- This package now has a typical package structure, instead of being a single module. The code is in `orderly_set/__init__.py` instead of `orderly_set.py`. +- There is an `orderly_set/py.typed` so that type checkers know about the types. +- Use the type aliases `SetLike[T]` and `OrderedSetInitializer[T]` to simplify some types. +- Updated the way overloaded type signatures are written to what MyPy currently expects. +- Minimum Python version is 3.7. + +## Version 4.0 (January 2020) + +- Added type signatures inline to the code, instead of using type stubs. +- Dropped Python 2 support. The minimum supported Python version is 3.5. + +## Version 3.1 (November 2018) + +- `__getitem__` accepts NumPy arrays of indices, and returns a list of elements with those indices. +- Updated in-place operations that took O(N^2) time, such as .difference_update(), to take O(N) time. +- Clarified whether various methods mutate or copy the OrderedSet. +- Added `OrderedSet.get_loc` and `OrderedSet.get_indexer` as aliases for `OrderedSet.index`, for interoperability with `pandas.Index`. +- Added type stubs in a .pyi file. + +## Version 3.0 (June 2018) + +- Implemented the abstract base classes `collections.MutableSet` and `collections.Sequence`. +- Changed the behavior of some methods to follow the MutableSet API. +- Indexing an OrderedSet with `[:]` returns a copy, not the same object. + +## Version 2.0 (December 2015) + +- Tuples are allowable values in the set, and are not treated as "fancy indexing". +- Added `update` and `pop` methods. + +## Version 1.4 (September 2015) + +- Added `discard` and `clear` methods. + +## Version 1.3 (April 2015) + +- Added support for pickling. + +## Version 1.2 (May 2014) + +- First Python 3 support. + +## Version 1.1 (August 2013) + +- Added tests. +- Removed a broken implementation of `discard`. + +## Version 1.0 (August 2012) + +- First release. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/CLAUDE.md new/orderly_set-5.5.0/CLAUDE.md --- old/orderly_set-5.4.1/CLAUDE.md 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/CLAUDE.md 2025-07-10 21:49:55.226135700 +0200 @@ -0,0 +1,91 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is `orderly-set`, a Python package that provides multiple implementations of ordered sets. The package includes five main set implementations: + +- **StableSet**: A dict-based ordered set that maintains insertion order with O(1) operations but O(N) index lookup +- **OrderedSet**: A list-based ordered set with O(1) index lookup but O(N) deletion +- **StableSetEq**: Like StableSet but with different equality semantics (ignores order for equality) +- **OrderlySet**: Keeps order on insertion but loses order on set operations like difference +- **SortedSet**: A set that maintains alphabetical order when displayed or iterated + +## Development Commands + +### Testing +```bash +# Run all tests +pytest + +# Run with coverage +pytest --cov=orderly_set + +# Run specific test file +pytest tests/test_ordered_set_1.py + +# Run doctests (configured in pytest.ini) +pytest --doctest-modules --doctest-glob=README.md +``` + +### Code Quality +```bash +# Format code +black . + +# Type checking +mypy orderly_set/ + +# Lint code +flake8 orderly_set/ +``` + +### Build and Distribution +```bash +# Install in development mode +uv pip install -e ".[coverage,dev,static,test]" +``` + +### Multi-version Testing +```bash +# Test across Python versions +tox +``` + +## Code Architecture + +### Core Module Structure +- `orderly_set/__init__.py`: Package exports +- `orderly_set/sets.py`: Main implementation file containing all set classes +- `orderly_set/py.typed`: Type stub marker + +### Key Implementation Details + +**StableSet** (lines 55-681 in sets.py): +- Uses `dict.fromkeys()` for O(1) operations +- Maintains insertion order via Python 3.7+ dict ordering +- Index lookup requires O(N) iteration through dict keys + +**OrderedSet** (lines 816-1057 in sets.py): +- Uses separate `_items` list and `_map` dict for O(1) index access +- `_map` stores `{item: index}` mappings +- Deletion requires reindexing all subsequent items + +**Type System**: +- Uses generics extensively with `TypeVar("T")` +- Implements `MutableSet[T]` and `Sequence[T]` protocols +- Complex type annotations for set operations and indexing + +### Performance Characteristics +- StableSet: Fast for all operations except index lookup +- OrderedSet: Fast index lookup but slow deletion +- OrderlySet: Optimized for set operations, loses order guarantees +- SortedSet: Maintains sorted order with lazy evaluation + +## Configuration Files + +- `pytest.ini`: Test configuration with doctest support +- `setup.cfg`: Flake8 linting config (max line length 120) +- `tox.ini`: Multi-version testing for Python 3.8-3.10, PyPy3 +- `requirements-dev.txt`: Development dependencies diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/PKG-INFO new/orderly_set-5.5.0/PKG-INFO --- old/orderly_set-5.4.1/PKG-INFO 2025-05-07 00:34:08.253512600 +0200 +++ new/orderly_set-5.5.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +1,10 @@ -Metadata-Version: 2.2 +Metadata-Version: 2.4 Name: orderly-set -Version: 5.4.1 +Version: 5.5.0 Summary: Orderly set -Home-page: https://github.com/seperman/orderly-set -Download-URL: https://github.com/seperman/orderly-set/tarball/master -Author: Seperman -Author-email: [email protected] -License: MIT +Author-email: Seperman <[email protected]> +Requires-Python: >=3.8 +Description-Content-Type: text/markdown Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent Classifier: Topic :: Software Development @@ -18,21 +16,26 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Development Status :: 5 - Production/Stable Classifier: License :: OSI Approved :: MIT License -Requires-Python: >=3.8 -Description-Content-Type: text/markdown -License-File: AUTHORS.md -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: description-content-type -Dynamic: download-url -Dynamic: home-page -Dynamic: license -Dynamic: requires-python -Dynamic: summary +License-File: MIT-LICENSE +Requires-Dist: coverage~=7.6.0 ; extra == "coverage" +Requires-Dist: bump2version~=1.0.0 ; extra == "dev" +Requires-Dist: ipdb~=0.13.0 ; extra == "dev" +Requires-Dist: orjson ; extra == "optimize" +Requires-Dist: flake8~=7.1.0 ; extra == "static" +Requires-Dist: flake8-pyproject~=1.2.3 ; extra == "static" +Requires-Dist: pytest~=8.3.0 ; extra == "test" +Requires-Dist: pytest-benchmark~=5.1.0 ; extra == "test" +Requires-Dist: pytest-cov~=6.0.0 ; extra == "test" +Requires-Dist: python-dotenv~=1.0.0 ; extra == "test" +Project-URL: Download, https://github.com/seperman/orderly-set/tarball/master +Project-URL: Homepage, https://github.com/seperman/orderly-set +Provides-Extra: coverage +Provides-Extra: dev +Provides-Extra: optimize +Provides-Extra: static +Provides-Extra: test -# Orderly Set 5.4.1 +# Orderly Set 5.5.0 Orderly Set is a package containing multiple implementations of Ordered Set. @@ -213,3 +216,4 @@ Its content is a standard Python list instead of a doubly-linked list. This provides O(1) lookups by index at the expense of O(N) deletion, as well as slightly faster iteration. + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/README.md new/orderly_set-5.5.0/README.md --- old/orderly_set-5.4.1/README.md 2025-05-07 00:30:27.000000000 +0200 +++ new/orderly_set-5.5.0/README.md 2025-07-10 22:08:59.852169500 +0200 @@ -1,4 +1,4 @@ -# Orderly Set 5.4.1 +# Orderly Set 5.5.0 Orderly Set is a package containing multiple implementations of Ordered Set. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/benchmarks/ordered_set_benchmark.py new/orderly_set-5.5.0/benchmarks/ordered_set_benchmark.py --- old/orderly_set-5.4.1/benchmarks/ordered_set_benchmark.py 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/benchmarks/ordered_set_benchmark.py 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,128 @@ +def main(): + import timeit + from functools import partial + from random import randint + + from ordered_set import OrderedSet as OS1 + from orderly_set import OrderedSet as OS2 + from orderly_set import StableSet as OS3 + from orderly_set import OrderlySet as OS5 + from orderly_set import SortedSet as OS6 + # from sortedcollections import OrderedSet as OS4 + + item_count = 10_000 + item_range = item_count * 2 + items = [randint(0, item_range) for _ in range(item_count)] + items_b = [randint(0, item_range) for _ in range(item_count)] + + oset1a = OS1(items) + oset2a = OS2(items) + oset1b = OS1(items_b) + oset2b = OS2(items_b) + assert oset1a.difference(oset1b) == oset2a.difference(oset2b) + assert oset1a.intersection(oset1b) == oset2a.intersection(oset2b) + + oset1c = OS1(items) + oset2c = OS2(items) + oset1c.add(item_range + 1) + oset2c.add(item_range + 1) + assert oset1c == oset2c + + for i in range(item_range): + assert (i in oset1a) == (i in oset2a) + if i in oset1a: + assert oset1a.index(i) == oset2a.index(i) + + + def init_set(T, items) -> set: + return T(items) + + + def init_set_list(T, items) -> list: + return list(T(items)) + + + def init_set_d(items) -> dict: + return dict.fromkeys(items) + + + def init_set_d_list(items) -> list: + return list(dict.fromkeys(items)) + + + def update(s: set, items) -> set: + s.update(items) + return s + + def update_and_get_item(set_type: set, items, items_b) -> set: + set_ = set_type(items) + if set_: + set_[0] + set_.update(items_b) + set_[0] + return set_ + + def update_d(s: dict, items) -> dict: + d2 = dict.fromkeys(items) + s.update(d2) + return s + + + def symmetric_diff(s: set, s2: set) -> dict: + return s ^ s2 + + + def diff(s: set, s2: set) -> dict: + return s - s2 + + + orderly_sets_types = [OS1, OS2, OS3, OS5, OS6] # OS4 is too slow + orderly_set_type_names = ['ordered_set.OrderedSet', 'orderly_set.OrderedSet', 'StableSet', 'OrderlySet', 'SortedSet'] # 'sortedcollections.OrderedSet' is too slow + set_types = [set] + orderly_sets_types + set_type_names = ['set'] + orderly_set_type_names + + oss = [init_set(T, items) for T in set_types] + oss_b = [init_set(T, items_b) for T in set_types] + od = init_set_d(items) + + osls = [init_set_list(T, items) for T in set_types[1:-1]] + [init_set_d_list(items)] + for x in osls: + assert osls[0] == x + + osls = [update(init_set(T, items), items_b) for T in orderly_sets_types[:-1]] + [ + update_d(init_set_d(items), items_b) + ] + osls = [list(x) for x in osls] + for x in osls: + assert osls[0] == x + + number = 10000 + repeats = 3 + for i in range(repeats): + print(f"----- series {i} ------") + + # print("-- initialize a set --") + # print(f"Using Python dict time: {timeit.timeit(partial(init_set_d, items),number=number)}") + # for idx, T in zip(set_type_names, set_types): + # print(f"{idx} time: {timeit.timeit(partial(init_set, T, items),number=number)}") + + # print("-- update a set --") + # print(f"Using Python dict: {timeit.timeit(partial(update_d, od, items_b),number=number)}") + # for idx, os in zip(set_type_names, oss): + # print(f"{idx} time: {timeit.timeit(partial(update, os, items_b),number=number)}") + + print("-- update a set and get item --") + for idx, os in zip(orderly_set_type_names, orderly_sets_types): + print(f"{idx} time: {timeit.timeit(partial(update_and_get_item, os, items, items_b),number=number)}") + + print("-- set symmetric difference (xor) --") + for idx, set1, set2 in zip(set_type_names, oss, oss_b): + print(f"{idx} time: {timeit.timeit(partial(symmetric_diff, set1, set2),number=number)}") + + print("-- set difference (-) --") + for idx, set1, set2 in zip(set_type_names, oss, oss_b): + print(f"{idx} time: {timeit.timeit(partial(diff, set1, set2),number=number)}") + + +if __name__ == '__main__': + main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/orderly_set/__init__.py new/orderly_set-5.5.0/orderly_set/__init__.py --- old/orderly_set-5.4.1/orderly_set/__init__.py 2024-08-28 22:10:12.000000000 +0200 +++ new/orderly_set-5.5.0/orderly_set/__init__.py 2025-07-10 22:08:59.850169700 +0200 @@ -1,4 +1,6 @@ -from orderly_set.sets import OrderedSet, StableSet, StableSetEq, OrderlySet, SortedSet # NOQA +__version__ = "5.5.0" + +from orderly_set.sets import OrderedSet, StableSet, StableSetEq, OrderlySet, SortedSet, RoughMaxSizeSet __all__ = [ "OrderedSet", @@ -6,4 +8,5 @@ "StableSetEq", "OrderlySet", "SortedSet", + "RoughMaxSizeSet", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/orderly_set/sets.py new/orderly_set-5.5.0/orderly_set/sets.py --- old/orderly_set-5.4.1/orderly_set/sets.py 2025-05-07 00:30:15.000000000 +0200 +++ new/orderly_set-5.5.0/orderly_set/sets.py 2025-07-10 21:33:31.571799800 +0200 @@ -15,12 +15,17 @@ Union, overload, Hashable, + Deque, + Generic, ) +from collections import deque + SLICE_ALL = slice(None) T = TypeVar("T") S = TypeVar("S", bound="StableSet") +E = TypeVar('E', bound=Hashable) # SetLike[T] is either a set of elements of type T, or a sequence, which # we will convert to a StableSet or to an OrderedSet by adding its elements in order. @@ -1273,3 +1278,61 @@ def isorderedsuperset(self, other: SetLike, non_consecutive: bool = False) -> bool: return StableSet.isorderedsubset(other, self, non_consecutive) + + + +class RoughMaxSizeSet(Generic[E]): + """ + A set-like container with a “soft” maximum size. When size exceeds + max_size + eviction_batch, it evicts oldest items down to max_size. + """ + + def __init__(self, max_size: int, eviction_batch: Optional[int] = None) -> None: + """ + :param max_size: Target size you generally want to stay under. + :param eviction_batch: How many over-max to tolerate before trimming + (defaults to 10% of max_size, minimum 1). + """ + self.max_size: int = max_size + self.eviction_batch: int = eviction_batch or max(max_size // 10, 1) + self._dq: Deque[E] = deque() # Maintain insertion order + self._set: Set[E] = set() # For O(1) membership tests + + def add(self, item: E) -> bool: + """ + Add item if not present. + :returns: True if inserted, False if already there. + """ + if item in self._set: + return False + self._dq.append(item) + self._set.add(item) + if len(self._set) > self.max_size + self.eviction_batch: + self._evict_to_size(self.max_size) + return True + + def _evict_to_size(self, target_size: int) -> None: + """ + Pop oldest items until our set is back down to target_size. + """ + while len(self._set) > target_size: + old: E = self._dq.popleft() + self._set.discard(old) + + def __contains__(self, item: E) -> bool: + return item in self._set + + def __len__(self) -> int: + return len(self._set) + + def __iter__(self) -> Iterator[E]: + """ + Iteration order is arbitrary (follows set iteration), not insertion order. + """ + return iter(self._set) + + def __repr__(self) -> str: + return ( + f"{self.__class__.__name__}(" + f"{list(self._dq)!r}, max_size={self.max_size!r})" + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/orderly_set.egg-info/PKG-INFO new/orderly_set-5.5.0/orderly_set.egg-info/PKG-INFO --- old/orderly_set-5.4.1/orderly_set.egg-info/PKG-INFO 2025-05-07 00:34:08.000000000 +0200 +++ new/orderly_set-5.5.0/orderly_set.egg-info/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,215 +0,0 @@ -Metadata-Version: 2.2 -Name: orderly-set -Version: 5.4.1 -Summary: Orderly set -Home-page: https://github.com/seperman/orderly-set -Download-URL: https://github.com/seperman/orderly-set/tarball/master -Author: Seperman -Author-email: [email protected] -License: MIT -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Topic :: Software Development -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Development Status :: 5 - Production/Stable -Classifier: License :: OSI Approved :: MIT License -Requires-Python: >=3.8 -Description-Content-Type: text/markdown -License-File: AUTHORS.md -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: description-content-type -Dynamic: download-url -Dynamic: home-page -Dynamic: license -Dynamic: requires-python -Dynamic: summary - -# Orderly Set 5.4.1 - -Orderly Set is a package containing multiple implementations of Ordered Set. - - -## OrderlySet - -This implementation keeps the order in all set operations except set difference operations. -As a result, it can do set difference operations much faster than other implementations. Still 2X slower than of Python's built-in set. - - -## StableSet - -A StableSet is a mutable set that remembers its insertion order. -Featuring: Fast O(1) insertion, deletion, iteration and membership testing. -But slow O(N) Index Lookup. - -## StableSetEq - -Same as StableSet but the order of items doesn't matter for equality comparisons. - -## OrderedSet - -An OrderedSet is a mutable data structure that is a hybrid of a list and a set. -It remembers its insertion order so that every entry has an index that can be looked up. -Featuring: O(1) Index lookup, insertion, iteration and membership testing. -But slow O(N) Deletion. - - -## SortedSet - -SortedSet is basically set but when printed, turned into string, or iterated over, returns the items in alphabetical order. - -# Installation - -`pip install orderly-set` - -# Usage examples - -An OrderedSet is created and used like a set: - - >>> from orderly_set import OrderedSet - - >>> letters = OrderedSet('abracadabra') - - >>> letters - OrderedSet(['a', 'b', 'r', 'c', 'd']) - - >>> 'r' in letters - True - -It is efficient to find the index of an entry in an OrderedSet, or find an -entry by its index. To help with this use case, the `.add()` method returns -the index of the added item, whether it was already in the set or not. - - >>> letters.index('r') - 2 - - >>> letters[2] - 'r' - - >>> letters.add('r') - 2 - - >>> letters.add('x') - 5 - -OrderedSets implement the union (`|`), intersection (`&`), and difference (`-`) -operators like sets do. - - >>> letters |= OrderedSet('shazam') - - >>> letters - OrderedSet(['a', 'b', 'r', 'c', 'd', 'x', 's', 'h', 'z', 'm']) - - >>> letters & set('aeiou') - OrderedSet(['a']) - - >>> letters -= 'abcd' - - >>> letters - OrderedSet(['r', 'x', 's', 'h', 'z', 'm']) - -The `__getitem__()` method has been extended to accept any -iterable except a string, returning a list, to perform NumPy-like "fancy -indexing". - - >>> letters = OrderedSet('abracadabra') - - >>> letters[[0, 2, 3]] - ['a', 'r', 'c'] - - >>> letters.indexes(['a', 'r', 'c']) - [0, 2, 3] - -OrderedSet implements `__getstate__` and `__setstate__` so it can be pickled, -and implements the abstract base classes `collections.MutableSet` and -`collections.Sequence`. - -OrderedSet can be used as a generic collection type, similar to the collections -in the `typing` module like List, Dict, and Set. For example, you can annotate -a variable as having the type `OrderedSet[str]` or `OrderedSet[Tuple[int, -str]]`. - - -# Authors - -Please check the [Authors](AUTHORS.md) file. - -# Comparisons - -``` --- initialize a set -- -Using Python dict time: 4.13 -set time: 2.98 -ordered_set.OrderedSet time: 15.77 -orderly_set.OrderedSet time: 15.25 -StableSet time: 4.78 -OrderlySet time: 4.38 -SortedSet time: 3.09 - --- update a set -- -Using Python dict: 6.77 -set time: 2.46 -ordered_set.OrderedSet time: 10.17 -orderly_set.OrderedSet time: 10.06 -StableSet time: 7.16 -OrderlySet time: 6.77 -SortedSet time: 2.46 - --- update a set and get item -- -ordered_set.OrderedSet time: 29.98 -orderly_set.OrderedSet time: 29.57 -StableSet time: 14.31 -OrderlySet time: 14.23 -SortedSet time: 9.03 - --- set symmetric difference (xor) -- -set time: 5.368663903005654 -ordered_set.OrderedSet time: 39.25 -orderly_set.OrderedSet time: 80.31 -StableSet time: 42.81 -OrderlySet time: 11.44 -SortedSet time: 3.87 - --- set difference (-) -- -set time: 3.7398674299911363 -ordered_set.OrderedSet time: 22.39 -orderly_set.OrderedSet time: 38.00 -StableSet time: 22.30 -OrderlySet time: 8.92 -SortedSet time: 3.03 -``` - -Despite what you see in the benchmarks, in DeepDiff OrderlySet performed better than SortedSet. - - -A StableSet is a mutable set that remembers its insertion order. -Featuring: Fast O(1) insertion, deletion, iteration and membership testing. -But slow O(N) Index Lookup. - -An OrderedSet is a mutable data structure that is a hybrid of a list and a set. -It remembers its insertion order so that every entry has an index that can be looked up. -Featuring: O(1) Index lookup, insertion, iteration and membership testing. -But slow O(N) Deletion. - -Both have similar interfaces but differ in respect of their implementation and performance. - -The original implementation of OrderedSet was a [recipe posted to ActiveState -Recipes][recipe] by Raymond Hettiger, released under the MIT license. - -[recipe]: https://code.activestate.com/recipes/576694-orderedset/ - -Hettiger's implementation kept its content in a doubly-linked list referenced by a -dict. As a result, looking up an item by its index was an O(N) operation, while -deletion was O(1). - -This version of OrderedSet makes different trade-offs for the sake of efficient lookups. -Its content is a standard Python list instead of a doubly-linked list. This -provides O(1) lookups by index at the expense of O(N) deletion, as well as -slightly faster iteration. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/orderly_set.egg-info/SOURCES.txt new/orderly_set-5.5.0/orderly_set.egg-info/SOURCES.txt --- old/orderly_set-5.4.1/orderly_set.egg-info/SOURCES.txt 2025-05-07 00:34:08.000000000 +0200 +++ new/orderly_set-5.5.0/orderly_set.egg-info/SOURCES.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,19 +0,0 @@ -AUTHORS.md -MANIFEST.in -MIT-LICENSE -README.md -setup.cfg -setup.py -orderly_set/__init__.py -orderly_set/py.typed -orderly_set/sets.py -orderly_set.egg-info/PKG-INFO -orderly_set.egg-info/SOURCES.txt -orderly_set.egg-info/dependency_links.txt -orderly_set.egg-info/top_level.txt -orderly_set.egg-info/zip-safe -tests/__init__.py -tests/pytest_util.py -tests/test_ordered_set_1.py -tests/test_ordered_set_2.py -tests/test_ordered_set_3.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/orderly_set.egg-info/dependency_links.txt new/orderly_set-5.5.0/orderly_set.egg-info/dependency_links.txt --- old/orderly_set-5.4.1/orderly_set.egg-info/dependency_links.txt 2025-05-07 00:34:08.000000000 +0200 +++ new/orderly_set-5.5.0/orderly_set.egg-info/dependency_links.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/orderly_set.egg-info/top_level.txt new/orderly_set-5.5.0/orderly_set.egg-info/top_level.txt --- old/orderly_set-5.4.1/orderly_set.egg-info/top_level.txt 2025-05-07 00:34:08.000000000 +0200 +++ new/orderly_set-5.5.0/orderly_set.egg-info/top_level.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -orderly_set diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/orderly_set.egg-info/zip-safe new/orderly_set-5.5.0/orderly_set.egg-info/zip-safe --- old/orderly_set-5.4.1/orderly_set.egg-info/zip-safe 2024-08-28 22:12:51.000000000 +0200 +++ new/orderly_set-5.5.0/orderly_set.egg-info/zip-safe 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/pyproject.toml new/orderly_set-5.5.0/pyproject.toml --- old/orderly_set-5.4.1/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/pyproject.toml 2025-07-10 22:08:59.850169700 +0200 @@ -0,0 +1,57 @@ +[build-system] +requires = ["flit_core >=3.2,<4"] +build-backend = "flit_core.buildapi" + +[project] +name = "orderly-set" +version = "5.5.0" +authors = [ + {name = "Seperman", email = "[email protected]"}, +] +description = "Orderly set" +readme = "README.md" +license = {file = "MIT-LICENSE"} +requires-python = ">=3.8" +classifiers = [ + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Topic :: Software Development", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: PyPy", + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: MIT License" +] + +[project.optional-dependencies] +coverage = [ + "coverage~=7.6.0" +] +dev = [ + "bump2version~=1.0.0", + "ipdb~=0.13.0", +] +static = [ + "flake8~=7.1.0", + "flake8-pyproject~=1.2.3", +] +test = [ + "pytest~=8.3.0", + "pytest-benchmark~=5.1.0", + "pytest-cov~=6.0.0", + "python-dotenv~=1.0.0", +] +optimize = [ + "orjson", +] + + +[project.urls] +Homepage = "https://github.com/seperman/orderly-set" +Download = "https://github.com/seperman/orderly-set/tarball/master" + +[tool.flit.module] +name = "orderly_set" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/pytest.ini new/orderly_set-5.5.0/pytest.ini --- old/orderly_set-5.4.1/pytest.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/pytest.ini 2024-06-30 01:37:24.522924700 +0200 @@ -0,0 +1,2 @@ +[pytest] +addopts = --pdbcls=IPython.terminal.debugger:Pdb --doctest-modules --doctest-glob=README.md --doctest-glob=*.py --ignore=setup.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/setup.cfg new/orderly_set-5.5.0/setup.cfg --- old/orderly_set-5.4.1/setup.cfg 2025-05-07 00:34:08.254512800 +0200 +++ new/orderly_set-5.5.0/setup.cfg 1970-01-01 01:00:00.000000000 +0100 @@ -1,21 +0,0 @@ -[bumpversion] -current_version = 5.4.1 -commit = False -tag = False -tag_name = {new_version} - -[flake8] -max-line-length = 120 -builtins = json -statistics = true -ignore = E202 -exclude = ./data,./src,.svn,CVS,.bzr,.hg,.git,__pycache__ - -[bumpversion:file:setup.py] - -[bumpversion:file:README.md] - -[egg_info] -tag_build = -tag_date = 0 - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/setup.py new/orderly_set-5.5.0/setup.py --- old/orderly_set-5.4.1/setup.py 2025-05-07 00:30:27.000000000 +0200 +++ new/orderly_set-5.5.0/setup.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,38 +0,0 @@ -from setuptools import setup - -version = '5.4.1' - - -with open('README.md') as file: - long_description = file.read() - - -setup(name='orderly-set', - version=version, - description='Orderly set', - url='https://github.com/seperman/orderly-set', - download_url='https://github.com/seperman/orderly-set/tarball/master', - author='Seperman', - author_email='[email protected]', - license='MIT', - packages=['orderly_set'], - zip_safe=True, - include_package_data=True, - long_description=long_description, - long_description_content_type='text/markdown', - install_requires=None, - python_requires='>=3.8', - classifiers=[ - "Intended Audience :: Developers", - "Operating System :: OS Independent", - "Topic :: Software Development", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: Implementation :: PyPy", - "Development Status :: 5 - Production/Stable", - "License :: OSI Approved :: MIT License" - ], - ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/tests/test_set_with_max_size.py new/orderly_set-5.5.0/tests/test_set_with_max_size.py --- old/orderly_set-5.4.1/tests/test_set_with_max_size.py 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/tests/test_set_with_max_size.py 2025-07-10 22:02:48.126607000 +0200 @@ -0,0 +1,69 @@ +import pytest +from orderly_set import RoughMaxSizeSet # adjust import path as needed + + [email protected] +def cache(): + # small size for testing + return RoughMaxSizeSet(max_size=5, eviction_batch=2) + +class TestRoughMaxSizeSet: + def test_add_new_item_returns_true(self, cache): + assert cache.add('a') is True + assert 'a' in cache + assert len(cache) == 1 + + def test_add_existing_item_returns_false(self, cache): + cache.add('x') + assert cache.add('x') is False + assert len(cache) == 1 + + def test_no_eviction_below_threshold(self, cache): + # fill up to max_size + batch, but not over + for i in range( cache.max_size + cache.eviction_batch ): + cache.add(i) + assert len(cache) == cache.max_size + cache.eviction_batch + + def test_eviction_when_exceeding_threshold(self, cache): + # add one more than threshold + total = cache.max_size + cache.eviction_batch + 1 + for i in range(total): + cache.add(i) + # should trim back to max_size + assert len(cache) == cache.max_size + # oldest should be gone + assert 0 not in cache + # newest max_size items should remain + remaining = set(list(range(total))[ -cache.max_size : ]) # last max_size integers + assert set(cache) == remaining + + def test_len_and_iteration(self, cache): + items = ['a', 'b', 'c'] + for x in items: + cache.add(x) + assert len(cache) == len(items) + assert set(cache) == set(items) + + def test_repr_shows_order_and_size(self, cache): + for x in ['x', 'y', 'z']: + cache.add(x) + rep = repr(cache) + assert "['x', 'y', 'z']" in rep + assert f"max_size={cache.max_size}" in rep + + def test_custom_eviction_batch(self): + custom = RoughMaxSizeSet(max_size=3, eviction_batch=1) + for i in [10, 20, 30, 40]: + custom.add(i) + # size stays at 4 (max_size + eviction_batch), no eviction yet + assert len(custom) == 4 + assert 10 in custom + + def test_reinsertion_of_evicted_item(self, cache): + # force eviction + for i in range(cache.max_size + cache.eviction_batch + 1): + cache.add(i) + # 0 was evicted; re-adding should work + assert cache.add(0) is True + assert 0 in cache + assert len(cache) == cache.max_size + 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/orderly_set-5.4.1/tox.ini new/orderly_set-5.5.0/tox.ini --- old/orderly_set-5.4.1/tox.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/orderly_set-5.5.0/tox.ini 2024-06-30 01:37:24.523924600 +0200 @@ -0,0 +1,6 @@ +[tox] +envlist = pypy3, py38, py39, py310 + +[testenv] +deps = pytest +commands = pytest
