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.
- copium-0.1.dev1/.github/workflows/build.yaml +81 -0
- copium-0.1.dev1/.github/workflows/lint.yaml +22 -0
- copium-0.1.dev1/.github/workflows/publish.yaml +87 -0
- copium-0.1.dev1/.github/workflows/test.yaml +25 -0
- copium-0.1.dev1/.github/workflows/typecheck.yaml +27 -0
- copium-0.1.dev1/.gitignore +41 -0
- copium-0.1.dev1/LICENSE +18 -0
- copium-0.1.dev1/LICENSES/MIT.txt +18 -0
- copium-0.1.dev1/PKG-INFO +242 -0
- copium-0.1.dev1/README.md +183 -0
- copium-0.1.dev1/assets/chart_dark.svg +1384 -0
- copium-0.1.dev1/assets/chart_light.svg +1384 -0
- copium-0.1.dev1/assets/chart_with_alternatives_dark.svg +1685 -0
- copium-0.1.dev1/assets/chart_with_alternatives_light.svg +1685 -0
- copium-0.1.dev1/pyproject.toml +224 -0
- copium-0.1.dev1/setup.cfg +4 -0
- copium-0.1.dev1/src/_copying.c +2669 -0
- copium-0.1.dev1/src/_memo.c +727 -0
- copium-0.1.dev1/src/_patching.c +550 -0
- copium-0.1.dev1/src/_pinning.c +815 -0
- copium-0.1.dev1/src/copium/__about__.pyi +23 -0
- copium-0.1.dev1/src/copium/__init__.pyi +31 -0
- copium-0.1.dev1/src/copium/extra.pyi +20 -0
- copium-0.1.dev1/src/copium/patch.pyi +16 -0
- copium-0.1.dev1/src/copium/py.typed +0 -0
- copium-0.1.dev1/src/copium.c +687 -0
- copium-0.1.dev1/src/copium.egg-info/PKG-INFO +242 -0
- copium-0.1.dev1/src/copium.egg-info/SOURCES.txt +45 -0
- copium-0.1.dev1/src/copium.egg-info/dependency_links.txt +1 -0
- copium-0.1.dev1/src/copium.egg-info/requires.txt +44 -0
- copium-0.1.dev1/src/copium.egg-info/top_level.txt +1 -0
- copium-0.1.dev1/src/copium_autopatch.pth +1 -0
- copium-0.1.dev1/taskfile.yaml +129 -0
- copium-0.1.dev1/tests/__init__.py +1 -0
- copium-0.1.dev1/tests/api/__init__.py +11 -0
- copium-0.1.dev1/tests/api/test_about.py +34 -0
- copium-0.1.dev1/tests/api/test_copy.py +99 -0
- copium-0.1.dev1/tests/api/test_extra.py +20 -0
- copium-0.1.dev1/tests/conftest.py +37 -0
- copium-0.1.dev1/tests/test_copium.py +173 -0
- copium-0.1.dev1/tests/test_copy.py +1294 -0
- copium-0.1.dev1/tests/test_patch.py +109 -0
- copium-0.1.dev1/tests/test_signatures.py +114 -0
- copium-0.1.dev1/tools/__init__.py +0 -0
- copium-0.1.dev1/tools/build_system/__init__.py +0 -0
- 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
|
copium-0.1.dev1/LICENSE
ADDED
|
@@ -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.
|
copium-0.1.dev1/PKG-INFO
ADDED
|
@@ -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
|
+
[](https://pypi.python.org/pypi/copium)
|
|
63
|
+
[](https://pypi.python.org/pypi/copium)
|
|
64
|
+
[](https://pypi.python.org/pypi/copium)
|
|
65
|
+
[](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`
|