Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:bmwiedemann:reproducible:distribution:ring1
python-rpds-py
rpds.py-0.7.1.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File rpds.py-0.7.1.obscpio of Package python-rpds-py
07070100000000000041ED0000000000000000000000036418B31700000000000000000000000000000000000000000000001600000000rpds.py-0.7.1/.github07070100000001000081A40000000000000000000000016418B317000000D0000000000000000000000000000000000000002500000000rpds.py-0.7.1/.github/dependabot.ymlversion: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" - package-ecosystem: "cargo" directory: "/" schedule: interval: "weekly" 07070100000002000041ED0000000000000000000000026418B31700000000000000000000000000000000000000000000002000000000rpds.py-0.7.1/.github/workflows07070100000003000081A40000000000000000000000016418B3170000103F000000000000000000000000000000000000002700000000rpds.py-0.7.1/.github/workflows/CI.ymlname: CI on: push: branches: - main tags: - "v[0-9].*" pull_request: release: types: [published] schedule: # Daily at 5:33 - cron: "33 5 * * *" workflow_dispatch: permissions: contents: write jobs: pre-commit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: "3.x" - uses: pre-commit/action@v3.0.0 list: runs-on: ubuntu-latest outputs: noxenvs: ${{ steps.noxenvs-matrix.outputs.noxenvs }} steps: - uses: actions/checkout@v3 - name: Set up nox uses: wntrblm/nox@2022.11.21 - id: noxenvs-matrix run: | echo >>$GITHUB_OUTPUT noxenvs=$( nox --list-sessions | grep '^* ' | cut -d ' ' -f 2- | jq --raw-input --slurp 'split("\n") | map(select(. != ""))' ) test: needs: list runs-on: ubuntu-latest strategy: fail-fast: false matrix: noxenv: ${{ fromJson(needs.list.outputs.noxenvs) }} steps: - uses: actions/checkout@v3 - name: Install dependencies run: sudo apt-get update && sudo apt-get install -y libenchant-2-dev if: runner.os == 'Linux' && startsWith(matrix.noxenv, 'docs') - name: Install dependencies run: brew install enchant if: runner.os == 'macOS' && startsWith(matrix.noxenv, 'docs') - name: Set up Python uses: actions/setup-python@v4 with: python-version: "3.x" - name: Set up nox uses: wntrblm/nox@2022.11.21 - name: Run nox run: nox -s "${{ matrix.noxenv }}" linux: needs: test runs-on: ubuntu-latest strategy: matrix: target: [x86_64, x86, aarch64, armv7, s390x, ppc64le] steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: "3.x" - name: Build wheels uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} args: --release --out dist --interpreter '3.8 3.9 3.10 3.11 pypy3.8 pypy3.9' manylinux: auto - name: Upload wheels uses: actions/upload-artifact@v3 with: name: wheels path: dist windows: needs: test runs-on: windows-latest strategy: matrix: target: [x64, x86] steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: "3.x" architecture: ${{ matrix.target }} - name: Build wheels uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} args: --release --out dist --find-interpreter --sdist - name: Upload wheels uses: actions/upload-artifact@v3 with: name: wheels path: dist macos: needs: test runs-on: macos-latest strategy: matrix: target: [x86_64, aarch64] steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: "3.x" - name: Build wheels uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} args: --release --out dist --find-interpreter - name: Upload wheels uses: actions/upload-artifact@v3 with: name: wheels path: dist release: name: Release runs-on: ubuntu-latest if: "startsWith(github.ref, 'refs/tags/')" needs: [linux, windows, macos] steps: - uses: actions/download-artifact@v3 with: name: wheels - name: Publish to PyPI uses: PyO3/maturin-action@v1 env: MATURIN_PYPI_TOKEN: ${{ secrets.pypi_password }} with: command: upload args: --skip-existing * - name: Create a GitHub Release if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') uses: softprops/action-gh-release@v1 with: files: | * generate_release_notes: true 07070100000004000081A40000000000000000000000016418B317000002AE000000000000000000000000000000000000001900000000rpds.py-0.7.1/.gitignore/target # Byte-compiled / optimized / DLL files __pycache__/ .pytest_cache/ *.py[cod] # C extensions *.so # Distribution / packaging .Python .venv/ env/ bin/ build/ develop-eggs/ dist/ eggs/ lib/ lib64/ parts/ sdist/ var/ include/ man/ venv/ *.egg-info/ .installed.cfg *.egg # Installer logs pip-log.txt pip-delete-this-directory.txt pip-selfcheck.json # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache nosetests.xml coverage.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # Rope .ropeproject # Django stuff: *.log *.pot .DS_Store # Sphinx documentation docs/_build/ # PyCharm .idea/ # VSCode .vscode/ # Pyenv .python-version 07070100000005000081A40000000000000000000000016418B317000003E7000000000000000000000000000000000000002600000000rpds.py-0.7.1/.pre-commit-config.yamlrepos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: check-ast - id: check-docstring-first - id: check-toml - id: check-vcs-permalinks - id: check-yaml - id: debug-statements - id: end-of-file-fixer - id: mixed-line-ending args: [--fix, lf] - id: trailing-whitespace - repo: https://github.com/doublify/pre-commit-rust rev: "v1.0" hooks: - id: fmt - repo: https://github.com/PyCQA/isort rev: 5.12.0 hooks: - id: isort - repo: https://github.com/pycqa/flake8 rev: "6.0.0" hooks: - id: flake8 - repo: https://github.com/asottile/pyupgrade rev: v3.3.1 hooks: - id: pyupgrade - repo: https://github.com/psf/black rev: 23.1.0 hooks: - name: black id: black args: ["--line-length", "79"] - repo: https://github.com/pre-commit/mirrors-prettier rev: "v3.0.0-alpha.4" hooks: - id: prettier 07070100000006000081A40000000000000000000000016418B31700002085000000000000000000000000000000000000001900000000rpds.py-0.7.1/Cargo.lock# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "archery" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6cd774058b1b415c4855d8b86436c04bf050c003156fe24bc326fb3fe75c343" dependencies = [ "static_assertions", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "indoc" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "libc" version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "lock_api" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "memoffset" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-sys", ] [[package]] name = "proc-macro2" version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06a3d8e8a46ab2738109347433cb7b96dffda2e4a218b03ef27090238886b147" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", "parking_lot", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", "unindent", ] [[package]] name = "pyo3-build-config" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d" dependencies = [ "once_cell", "target-lexicon", ] [[package]] name = "pyo3-ffi" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "839526a5c07a17ff44823679b68add4a58004de00512a95b6c1c98a6dcac0ee5" dependencies = [ "libc", "pyo3-build-config", ] [[package]] name = "pyo3-macros" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd44cf207476c6a9760c4653559be4f206efafb924d3e4cbf2721475fc0d6cc5" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", "syn", ] [[package]] name = "pyo3-macros-backend" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1f43d8e30460f36350d18631ccf85ded64c059829208fe680904c65bcd0a4c" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "quote" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] name = "rpds" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd6ce569b15c331b1e5fd8cf6adb0bf240678b5f0cdc4d0f41e11683f6feba9" dependencies = [ "archery", ] [[package]] name = "rpds-py" version = "0.7.1" dependencies = [ "archery", "pyo3", "rpds", ] [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "smallvec" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "target-lexicon" version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "unicode-ident" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unindent" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" [[package]] name = "windows-sys" version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" 07070100000007000081A40000000000000000000000016418B317000000DE000000000000000000000000000000000000001900000000rpds.py-0.7.1/Cargo.toml[package] name = "rpds-py" version = "0.7.1" edition = "2021" [lib] name = "rpds" crate-type = ["cdylib"] [dependencies] rpds = "0.13.0" archery = "0.5.0" [dependencies.pyo3] version = "0.18.1" features = ["abi3-py38"] 07070100000008000081A40000000000000000000000016418B31700000421000000000000000000000000000000000000001600000000rpds.py-0.7.1/LICENSECopyright (c) 2023 Julian Berman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 07070100000009000081A40000000000000000000000016418B3170000069E000000000000000000000000000000000000001900000000rpds.py-0.7.1/README.rst=========== ``rpds.py`` =========== |PyPI| |Pythons| |CI| .. |PyPI| image:: https://img.shields.io/pypi/v/rpds-py.svg :alt: PyPI version :target: https://pypi.org/project/rpds-py/ .. |Pythons| image:: https://img.shields.io/pypi/pyversions/rpds-py.svg :alt: Supported Python versions :target: https://pypi.org/project/rpds-py/ .. |CI| image:: https://github.com/Julian/rpds.py/workflows/CI/badge.svg :alt: Build status :target: https://github.com/Julian/rpds.py/actions?query=workflow%3ACI Python bindings to the Rust ``rpds`` crate. What's here is quite minimal (in transparency, it was written initially to support replacing ``pyrsistent`` in the `referencing library <https://github.com/python-jsonschema/referencing>`_). If you see something missing (which is very likely), a PR is definitely welcome to add it. Methods in general are named similarly to their ``rpds`` counterparts (rather than ``pyrsistent``\ 's conventions, though probably a full drop-in ``pyrsistent``\ -compatible wrapper module is a good addition at some point). .. code:: python >>> from rpds import HashTrieMap, HashTrieSet, List >>> m = HashTrieMap({"foo": "bar", "baz": "quux"}) >>> m.insert("spam", 37) == HashTrieMap({"foo": "bar", "baz": "quux", "spam": 37}) True >>> m.remove("foo") == HashTrieMap({"baz": "quux"}) True >>> s = HashTrieSet({"foo", "bar", "baz", "quux"}) >>> s.insert("spam") == HashTrieSet({"foo", "bar", "baz", "quux", "spam"}) True >>> s.remove("foo") == HashTrieSet({"bar", "baz", "quux"}) True >>> L = List([1, 3, 5]) >>> L.push_front(-1) == List([-1, 1, 3, 5]) True >>> L.rest == List([3, 5]) True 0707010000000A000081A40000000000000000000000016418B317000003ED000000000000000000000000000000000000001900000000rpds.py-0.7.1/noxfile.pyfrom pathlib import Path import nox ROOT = Path(__file__).parent TESTS = ROOT / "tests" PYPROJECT = ROOT / "pyproject.toml" nox.options.sessions = [] def session(default=True, **kwargs): def _session(fn): if default: nox.options.sessions.append(kwargs.get("name", fn.__name__)) return nox.session(**kwargs)(fn) return _session @session(python=["3.8", "3.9", "3.10", "3.11", "pypy3"]) def tests(session): session.install(ROOT, "-r", TESTS / "requirements.txt") if session.posargs == ["coverage"]: session.install("coverage[toml]") session.run("coverage", "run", "-m", "pytest") session.run("coverage", "report") else: session.run("pytest", *session.posargs, TESTS) @session(tags=["style"]) def readme(session): session.install("build", "twine") tmpdir = session.create_tmp() session.run("python", "-m", "build", ROOT, "--outdir", tmpdir) session.run("python", "-m", "twine", "check", tmpdir + "/*") 0707010000000B000081A40000000000000000000000016418B31700000442000000000000000000000000000000000000001D00000000rpds.py-0.7.1/pyproject.toml[build-system] requires = ["maturin>=0.14,<0.15"] build-backend = "maturin" [project] name = "rpds-py" description = "Python bindings to Rust's persistent data structures (rpds)" readme = "README.rst" license = {text = "MIT"} requires-python = ">=3.8" keywords = ["data structures", "rust", "persistent"] authors = [ {email = "Julian+rpds@GrayVines.com"}, {name = "Julian Berman"}, ] classifiers = [ "Development Status :: 3 - Alpha", "Operating System :: OS Independent", "Programming Language :: Rust", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ] dynamic = ["version"] [tool.isort] combine_as_imports = true from_first = true include_trailing_comma = true multi_line_output = 3 [tool.maturin] features = ["pyo3/extension-module"] 0707010000000C000081A40000000000000000000000016418B3170000066E000000000000000000000000000000000000001700000000rpds.py-0.7.1/rpds.pyifrom typing import ( FrozenSet, ItemsView, Iterable, Iterator, KeysView, Mapping, TypeVar, ValuesView, ) T = TypeVar("T") KT = TypeVar("KT", covariant=True) VT = TypeVar("VT", covariant=True) class HashTrieMap(Mapping[KT, VT]): def __init__( self, value: Mapping[KT, VT] | Iterable[tuple[KT, VT]] = {}, **kwds: Mapping[KT, VT], ): ... def __getitem__(self, key: KT) -> VT: ... def __iter__(self) -> Iterator[KT]: ... def __len__(self) -> int: ... def discard(self, key: KT) -> "HashTrieMap[KT, VT]": ... def items(self) -> ItemsView[KT, VT]: ... def keys(self) -> KeysView[KT]: ... def values(self) -> ValuesView[VT]: ... def remove(self, key: KT) -> "HashTrieMap[KT, VT]": ... def insert(self, key: KT, val: VT) -> "HashTrieMap[KT, VT]": ... def update(self, *args: Mapping): ... @classmethod def convert( cls, value: Mapping[KT, VT] | Iterable[tuple[KT, VT]], ) -> "HashTrieMap[KT, VT]": ... class HashTrieSet(FrozenSet[T]): def __init__(self, value: Iterable[T] = ()): ... def __iter__(self) -> Iterator[T]: ... def __len__(self) -> int: ... def discard(self, value: T) -> "HashTrieSet[T]": ... def remove(self, value: T) -> "HashTrieSet[T]": ... def insert(self, value: T) -> "HashTrieSet[T]": ... def update(self, *args: Iterable[T]) -> "HashTrieSet[T]": ... class List(Iterable[T]): def __init__(self, value: Iterable[T] = (), *more: T): ... def __iter__(self) -> Iterator[T]: ... def __len__(self) -> int: ... def push_front(self, value: T) -> "List[T]": ... 0707010000000D000041ED0000000000000000000000026418B31700000000000000000000000000000000000000000000001200000000rpds.py-0.7.1/src0707010000000E000081A40000000000000000000000016418B31700004257000000000000000000000000000000000000001900000000rpds.py-0.7.1/src/lib.rsuse std::hash::{Hash, Hasher}; use std::vec::IntoIter; use pyo3::exceptions::PyIndexError; use pyo3::pyclass::CompareOp; use pyo3::types::{PyDict, PyIterator, PyTuple, PyType}; use pyo3::{exceptions::PyKeyError, types::PyMapping}; use pyo3::{prelude::*, AsPyPointer}; use rpds::{HashTrieMap, HashTrieMapSync, HashTrieSet, HashTrieSetSync, List, ListSync}; #[derive(Clone, Debug)] struct Key { hash: isize, inner: PyObject, } impl Hash for Key { fn hash<H: Hasher>(&self, state: &mut H) { state.write_isize(self.hash); } } impl Eq for Key {} impl PartialEq for Key { fn eq(&self, other: &Self) -> bool { Python::with_gil(|py| { self.inner .call_method1(py, "__eq__", (&other.inner,)) .and_then(|value| value.extract(py)) .expect("__eq__ failed!") }) } } impl IntoPy<PyObject> for Key { fn into_py(self, py: Python<'_>) -> PyObject { self.inner.into_py(py) } } impl AsPyPointer for Key { fn as_ptr(&self) -> *mut pyo3::ffi::PyObject { self.inner.as_ptr() } } impl<'source> FromPyObject<'source> for Key { fn extract(ob: &'source PyAny) -> PyResult<Self> { Ok(Key { hash: ob.hash()?, inner: ob.into(), }) } } #[repr(transparent)] #[pyclass(name = "HashTrieMap", module = "rpds", frozen, mapping)] struct HashTrieMapPy { inner: HashTrieMapSync<Key, PyObject>, } impl From<HashTrieMapSync<Key, PyObject>> for HashTrieMapPy { fn from(map: HashTrieMapSync<Key, PyObject>) -> Self { HashTrieMapPy { inner: map } } } impl<'source> FromPyObject<'source> for HashTrieMapPy { fn extract(ob: &'source PyAny) -> PyResult<Self> { let mut ret = HashTrieMap::new_sync(); if let Ok(mapping) = ob.downcast::<PyMapping>() { for each in mapping.items()?.iter()? { let (k, v): (Key, PyObject) = each?.extract()?; ret.insert_mut(k, v); } } else { for each in ob.iter()? { let (k, v): (Key, PyObject) = each?.extract()?; ret.insert_mut(k, v); } } Ok(HashTrieMapPy { inner: ret }) } } #[pymethods] impl HashTrieMapPy { #[new] #[pyo3(signature = (value=None, **kwds))] fn init(value: Option<HashTrieMapPy>, kwds: Option<&PyDict>) -> PyResult<Self> { let mut map: HashTrieMapPy; if let Some(value) = value { map = value; } else { map = HashTrieMapPy { inner: HashTrieMap::new_sync(), }; } if let Some(kwds) = kwds { for (k, v) in kwds { map.inner.insert_mut(Key::extract(k)?, v.into()); } } Ok(map) } fn __contains__(&self, key: Key) -> bool { self.inner.contains_key(&key) } fn __iter__(slf: PyRef<'_, Self>) -> PyResult<Py<KeyIterator>> { Py::new( slf.py(), KeyIterator { inner: slf.keys().into_iter(), }, ) } fn __getitem__(&self, key: Key) -> PyResult<PyObject> { match self.inner.get(&key) { Some(value) => Ok(value.to_owned()), None => Err(PyKeyError::new_err(key)), } } fn __len__(&self) -> usize { self.inner.size().into() } fn __repr__(&self, py: Python) -> String { let contents = self.inner.into_iter().map(|(k, v)| { format!( "{}: {}", k.into_py(py), v.call_method0(py, "__repr__") .and_then(|r| r.extract(py)) .unwrap_or("<repr error>".to_owned()) ) }); format!( "HashTrieMap({{{}}})", contents.collect::<Vec<_>>().join(", ") ) } fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> PyResult<PyObject> { match op { CompareOp::Eq => Ok((self.inner.size() == other.inner.size() && self .inner .iter() .map(|(k1, v1)| (v1, other.inner.get(&k1))) .map(|(v1, v2)| PyAny::eq(v1.extract(py)?, v2)) .all(|r| r.unwrap_or(false))) .into_py(py)), CompareOp::Ne => Ok((self.inner.size() != other.inner.size() || self .inner .iter() .map(|(k1, v1)| (v1, other.inner.get(&k1))) .map(|(v1, v2)| PyAny::ne(v1.extract(py)?, v2)) .all(|r| r.unwrap_or(true))) .into_py(py)), _ => Ok(py.NotImplemented()), } } #[classmethod] fn convert(_cls: &PyType, value: &PyAny, py: Python) -> PyResult<PyObject> { if value.is_instance_of::<HashTrieMapPy>()? { Ok(value.into()) } else { Ok(HashTrieMapPy::extract(value)?.into_py(py)) } } fn get(&self, key: Key) -> Option<&PyObject> { self.inner.get(&key) } fn keys(&self) -> Vec<Key> { self.inner.keys().map(|key| key.clone()).collect() } fn values(&self) -> Vec<&PyObject> { self.inner.values().collect::<Vec<&PyObject>>().to_owned() } fn items(&self) -> Vec<(&Key, &PyObject)> { self.inner .iter() .collect::<Vec<(&Key, &PyObject)>>() .to_owned() } fn discard(&self, key: Key) -> PyResult<HashTrieMapPy> { match self.inner.contains_key(&key) { true => Ok(HashTrieMapPy { inner: self.inner.remove(&key), }), false => Ok(HashTrieMapPy { inner: self.inner.clone(), }), } } fn insert(&self, key: Key, value: &PyAny) -> HashTrieMapPy { HashTrieMapPy { inner: self.inner.insert(Key::from(key), value.into()), } } fn remove(&self, key: Key) -> PyResult<HashTrieMapPy> { match self.inner.contains_key(&key) { true => Ok(HashTrieMapPy { inner: self.inner.remove(&key), }), false => Err(PyKeyError::new_err(key)), } } #[pyo3(signature = (*maps, **kwds))] fn update(&self, maps: &PyTuple, kwds: Option<&PyDict>) -> PyResult<HashTrieMapPy> { let mut inner = self.inner.clone(); for value in maps { let map = HashTrieMapPy::extract(value)?; for (k, v) in &map.inner { inner.insert_mut(k.to_owned(), v.to_owned()); } } if let Some(kwds) = kwds { for (k, v) in kwds { inner.insert_mut(Key::extract(k)?, v.extract()?); } } Ok(HashTrieMapPy { inner }) } } #[pyclass(module = "rpds")] struct KeyIterator { inner: IntoIter<Key>, } #[pymethods] impl KeyIterator { fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { slf } fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<Key> { slf.inner.next() } } #[repr(transparent)] #[pyclass(name = "HashTrieSet", module = "rpds", frozen)] struct HashTrieSetPy { inner: HashTrieSetSync<Key>, } impl<'source> FromPyObject<'source> for HashTrieSetPy { fn extract(ob: &'source PyAny) -> PyResult<Self> { let mut ret = HashTrieSet::new_sync(); for each in ob.iter()? { let k: Key = each?.extract()?; ret.insert_mut(k); } Ok(HashTrieSetPy { inner: ret }) } } fn is_subset(one: &HashTrieSetSync<Key>, two: &HashTrieSetSync<Key>) -> bool { one.iter().all(|v| two.contains(v)) } #[pymethods] impl HashTrieSetPy { #[new] fn init(value: Option<HashTrieSetPy>) -> Self { if let Some(value) = value { value } else { HashTrieSetPy { inner: HashTrieSet::new_sync(), } } } fn __and__(&self, other: &Self) -> Self { self.intersection(&other) } fn __or__(&self, other: &Self) -> Self { self.union(&other) } fn __sub__(&self, other: &Self) -> Self { self.difference(&other) } fn __xor__(&self, other: &Self) -> Self { self.symmetric_difference(&other) } fn __iter__(slf: PyRef<'_, Self>) -> PyResult<Py<KeyIterator>> { let iter = slf .inner .iter() .map(|k| k.to_owned()) .collect::<Vec<_>>() .into_iter(); Py::new(slf.py(), KeyIterator { inner: iter }) } fn __len__(&self) -> usize { self.inner.size().into() } fn __repr__(&self, py: Python) -> String { let contents = self.inner.into_iter().map(|k| { k.into_py(py) .call_method0(py, "__repr__") .and_then(|r| r.extract(py)) .unwrap_or("<repr failed>".to_owned()) }); format!( "HashTrieSet({{{}}})", contents.collect::<Vec<_>>().join(", ") ) } fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> PyResult<PyObject> { match op { CompareOp::Eq => Ok((self.inner.size() == other.inner.size() && is_subset(&self.inner, &other.inner)) .into_py(py)), CompareOp::Ne => Ok((self.inner.size() != other.inner.size() || self.inner.iter().any(|k| !other.inner.contains(k))) .into_py(py)), CompareOp::Lt => Ok((self.inner.size() < other.inner.size() && is_subset(&self.inner, &other.inner)) .into_py(py)), CompareOp::Le => Ok(is_subset(&self.inner, &other.inner).into_py(py)), _ => Ok(py.NotImplemented()), } } fn insert(&self, value: Key) -> HashTrieSetPy { HashTrieSetPy { inner: self.inner.insert(Key::from(value)), } } fn discard(&self, value: Key) -> PyResult<HashTrieSetPy> { match self.inner.contains(&value) { true => Ok(HashTrieSetPy { inner: self.inner.remove(&value), }), false => Ok(HashTrieSetPy { inner: self.inner.clone(), }), } } fn remove(&self, value: Key) -> PyResult<HashTrieSetPy> { match self.inner.contains(&value) { true => Ok(HashTrieSetPy { inner: self.inner.remove(&value), }), false => Err(PyKeyError::new_err(value)), } } fn difference(&self, other: &Self) -> HashTrieSetPy { let mut inner = self.inner.clone(); for value in other.inner.iter() { inner.remove_mut(value); } HashTrieSetPy { inner } } fn intersection(&self, other: &Self) -> HashTrieSetPy { let mut inner: HashTrieSetSync<Key> = HashTrieSet::new_sync(); let larger: &HashTrieSetSync<Key>; let iter; if self.inner.size() > other.inner.size() { larger = &self.inner; iter = other.inner.iter(); } else { larger = &other.inner; iter = self.inner.iter(); } for value in iter { if larger.contains(value) { inner.insert_mut(value.to_owned()); } } HashTrieSetPy { inner } } fn symmetric_difference(&self, other: &Self) -> HashTrieSetPy { let mut inner: HashTrieSetSync<Key>; let iter; if self.inner.size() > other.inner.size() { inner = self.inner.clone(); iter = other.inner.iter(); } else { inner = other.inner.clone(); iter = self.inner.iter(); } for value in iter { if inner.contains(value) { inner.remove_mut(value); } else { inner.insert_mut(value.to_owned()); } } HashTrieSetPy { inner } } fn union(&self, other: &Self) -> HashTrieSetPy { let mut inner: HashTrieSetSync<Key>; let iter; if self.inner.size() > other.inner.size() { inner = self.inner.clone(); iter = other.inner.iter(); } else { inner = other.inner.clone(); iter = self.inner.iter(); } for value in iter { inner.insert_mut(value.to_owned()); } HashTrieSetPy { inner } } #[pyo3(signature = (*iterables))] fn update(&self, iterables: &PyTuple) -> PyResult<HashTrieSetPy> { let mut inner = self.inner.clone(); for each in iterables { let iter = each.iter()?; for value in iter { inner.insert_mut(Key::extract(value?)?.to_owned()); } } Ok(HashTrieSetPy { inner }) } } #[repr(transparent)] #[pyclass(name = "List", module = "rpds", frozen, sequence)] struct ListPy { inner: ListSync<PyObject>, } impl From<ListSync<PyObject>> for ListPy { fn from(elements: ListSync<PyObject>) -> Self { ListPy { inner: elements } } } impl<'source> FromPyObject<'source> for ListPy { fn extract(ob: &'source PyAny) -> PyResult<Self> { let mut ret = List::new_sync(); let reversed = PyModule::import(ob.py(), "builtins")?.getattr("reversed")?; let rob: &PyIterator = reversed.call1((ob,))?.iter()?; for each in rob { ret.push_front_mut(each?.extract()?); } Ok(ListPy { inner: ret }) } } #[pymethods] impl ListPy { #[new] #[pyo3(signature = (*elements))] fn init(elements: &PyTuple) -> PyResult<Self> { let mut ret: ListPy; if elements.len() == 1 { ret = elements.get_item(0)?.extract()?; } else { ret = ListPy { inner: List::new_sync(), }; if elements.len() > 1 { for each in (0..elements.len()).rev() { ret.inner .push_front_mut(elements.get_item(each)?.extract()?); } } } Ok(ret) } fn __len__(&self) -> usize { self.inner.len() } fn __repr__(&self, py: Python) -> String { let contents = self.inner.into_iter().map(|k| { k.into_py(py) .call_method0(py, "__repr__") .and_then(|r| r.extract(py)) .unwrap_or("<repr failed>".to_owned()) }); format!("List([{}])", contents.collect::<Vec<_>>().join(", ")) } fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> PyResult<PyObject> { match op { CompareOp::Eq => Ok((self.inner.len() == other.inner.len() && self .inner .iter() .zip(other.inner.iter()) .map(|(e1, e2)| PyAny::eq(e1.extract(py)?, e2)) .all(|r| r.unwrap_or(false))) .into_py(py)), CompareOp::Ne => Ok((self.inner.len() != other.inner.len() || self .inner .iter() .zip(other.inner.iter()) .map(|(e1, e2)| PyAny::ne(e1.extract(py)?, e2)) .any(|r| r.unwrap_or(true))) .into_py(py)), _ => Ok(py.NotImplemented()), } } fn __iter__(slf: PyRef<'_, Self>) -> PyResult<Py<ListIterator>> { let iter = slf .inner .iter() .map(|k| k.to_owned()) .collect::<Vec<_>>() .into_iter(); Py::new(slf.py(), ListIterator { inner: iter }) } fn __reversed__(&self) -> ListPy { ListPy { inner: self.inner.reverse(), } } #[getter] fn first(&self) -> PyResult<&PyObject> { self.inner .first() .ok_or_else(|| PyIndexError::new_err("empty list has no first element")) } fn push_front(&self, other: PyObject) -> ListPy { ListPy { inner: self.inner.push_front(other), } } #[getter] fn rest(&self) -> ListPy { let mut inner = self.inner.clone(); inner.drop_first_mut(); ListPy { inner } } } #[pyclass(module = "rpds")] struct ListIterator { inner: IntoIter<PyObject>, } #[pymethods] impl ListIterator { fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { slf } fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<PyObject> { slf.inner.next() } } #[pymodule] #[pyo3(name = "rpds")] fn rpds_py(py: Python, m: &PyModule) -> PyResult<()> { m.add_class::<HashTrieMapPy>()?; PyMapping::register::<HashTrieMapPy>(py)?; m.add_class::<HashTrieSetPy>()?; m.add_class::<ListPy>()?; Ok(()) } 0707010000000F000041ED0000000000000000000000026418B31700000000000000000000000000000000000000000000001400000000rpds.py-0.7.1/tests07070100000010000081A40000000000000000000000016418B31700000012000000000000000000000000000000000000002400000000rpds.py-0.7.1/tests/requirements.inhypothesis pytest 07070100000011000081A40000000000000000000000016418B317000001CE000000000000000000000000000000000000002500000000rpds.py-0.7.1/tests/requirements.txt# # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # pip-compile --resolver=backtracking tests/requirements.in # attrs==22.2.0 # via # hypothesis # pytest hypothesis==6.68.2 # via -r tests/requirements.in iniconfig==2.0.0 # via pytest packaging==23.0 # via pytest pluggy==1.0.0 # via pytest pytest==7.2.1 # via -r tests/requirements.in sortedcontainers==2.4.0 # via hypothesis 07070100000012000081A40000000000000000000000016418B31700002088000000000000000000000000000000000000002A00000000rpds.py-0.7.1/tests/test_hash_trie_map.py""" Modified from the pyrsistent test suite. Pre-modification, these were MIT licensed, and are copyright: Copyright (c) 2022 Tobias Gustafsson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from collections.abc import Hashable, Mapping from rpds import HashTrieMap import pytest HASH_MSG = "Not sure HashTrieMap implements Hash, it has mutable methods" @pytest.mark.xfail(reason=HASH_MSG) def test_instance_of_hashable(): assert isinstance(HashTrieMap(), Hashable) def test_instance_of_map(): assert isinstance(HashTrieMap(), Mapping) def test_literalish_works(): assert HashTrieMap() == HashTrieMap() assert HashTrieMap(a=1, b=2) == HashTrieMap({"a": 1, "b": 2}) def test_empty_initialization(): a_map = HashTrieMap() assert len(a_map) == 0 def test_initialization_with_one_element(): the_map = HashTrieMap({"a": 2}) assert len(the_map) == 1 assert the_map["a"] == 2 assert "a" in the_map empty_map = the_map.remove("a") assert len(empty_map) == 0 assert "a" not in empty_map def test_get_non_existing_raises_key_error(): m1 = HashTrieMap() with pytest.raises(KeyError) as error: m1["foo"] assert str(error.value) == "'foo'" def test_remove_non_existing_element_raises_key_error(): m1 = HashTrieMap(a=1) with pytest.raises(KeyError) as error: m1.remove("b") assert str(error.value) == "'b'" def test_various_iterations(): assert {"a", "b"} == set(HashTrieMap(a=1, b=2)) assert ["a", "b"] == sorted(HashTrieMap(a=1, b=2).keys()) assert [1, 2] == sorted(HashTrieMap(a=1, b=2).values()) assert {("a", 1), ("b", 2)} == set(HashTrieMap(a=1, b=2).items()) pm = HashTrieMap({k: k for k in range(100)}) assert len(pm) == len(pm.keys()) assert len(pm) == len(pm.values()) assert len(pm) == len(pm.items()) ks = pm.keys() assert all(k in pm for k in ks) assert all(k in ks for k in ks) us = pm.items() assert all(pm[k] == v for (k, v) in us) vs = pm.values() assert all(v in vs for v in vs) def test_initialization_with_two_elements(): map1 = HashTrieMap({"a": 2, "b": 3}) assert len(map1) == 2 assert map1["a"] == 2 assert map1["b"] == 3 map2 = map1.remove("a") assert "a" not in map2 assert map2["b"] == 3 def test_initialization_with_many_elements(): init_dict = {str(x): x for x in range(1700)} the_map = HashTrieMap(init_dict) assert len(the_map) == 1700 assert the_map["16"] == 16 assert the_map["1699"] == 1699 assert the_map.insert("256", 256) == the_map new_map = the_map.remove("1600") assert len(new_map) == 1699 assert "1600" not in new_map assert new_map["1601"] == 1601 # Some NOP properties assert new_map.discard("18888") == new_map assert "19999" not in new_map assert new_map["1500"] == 1500 assert new_map.insert("1500", new_map["1500"]) == new_map def test_access_non_existing_element(): map1 = HashTrieMap() assert len(map1) == 0 map2 = map1.insert("1", 1) assert "1" not in map1 assert map2["1"] == 1 assert "2" not in map2 def test_overwrite_existing_element(): map1 = HashTrieMap({"a": 2}) map2 = map1.insert("a", 3) assert len(map2) == 1 assert map2["a"] == 3 @pytest.mark.xfail(reason=HASH_MSG) def test_hash(): x = HashTrieMap(a=1, b=2, c=3) y = HashTrieMap(a=1, b=2, c=3) assert hash(x) == hash(y) def test_same_hash_when_content_the_same_but_underlying_vector_size_differs(): x = HashTrieMap({x: x for x in range(1000)}) y = HashTrieMap({10: 10, 200: 200, 700: 700}) for z in x: if z not in y: x = x.remove(z) assert x == y # assert hash(x) == hash(y) class HashabilityControlled: hashable = True def __hash__(self): if self.hashable: return 4 # Proven random raise ValueError("I am not currently hashable.") @pytest.mark.xfail(reason=HASH_MSG) def test_map_does_not_hash_values_on_second_hash_invocation(): hashable = HashabilityControlled() x = HashTrieMap(dict(el=hashable)) hash(x) hashable.hashable = False hash(x) def test_equal(): x = HashTrieMap(a=1, b=2, c=3) y = HashTrieMap(a=1, b=2, c=3) assert x == y assert not (x != y) assert y == x assert not (y != x) def test_equal_with_different_insertion_order(): x = HashTrieMap([(i, i) for i in range(50)]) y = HashTrieMap([(i, i) for i in range(49, -1, -1)]) assert x == y assert not (x != y) assert y == x assert not (y != x) def test_not_equal(): x = HashTrieMap(a=1, b=2, c=3) y = HashTrieMap(a=1, b=2) assert x != y assert not (x == y) assert y != x assert not (y == x) def test_not_equal_to_dict(): x = HashTrieMap(a=1, b=2, c=3) y = dict(a=1, b=2, d=4) assert x != y assert not (x == y) assert y != x assert not (y == x) def test_update_with_multiple_arguments(): # If same value is present in multiple sources, the rightmost is used. x = HashTrieMap(a=1, b=2, c=3) y = x.update(HashTrieMap(b=4, c=5), {"c": 6}) assert y == HashTrieMap(a=1, b=4, c=6) def test_update_one_argument(): x = HashTrieMap(a=1) assert x.update({"b": 2}) == HashTrieMap(a=1, b=2) def test_update_no_arguments(): x = HashTrieMap(a=1) assert x.update() == x class HashDummy: def __hash__(self): return 6528039219058920 # Hash of '33' def __eq__(self, other): return self is other def test_iteration_with_many_elements(): values = list(range(0, 2000)) keys = [str(x) for x in values] init_dict = dict(zip(keys, values)) hash_dummy1 = HashDummy() hash_dummy2 = HashDummy() # Throw in a couple of hash collision nodes to tests # those properly as well init_dict[hash_dummy1] = 12345 init_dict[hash_dummy2] = 54321 a_map = HashTrieMap(init_dict) actual_values = set() actual_keys = set() for k, v in a_map.items(): actual_values.add(v) actual_keys.add(k) assert actual_keys == set(keys + [hash_dummy1, hash_dummy2]) assert actual_values == set(values + [12345, 54321]) def test_str(): s = str(HashTrieMap({1: 2, 3: 4})) assert s == "HashTrieMap({1: 2, 3: 4})" or s == "HashTrieMap({3: 4, 1: 2})" def test_empty_truthiness(): assert HashTrieMap(a=1) assert not HashTrieMap() def test_iterable(): m = HashTrieMap((i, i * 2) for i in range(3)) assert m == HashTrieMap({0: 0, 1: 2, 2: 4}) def test_convert_hashtriemap(): m = HashTrieMap({i: i * 2 for i in range(3)}) assert HashTrieMap.convert({i: i * 2 for i in range(3)}) == m def test_fast_convert_hashtriemap(): m = HashTrieMap({i: i * 2 for i in range(3)}) assert HashTrieMap.convert(m) is m def test_more_eq(): # Non-pyrsistent-test-suite test o = object() assert HashTrieMap([(o, o), (1, o)]) == HashTrieMap([(o, o), (1, o)]) assert HashTrieMap([(o, "foo")]) == HashTrieMap([(o, "foo")]) assert HashTrieMap() == HashTrieMap([]) assert HashTrieMap({1: 2}) != HashTrieMap({1: 3}) assert HashTrieMap({o: 1}) != HashTrieMap({o: o}) assert HashTrieMap([]) != HashTrieMap([(o, 1)]) 07070100000013000081A40000000000000000000000016418B31700001332000000000000000000000000000000000000002A00000000rpds.py-0.7.1/tests/test_hash_trie_set.py""" Modified from the pyrsistent test suite. Pre-modification, these were MIT licensed, and are copyright: Copyright (c) 2022 Tobias Gustafsson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from rpds import HashTrieSet import pytest HASH_MSG = "Not sure HashTrieSet implements Hash, it has mutable methods" def test_key_is_tuple(): with pytest.raises(KeyError): HashTrieSet().remove((1, 1)) def test_key_is_not_tuple(): with pytest.raises(KeyError): HashTrieSet().remove("asdf") @pytest.mark.xfail(reason=HASH_MSG) def test_supports_hash(): assert hash(HashTrieSet((1, 2))) == hash(HashTrieSet(1, 2)) def test_empty_truthiness(): assert HashTrieSet([1]) assert not HashTrieSet() def test_contains_elements_that_it_was_initialized_with(): initial = [1, 2, 3] s = HashTrieSet(initial) assert set(s) == set(initial) assert len(s) == len(set(initial)) def test_is_immutable(): s1 = HashTrieSet([1]) s2 = s1.insert(2) assert s1 == HashTrieSet([1]) assert s2 == HashTrieSet([1, 2]) s3 = s2.remove(1) assert s2 == HashTrieSet([1, 2]) assert s3 == HashTrieSet([2]) def test_remove_when_not_present(): s1 = HashTrieSet([1, 2, 3]) with pytest.raises(KeyError): s1.remove(4) def test_discard(): s1 = HashTrieSet((1, 2, 3)) assert s1.discard(3) == HashTrieSet((1, 2)) assert s1.discard(4) == s1 def test_is_iterable(): assert sum(HashTrieSet([1, 2, 3])) == 6 def test_contains(): s = HashTrieSet([1, 2, 3]) assert 2 in s assert 4 not in s def test_supports_set_operations(): s1 = HashTrieSet([1, 2, 3]) s2 = HashTrieSet([3, 4, 5]) assert s1 | s2 == HashTrieSet([1, 2, 3, 4, 5]) assert s1.union(s2) == s1 | s2 assert s1 & s2 == HashTrieSet([3]) assert s1.intersection(s2) == s1 & s2 assert s1 - s2 == HashTrieSet([1, 2]) assert s1.difference(s2) == s1 - s2 assert s1 ^ s2 == HashTrieSet([1, 2, 4, 5]) assert s1.symmetric_difference(s2) == s1 ^ s2 def test_supports_set_comparisons(): s1 = HashTrieSet([1, 2, 3]) s3 = HashTrieSet([1, 2]) s4 = HashTrieSet([1, 2, 3]) assert HashTrieSet([1, 2, 3, 3, 5]) == HashTrieSet([1, 2, 3, 5]) assert s1 != s3 assert s3 < s1 assert s3 <= s1 assert s3 <= s4 assert s1 > s3 assert s1 >= s3 assert s4 >= s3 def test_repr(): rep = repr(HashTrieSet([1, 2])) assert rep == "HashTrieSet({1, 2})" or rep == "HashTrieSet({2, 1})" rep = repr(HashTrieSet(["1", "2"])) assert rep == "HashTrieSet({'1', '2'})" or rep == "HashTrieSet({'2', '1'})" def test_update(): assert HashTrieSet([1, 2, 3]).update([3, 4, 4, 5]) == HashTrieSet( [1, 2, 3, 4, 5] ) def test_update_no_elements(): s1 = HashTrieSet([1, 2]) assert s1.update([]) == s1 def test_iterable(): assert HashTrieSet(iter("a")) == HashTrieSet(iter("a")) def test_more_eq(): # Non-pyrsistent-test-suite test o = object() assert HashTrieSet([o]) == HashTrieSet([o]) assert HashTrieSet([o, o]) == HashTrieSet([o, o]) assert HashTrieSet([o]) == HashTrieSet([o, o]) assert HashTrieSet() == HashTrieSet([]) assert not (HashTrieSet([1, 2]) == HashTrieSet([1, 3])) assert not (HashTrieSet([o, 1]) == HashTrieSet([o, o])) assert not (HashTrieSet([]) == HashTrieSet([o])) assert HashTrieSet([1, 2]) != HashTrieSet([1, 3]) assert HashTrieSet([]) != HashTrieSet([o]) assert not (HashTrieSet([o]) != HashTrieSet([o])) assert not (HashTrieSet([o, o]) != HashTrieSet([o, o])) assert not (HashTrieSet([o]) != HashTrieSet([o, o])) assert not (HashTrieSet() != HashTrieSet([])) def test_more_set_comparisons(): s = HashTrieSet([1, 2, 3]) assert s == s assert not (s < s) assert s <= s assert not (s > s) assert s >= s 07070100000014000081A40000000000000000000000016418B31700000D4D000000000000000000000000000000000000002100000000rpds.py-0.7.1/tests/test_list.py""" Modified from the pyrsistent test suite. Pre-modification, these were MIT licensed, and are copyright: Copyright (c) 2022 Tobias Gustafsson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from rpds import List import pytest HASH_MSG = "Not sure List implements Hash, it has mutable methods" def test_literalish_works(): assert List(1, 2, 3) == List([1, 2, 3]) def test_first_and_rest(): pl = List([1, 2]) assert pl.first == 1 assert pl.rest.first == 2 assert pl.rest.rest == List() def test_instantiate_large_list(): assert List(range(1000)).first == 0 def test_iteration(): assert list(List()) == [] assert list(List([1, 2, 3])) == [1, 2, 3] def test_push_front(): assert List([1, 2, 3]).push_front(0) == List([0, 1, 2, 3]) def test_push_front_empty_list(): assert List().push_front(0) == List([0]) def test_truthiness(): assert List([1]) assert not List() def test_len(): assert len(List([1, 2, 3])) == 3 assert len(List()) == 0 def test_first_illegal_on_empty_list(): with pytest.raises(IndexError): List().first def test_rest_return_self_on_empty_list(): assert List().rest == List() def test_reverse(): assert reversed(List([1, 2, 3])) == List([3, 2, 1]) assert reversed(List()) == List() def test_inequality(): assert List([1, 2]) != List([1, 3]) assert List([1, 2]) != List([1, 2, 3]) assert List() != List([1, 2, 3]) def test_repr(): assert str(List()) == "List([])" assert str(List([1, 2, 3])) in "List([1, 2, 3])" @pytest.mark.xfail(reason=HASH_MSG) def test_hashing(): assert hash(List([1, 2])) == hash(List([1, 2])) assert hash(List([1, 2])) != hash(List([2, 1])) def test_sequence(): m = List("asdf") assert m == List(["a", "s", "d", "f"]) def test_more_eq(): # Non-pyrsistent-test-suite test o = object() assert List([o, o]) == List([o, o]) assert List([o]) == List([o]) assert List() == List([]) assert not (List([1, 2]) == List([1, 3])) assert not (List([o]) == List([o, o])) assert not (List([]) == List([o])) assert List([1, 2]) != List([1, 3]) assert List([o]) != List([o, o]) assert List([]) != List([o]) assert not (List([o, o]) != List([o, o])) assert not (List([o]) != List([o])) assert not (List() != List([])) 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!114 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor