copium 0.1.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. copium-0.1.dev1/.github/workflows/build.yaml +81 -0
  2. copium-0.1.dev1/.github/workflows/lint.yaml +22 -0
  3. copium-0.1.dev1/.github/workflows/publish.yaml +87 -0
  4. copium-0.1.dev1/.github/workflows/test.yaml +25 -0
  5. copium-0.1.dev1/.github/workflows/typecheck.yaml +27 -0
  6. copium-0.1.dev1/.gitignore +41 -0
  7. copium-0.1.dev1/LICENSE +18 -0
  8. copium-0.1.dev1/LICENSES/MIT.txt +18 -0
  9. copium-0.1.dev1/PKG-INFO +242 -0
  10. copium-0.1.dev1/README.md +183 -0
  11. copium-0.1.dev1/assets/chart_dark.svg +1384 -0
  12. copium-0.1.dev1/assets/chart_light.svg +1384 -0
  13. copium-0.1.dev1/assets/chart_with_alternatives_dark.svg +1685 -0
  14. copium-0.1.dev1/assets/chart_with_alternatives_light.svg +1685 -0
  15. copium-0.1.dev1/pyproject.toml +224 -0
  16. copium-0.1.dev1/setup.cfg +4 -0
  17. copium-0.1.dev1/src/_copying.c +2669 -0
  18. copium-0.1.dev1/src/_memo.c +727 -0
  19. copium-0.1.dev1/src/_patching.c +550 -0
  20. copium-0.1.dev1/src/_pinning.c +815 -0
  21. copium-0.1.dev1/src/copium/__about__.pyi +23 -0
  22. copium-0.1.dev1/src/copium/__init__.pyi +31 -0
  23. copium-0.1.dev1/src/copium/extra.pyi +20 -0
  24. copium-0.1.dev1/src/copium/patch.pyi +16 -0
  25. copium-0.1.dev1/src/copium/py.typed +0 -0
  26. copium-0.1.dev1/src/copium.c +687 -0
  27. copium-0.1.dev1/src/copium.egg-info/PKG-INFO +242 -0
  28. copium-0.1.dev1/src/copium.egg-info/SOURCES.txt +45 -0
  29. copium-0.1.dev1/src/copium.egg-info/dependency_links.txt +1 -0
  30. copium-0.1.dev1/src/copium.egg-info/requires.txt +44 -0
  31. copium-0.1.dev1/src/copium.egg-info/top_level.txt +1 -0
  32. copium-0.1.dev1/src/copium_autopatch.pth +1 -0
  33. copium-0.1.dev1/taskfile.yaml +129 -0
  34. copium-0.1.dev1/tests/__init__.py +1 -0
  35. copium-0.1.dev1/tests/api/__init__.py +11 -0
  36. copium-0.1.dev1/tests/api/test_about.py +34 -0
  37. copium-0.1.dev1/tests/api/test_copy.py +99 -0
  38. copium-0.1.dev1/tests/api/test_extra.py +20 -0
  39. copium-0.1.dev1/tests/conftest.py +37 -0
  40. copium-0.1.dev1/tests/test_copium.py +173 -0
  41. copium-0.1.dev1/tests/test_copy.py +1294 -0
  42. copium-0.1.dev1/tests/test_patch.py +109 -0
  43. copium-0.1.dev1/tests/test_signatures.py +114 -0
  44. copium-0.1.dev1/tools/__init__.py +0 -0
  45. copium-0.1.dev1/tools/build_system/__init__.py +0 -0
  46. copium-0.1.dev1/tools/build_system/backend.py +837 -0
@@ -0,0 +1,81 @@
1
+ name: Build
2
+
3
+ on:
4
+ push:
5
+ tags: [ "v*" ]
6
+ branches: [ main ]
7
+ pull_request:
8
+ branches: [ main ]
9
+ workflow_dispatch:
10
+
11
+ jobs:
12
+ wheels:
13
+ # Separate native runners so mac gets native arm64 & x86_64 (universal2), Windows gets MSVC, etc.
14
+ strategy:
15
+ fail-fast: false
16
+ max-parallel: 64
17
+ matrix:
18
+ build:
19
+ # Linux
20
+ - { os: ubuntu-latest, platform: linux, archs: x86_64, arch_label: "x86_64" }
21
+ - { os: ubuntu-24.04-arm, platform: linux, archs: aarch64, arch_label: "ARM64" }
22
+ # - { os: ubuntu-latest, platform: linux, archs: ppc64le, arch_label: "ppc64le" }
23
+ # - { os: ubuntu-latest, platform: linux, archs: s390x, arch_label: "s390x" }
24
+ # Windows
25
+ # - { os: windows-latest, platform: windows, archs: AMD64, arch_label: "x64" }
26
+ # - { os: windows-11-arm, platform: windows, archs: ARM64, arch_label: "ARM64" }
27
+ # macOS
28
+ - { os: macos-15, platform: macos, archs: arm64, arch_label: "Apple Silicon" }
29
+ - { os: macos-15-intel, platform: macos, archs: x86_64, arch_label: "Intel" }
30
+ python:
31
+ - { display: "3.10", tag: "cp310" }
32
+ - { display: "3.11", tag: "cp311" }
33
+ - { display: "3.12", tag: "cp312" }
34
+ - { display: "3.13", tag: "cp313" }
35
+ - { display: "3.14", tag: "cp314" }
36
+
37
+ runs-on: ${{ matrix.build.os }}
38
+
39
+ name: "Python ${{ matrix.python.display }} / ${{ fromJSON('{\"linux\":\"Linux\",\"windows\":\"Windows\",\"macos\":\"macOS\"}')[matrix.build.platform] }} / ${{ matrix.build.arch_label }}"
40
+
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+
44
+ - name: Set up QEMU
45
+ if: runner.os == 'Linux' && runner.arch == 'X64'
46
+ uses: docker/setup-qemu-action@v3
47
+ with:
48
+ platforms: all
49
+
50
+ - name: Setup uv
51
+ uses: astral-sh/setup-uv@v6
52
+ with:
53
+ enable-cache: true
54
+
55
+ - name: Build wheels
56
+ uses: pypa/cibuildwheel@v3.2.1
57
+ env:
58
+ CIBW_BUILD: "${{ matrix.python.tag }}-*"
59
+ CIBW_ARCHS: "${{ matrix.build.archs }}"
60
+ CIBW_BUILD_VERBOSITY: 1
61
+
62
+ - uses: actions/upload-artifact@v4
63
+ with:
64
+ name: "Wheels-${{ matrix.python.display }}-${{ fromJSON('{\"linux\":\"Linux\",\"windows\":\"Windows\",\"macos\":\"macOS\"}')[matrix.build.platform] }}-${{ matrix.build.arch_label }}"
65
+ path: ./wheelhouse/*.whl
66
+
67
+ sdist:
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+ - name: Setup uv
72
+ uses: astral-sh/setup-uv@v6
73
+ with:
74
+ enable-cache: true
75
+ - name: Build sdist
76
+ run: uv build --sdist
77
+ - name: Upload sdist
78
+ uses: actions/upload-artifact@v4
79
+ with:
80
+ name: sdist
81
+ path: dist/*.tar.gz
@@ -0,0 +1,22 @@
1
+ name: Lint
2
+ on:
3
+ push:
4
+ branches: [ "**" ]
5
+ tags: [ "*" ]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ lint:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v5
16
+ - uses: astral-sh/setup-uv@v6
17
+ with:
18
+ python-version: "3.14"
19
+ enable-cache: true
20
+ - uses: go-task/setup-task@v1
21
+ - run: task setup
22
+ - run: task lint
@@ -0,0 +1,87 @@
1
+ name: Publish
2
+
3
+ on:
4
+ # Auto-publish after Build completes
5
+ workflow_run:
6
+ workflows: [ "Build" ]
7
+ types: [ "completed" ]
8
+ # Manual publish from a specific Build run
9
+ workflow_dispatch:
10
+ inputs:
11
+ run-id:
12
+ description: "Build workflow run ID to fetch artifacts from (Actions ➜ Build ➜ a completed run)"
13
+ required: true
14
+ type: string
15
+
16
+ permissions:
17
+ contents: read
18
+ id-token: write
19
+
20
+ concurrency:
21
+ # Use head SHA for auto, current SHA for manual, so concurrent publishes of the same ref collapse.
22
+ group: publish-${{ (github.event_name == 'workflow_run' && github.event.workflow_run.head_sha) || github.sha }}
23
+ cancel-in-progress: true
24
+
25
+ jobs:
26
+ publish:
27
+ # Conditions:
28
+ # - Auto path: Build succeeded, and original trigger was a push to main OR a tag push (head_branch == null for tags)
29
+ # - Manual path: always allowed; caller supplies run-id
30
+ if: >
31
+ (github.event_name == 'workflow_run' &&
32
+ github.event.workflow_run.conclusion == 'success' &&
33
+ github.event.workflow_run.event == 'push' &&
34
+ (github.event.workflow_run.head_branch == 'main' || github.event.workflow_run.head_branch == null))
35
+ || (github.event_name == 'workflow_dispatch')
36
+ runs-on: ubuntu-latest
37
+ environment:
38
+ name: pypi
39
+ url: https://pypi.org/project/copium
40
+ steps:
41
+ - name: Resolve source run-id
42
+ id: resolve
43
+ run: |
44
+ if [ "${{ github.event_name }}" = "workflow_run" ]; then
45
+ echo "RUN_ID=${{ github.event.workflow_run.id }}" >> "$GITHUB_OUTPUT"
46
+ else
47
+ echo "RUN_ID=${{ inputs.run-id }}" >> "$GITHUB_OUTPUT"
48
+ fi
49
+
50
+ - name: Prepare directories
51
+ run: |
52
+ rm -rf artifacts dist
53
+ mkdir -p artifacts dist
54
+
55
+ - name: Download Wheels
56
+ uses: dawidd6/action-download-artifact@v3
57
+ with:
58
+ run_id: ${{ steps.resolve.outputs.RUN_ID }}
59
+ name: "^Wheels-"
60
+ name_is_regexp: true
61
+ path: artifacts
62
+ if_no_artifact_found: fail
63
+
64
+ - name: Download sdist
65
+ uses: dawidd6/action-download-artifact@v3
66
+ with:
67
+ run_id: ${{ steps.resolve.outputs.RUN_ID }}
68
+ name: sdist
69
+ path: artifacts
70
+ if_no_artifact_found: fail
71
+
72
+ - name: Flatten artifacts into ./dist
73
+ shell: bash
74
+ run: |
75
+ shopt -s globstar nullglob
76
+ # Copy wheels and sdists from any artifact subfolder into ./dist
77
+ for f in artifacts/**/*.whl artifacts/**/*.tar.gz; do
78
+ cp -v "$f" dist/
79
+ done
80
+ echo "Contents of dist:"
81
+ ls -l dist
82
+
83
+ - name: Publish to PyPI
84
+ uses: pypa/gh-action-pypi-publish@release/v1
85
+ with:
86
+ packages-dir: dist/
87
+ skip-existing: true # Safe for dev versions or reruns
@@ -0,0 +1,25 @@
1
+ name: Test
2
+ on:
3
+ push:
4
+ branches: [ "**" ]
5
+ tags: [ "*" ]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ name: Python ${{ matrix.python }}
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ python: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t", "3.15"]
18
+ steps:
19
+ - uses: actions/checkout@v5
20
+ - uses: astral-sh/setup-uv@v6
21
+ with:
22
+ python-version: ${{ matrix.python }}
23
+ enable-cache: true
24
+ - uses: go-task/setup-task@v1
25
+ - run: task test
@@ -0,0 +1,27 @@
1
+ name: Typecheck
2
+ on:
3
+ push:
4
+ branches: [ "**" ]
5
+ tags: [ "*" ]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ typecheck:
13
+ name: Python ${{ matrix.python }}
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ python: [
18
+ "3.10", "3.11", "3.12", "3.13", "3.14"
19
+ ]
20
+ steps:
21
+ - uses: actions/checkout@v5
22
+ - uses: astral-sh/setup-uv@v6
23
+ with:
24
+ python-version: ${{ matrix.python }}
25
+ enable-cache: true
26
+ - uses: go-task/setup-task@v1
27
+ - run: task typecheck
@@ -0,0 +1,41 @@
1
+ # Python / build
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ .build/
6
+ ./build
7
+ dist/
8
+ .eggs/
9
+ *.egg-info/
10
+
11
+ # venv
12
+ .venv/
13
+ .env
14
+ venv/
15
+
16
+ # tooling
17
+ .pytest_cache/
18
+ .mypy_cache/
19
+ .pytype/
20
+ .pyre/
21
+ .dmypy.json
22
+ .hypothesis/
23
+
24
+ # coverage
25
+ .coverage
26
+ .coverage.*
27
+ htmlcov/
28
+
29
+ # editors
30
+ .vscode/*
31
+ !.vscode/settings.json
32
+ !.vscode/tasks.json
33
+ !.vscode/launch.json
34
+ !.vscode/extensions.json
35
+ !.vscode/*.code-snippets
36
+ .idea/
37
+ .DS_Store
38
+ .build-cache
39
+ .task
40
+ .pgo
41
+ *.so
@@ -0,0 +1,18 @@
1
+ MIT License
2
+
3
+ Copyright (c) <year> <copyright holders>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial
12
+ portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
16
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ MIT License
2
+
3
+ Copyright (c) <year> <copyright holders>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial
12
+ portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
16
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,242 @@
1
+ Metadata-Version: 2.4
2
+ Name: copium
3
+ Version: 0.1.dev1
4
+ Summary: Fastest deepcopy implementation for CPython
5
+ Author-email: "Arseny Boykov (Bobronium)" <hi@bobronium.me>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Bobronium/copium
8
+ Project-URL: Source, https://github.com/Bobronium/copium
9
+ Project-URL: Issues, https://github.com/Bobronium/copium/issues
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Development Status :: 3 - Alpha
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Provides-Extra: dev
24
+ Requires-Dist: copium[lint]; extra == "dev"
25
+ Requires-Dist: copium[typecheck]; extra == "dev"
26
+ Requires-Dist: copium[test]; extra == "dev"
27
+ Requires-Dist: copium[docs]; extra == "dev"
28
+ Provides-Extra: lint
29
+ Requires-Dist: ruff>=0.5; extra == "lint"
30
+ Provides-Extra: typecheck
31
+ Requires-Dist: mypy>=1.10; extra == "typecheck"
32
+ Requires-Dist: pyright>=1.1.400; extra == "typecheck"
33
+ Requires-Dist: zuban>=0.2.0; extra == "typecheck"
34
+ Requires-Dist: pytest; extra == "typecheck"
35
+ Provides-Extra: test
36
+ Requires-Dist: pytest>=8; extra == "test"
37
+ Requires-Dist: pytest-assert-type>=0.1.5; extra == "test"
38
+ Requires-Dist: indifference>=0.1.0; extra == "test"
39
+ Requires-Dist: typing-extensions; python_version < "3.12" and extra == "test"
40
+ Requires-Dist: datamodelzoo; extra == "test"
41
+ Provides-Extra: docs
42
+ Requires-Dist: mkdocs-material; extra == "docs"
43
+ Requires-Dist: mkdocstrings[python]; extra == "docs"
44
+ Requires-Dist: mkdocs-autorefs; extra == "docs"
45
+ Requires-Dist: mkdocs-section-index; extra == "docs"
46
+ Provides-Extra: benchmark
47
+ Requires-Dist: tyro>=0.9.33; extra == "benchmark"
48
+ Requires-Dist: pyperf>=2.9.0; extra == "benchmark"
49
+ Requires-Dist: ipython>=8.37.0; extra == "benchmark"
50
+ Requires-Dist: datamodelzoo; extra == "benchmark"
51
+ Provides-Extra: build
52
+ Requires-Dist: build>=1.3.0; extra == "build"
53
+ Requires-Dist: cibuildwheel>=2.23.3; extra == "build"
54
+ Requires-Dist: pip>=25.3; extra == "build"
55
+ Requires-Dist: setuptools>=80.9.0; extra == "build"
56
+ Requires-Dist: setuptools-scm>=9.2.2; extra == "build"
57
+ Requires-Dist: wheel>=0.45.1; extra == "build"
58
+ Dynamic: license-file
59
+
60
+ # copium
61
+
62
+ [![image](https://img.shields.io/pypi/v/copium.svg)](https://pypi.python.org/pypi/copium)
63
+ [![image](https://img.shields.io/pypi/l/copium.svg)](https://pypi.python.org/pypi/copium)
64
+ [![image](https://img.shields.io/pypi/pyversions/copium.svg)](https://pypi.python.org/pypi/copium)
65
+ [![Actions status](https://github.com/Bobronium/copium/actions/workflows/build.yml/badge.svg)](https://github.com/Bobronium/copium/actions)
66
+
67
+ An extremely fast Python copy/deepcopy implementation, written in C.
68
+
69
+ <div align="center">
70
+ <picture>
71
+ <source srcset="https://raw.githubusercontent.com/Bobronium/copium/main/assets/chart_dark.svg" media="(prefers-color-scheme: dark)">
72
+ <source srcset="https://raw.githubusercontent.com/Bobronium/copium/main/assets/chart_light.svg" media="(prefers-color-scheme: light)">
73
+ <img src="https://raw.githubusercontent.com/Bobronium/copium/main/assets/chart_light.svg" alt="Benchmark results bar chart">
74
+ </picture>
75
+ </div>
76
+
77
+ <div align="center">
78
+ <i>Getting a deep copy of <a href="https://github.com/python-jsonschema/jsonschema/blob/0798cd7a59caea669e2de2ecac9c6e2dfcb57f6d/jsonschema/validators.py#L812">jsonschema.Draft202012Validator.META_SCHEMA</a>.</i>
79
+ </div>
80
+
81
+ ## Highlights
82
+
83
+ - ~3x faster on mixed data
84
+ - ~6x faster on typical data
85
+ - [~30 faster in some cases](#benchmarks)
86
+ - [Requires **zero** code changes to adopt](#1-you-set-copium_patch_deepcopy1-before-launch)
87
+ - Passes all tests from `CPython/Lib/test/test_copy.py`
88
+
89
+ ## Installation
90
+
91
+ ```bash
92
+ pip install copium
93
+ ```
94
+
95
+ ## Usage
96
+
97
+ `copium` is designed to be drop-in replacement for `copy` module.
98
+
99
+ After installation deepcopy will be fast in either of 3 cases:
100
+
101
+ ##### 1) You set `COPIUM_PATCH_DEEPCOPY=1` before launch
102
+
103
+ ##### 2) You call `copium.patch.enable()` manually at launch
104
+
105
+ ##### 3) You use `copium.deepcopy()` directly
106
+
107
+ Generally any code that uses stdlib `copy` can be replaced with `copium` simply by:
108
+
109
+ ```diff
110
+ - from copy import deepcopy
111
+ + from copium import deepcopy
112
+ ```
113
+
114
+ Alternatively, you can import `copium.patch` once and enable it:
115
+
116
+ ```python
117
+ import copium.patch
118
+
119
+
120
+ copium.patch.enable()
121
+ ```
122
+
123
+ Or just `export COPIUM_PATCH_DEEPCOPY=1` before running your Python process.
124
+
125
+ This will automatically call `copium.patch.enable()` on start, and all calls to `copy.deepcopy()` will be forwarded to
126
+ `copium.deepcopy()`. On Python 3.12+ there's no performance overhead compared to direct
127
+ usage.
128
+
129
+ There are two main benefits of using `copium.patch`,
130
+
131
+ - It requires zero code changes
132
+ - It automatically makes any third party code that uses deepcopy faster, for
133
+ instance, it will speed up instantiations of pydantic
134
+ models with mutable defaults
135
+ \(see [pydantic_core](https://github.com/pydantic/pydantic-core/blob/f1239f81d944bcda84bffec64527d46f041ccc9e/src/validators/with_default.rs#L23)).
136
+
137
+ ## Caveats
138
+
139
+ - `copium.deepcopy()` ignores `sys.getrecursionlimit()`. It still may raise `RecursionError` at some point, but at much
140
+ larger depths than default interpreter recursion limit (see `tests.test_copium.test_recursion_error`)
141
+ - unless `memo` argument supplied as `dict` when calling `copium.deepcopy()`, special lightweight memo storage will be
142
+ used to reduce memoization overhead. It implements `MutableMapping` methods, so any custom `__deepcopy__` methods
143
+ should work as expected
144
+ - `copium.deepcopy()` will raise `TypeError` if `type(memo) is not dict` — if you're unsure what it means, don't worry —
145
+ you don't need to supply memo to deepcopy in the first place.
146
+ - `copium` uses unstable CPython API. This means that it might break on new major Python release
147
+
148
+ ## Benchmarks
149
+
150
+ A full benchmark suite is in progress and will be published soon.
151
+ In the meanwhile, you can reproduce the results shown in the chart above with this minimal script
152
+
153
+ <details>
154
+ <summary>Pyperf case</summary>
155
+
156
+ ```shell
157
+ cat > benchmark.py << 'PY'
158
+ # /// script
159
+ # requires-python = ">=3.10"
160
+ # dependencies = [
161
+ # "pyperf",
162
+ # "copium",
163
+ # ]
164
+ # ///
165
+ import pyperf
166
+
167
+ runner = pyperf.Runner()
168
+
169
+ setup = """
170
+ import copy
171
+ from decimal import Decimal
172
+
173
+ payload = {
174
+ "a": 1,
175
+ "b": (b := [(1, 2, 3), (4, 5, 6)]),
176
+ "c": [Decimal("3.14"), complex(), [], (), frozenset(), b],
177
+ }
178
+ """
179
+
180
+ runner.timeit(name="deepcopy", stmt=f"b=copy.deepcopy(payload)", setup=setup)
181
+ PY
182
+ ```
183
+
184
+ ```shell
185
+ uv run --python 3.14t benchmark.py -q -o copy3.14t.json && \
186
+ COPIUM_PATCH_DEEPCOPY=1 PYTHON_GIL=0 \
187
+ uv run --python 3.14t benchmark.py -q -o copium3.14t.json --copy-env && \
188
+ uvx pyperf compare_to copy3.14t.json copium3.14t.json --table
189
+ ```
190
+
191
+ Output:
192
+
193
+ ```shell
194
+ deepcopy: Mean +- std dev: 20.8 us +- 1.6 us
195
+ deepcopy: Mean +- std dev: 928 ns +- 11 ns
196
+ +--------------+---------+--------------------+
197
+ | Benchmark | copy | copium |
198
+ +===========+=========+=======================+
199
+ | deepcopy | 20.8 us | 928 ns: 22.40x faster |
200
+ +-----------+---------+-----------------------+
201
+ ```
202
+
203
+ ```shell
204
+ ❯ uv run --python 3.13 benchmark.py -q -o copy3.13.json && \
205
+ COPIUM_PATCH_DEEPCOPY=1 \
206
+ uv run --python 3.13 benchmark.py -q -o copium3.13.json --copy-env && \
207
+ uvx pyperf compare_to copy3.13.json copium3.13.json --table
208
+ ```
209
+
210
+ ```shell
211
+ deepcopy: Mean +- std dev: 10.8 us +- 0.9 us
212
+ deepcopy: Mean +- std dev: 880 ns +- 23 ns
213
+ +-----------+-----------+-----------------------+
214
+ | Benchmark | copy3.13t | copium3.13t |
215
+ +===========+===========+=======================+
216
+ | deepcopy | 10.8 us | 880 ns: 12.26x faster |
217
+ +-----------+-----------+-----------------------+
218
+ ```
219
+
220
+ ```shell
221
+ ❯ uv run --python 3.13t benchmark.py -q -o copy3.13t.json && \
222
+ COPIUM_PATCH_DEEPCOPY=1 PYTHON_GIL=0 \
223
+ uv run --python 3.13t benchmark.py -q -o copium3.13t.json --copy-env && \
224
+ uvx pyperf compare_to copy3.13t.json copium3.13t.json --table
225
+ ```
226
+
227
+ ```shell
228
+ deepcopy: Mean +- std dev: 29.0 us +- 6.7 us
229
+ deepcopy: Mean +- std dev: 942 ns +- 29 ns
230
+ +-----------+-----------+-----------------------+
231
+ | Benchmark | copy3.13t | copium3.13t |
232
+ +===========+===========+=======================+
233
+ | deepcopy | 29.0 us | 942 ns: 30.84x faster |
234
+ +-----------+-----------+-----------------------+
235
+ ```
236
+
237
+ </details>
238
+
239
+ ## Development
240
+
241
+ - Install Task: https://taskfile.dev
242
+ - All checks: `task` / `task MATRIX=1`