Metadata-Version: 2.4
Name: copium
Version: 0.1.dev1
Summary: Fastest deepcopy implementation for CPython
Author-email: "Arseny Boykov (Bobronium)" <hi@bobronium.me>
License-Expression: MIT
Project-URL: Homepage, https://github.com/Bobronium/copium
Project-URL: Source, https://github.com/Bobronium/copium
Project-URL: Issues, https://github.com/Bobronium/copium/issues
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: copium[lint]; extra == "dev"
Requires-Dist: copium[typecheck]; extra == "dev"
Requires-Dist: copium[test]; extra == "dev"
Requires-Dist: copium[docs]; extra == "dev"
Provides-Extra: lint
Requires-Dist: ruff>=0.5; extra == "lint"
Provides-Extra: typecheck
Requires-Dist: mypy>=1.10; extra == "typecheck"
Requires-Dist: pyright>=1.1.400; extra == "typecheck"
Requires-Dist: zuban>=0.2.0; extra == "typecheck"
Requires-Dist: pytest; extra == "typecheck"
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Requires-Dist: pytest-assert-type>=0.1.5; extra == "test"
Requires-Dist: indifference>=0.1.0; extra == "test"
Requires-Dist: typing-extensions; python_version < "3.12" and extra == "test"
Requires-Dist: datamodelzoo; extra == "test"
Requires-Dist: pytest-codspeed>=4.2.0; extra == "test"
Requires-Dist: pytest-test-groups>=1.2.1; extra == "test"
Provides-Extra: docs
Requires-Dist: mkdocs-material; extra == "docs"
Requires-Dist: mkdocstrings[python]; extra == "docs"
Requires-Dist: mkdocs-autorefs; extra == "docs"
Requires-Dist: mkdocs-section-index; extra == "docs"
Provides-Extra: benchmark
Requires-Dist: tyro>=0.9.33; extra == "benchmark"
Requires-Dist: pyperf>=2.9.0; extra == "benchmark"
Requires-Dist: ipython>=8.37.0; extra == "benchmark"
Requires-Dist: datamodelzoo; extra == "benchmark"
Provides-Extra: build
Requires-Dist: build>=1.3.0; extra == "build"
Requires-Dist: cibuildwheel>=2.23.3; extra == "build"
Requires-Dist: pip>=25.3; extra == "build"
Requires-Dist: setuptools>=80.9.0; extra == "build"
Requires-Dist: setuptools-scm>=9.2.2; extra == "build"
Requires-Dist: wheel>=0.45.1; extra == "build"
Dynamic: license-file

# copium

[![image](https://img.shields.io/pypi/v/copium.svg)](https://pypi.python.org/pypi/copium)
[![image](https://img.shields.io/pypi/l/copium.svg)](https://pypi.python.org/pypi/copium)
[![image](https://img.shields.io/pypi/pyversions/copium.svg)](https://pypi.python.org/pypi/copium)
[![Actions status](https://github.com/Bobronium/copium/actions/workflows/build.yml/badge.svg)](https://github.com/Bobronium/copium/actions)

An extremely fast Python copy/deepcopy implementation, written in C.

<div align="center">
  <picture>
    <source srcset="https://raw.githubusercontent.com/Bobronium/copium/main/assets/chart_dark.svg" media="(prefers-color-scheme: dark)">
    <source srcset="https://raw.githubusercontent.com/Bobronium/copium/main/assets/chart_light.svg" media="(prefers-color-scheme: light)">
    <img src="https://raw.githubusercontent.com/Bobronium/copium/main/assets/chart_light.svg" alt="Benchmark results bar chart">
  </picture>
</div>

<div align="center">
  <i><code>deepcopy_memo</code> suite from <a href="https://github.com/python/pyperformance/blob/643526f166869c6006009d316be38a35a3cffb2c/pyperformance/data-files/benchmarks/bm_deepcopy/run_benchmark.py#L88">python/pyperformance</a></i>
</div>

## Highlights

- ~3x faster on mixed data
- ~6x faster on typical data
- [~30 faster in some cases](#benchmarks)
- [Requires **zero** code changes to adopt](#1-you-set-copium_patch_deepcopy1-before-launch)
- Passes all tests from `CPython/Lib/test/test_copy.py`

## Installation

```bash
pip install copium
```

## Usage

`copium` is designed to be drop-in replacement for `copy` module.

After installation deepcopy will be fast in either of 3 cases:

##### 1) You set `COPIUM_PATCH_DEEPCOPY=1` before launch

##### 2) You call `copium.patch.enable()` manually at launch

##### 3) You use `copium.deepcopy()` directly

Generally any code that uses stdlib `copy` can be replaced with `copium` simply by:

```diff
- from copy import deepcopy
+ from copium import deepcopy
```

Alternatively, you can import `copium.patch` once and enable it:

```python
import copium.patch


copium.patch.enable()
```

Or just `export COPIUM_PATCH_DEEPCOPY=1` before running your Python process.

This will automatically call `copium.patch.enable()` on start, and all calls to `copy.deepcopy()` will be forwarded to
`copium.deepcopy()`. On Python 3.12+ there's no performance overhead compared to direct
usage.

There are two main benefits of using `copium.patch`,

- It requires zero code changes
- It automatically makes any third party code that uses deepcopy faster, for
  instance, it will speed up instantiations of pydantic
  models with mutable defaults
  \(see [pydantic_core](https://github.com/pydantic/pydantic-core/blob/f1239f81d944bcda84bffec64527d46f041ccc9e/src/validators/with_default.rs#L23)).

## Caveats

- `copium.deepcopy()` ignores `sys.getrecursionlimit()`. It still may raise `RecursionError` at some point, but at much
  larger depths than default interpreter recursion limit (see `tests.test_copium.test_recursion_error`)
- unless `memo` argument supplied as `dict` when calling `copium.deepcopy()`, special lightweight memo storage will be
  used to reduce memoization overhead. It implements `MutableMapping` methods, so any custom `__deepcopy__` methods
  should work as expected
- `copium.deepcopy()` will raise `TypeError` if `type(memo) is not dict` — if you're unsure what it means, don't worry —
  you don't need to supply memo to deepcopy in the first place.
- `copium` uses unstable CPython API. This means that it might break on new major Python release

## Benchmarks

A full benchmark suite is in progress and will be published soon.
In the meanwhile, you can reproduce the results shown in the chart above with this minimal script

<details>
<summary>Pyperf case</summary>

```shell
cat > benchmark.py << 'PY'
# /// script
# requires-python = ">=3.10"
# dependencies = [
#     "pyperf",
#     "copium",
# ]
# ///
import pyperf

runner = pyperf.Runner()

setup = """
import copy
from decimal import Decimal

payload = {
        "a": 1,
        "b": (b := [(1, 2, 3), (4, 5, 6)]),
        "c": [Decimal("3.14"), complex(), [], (), frozenset(), b],
}
"""

runner.timeit(name="deepcopy", stmt=f"b=copy.deepcopy(payload)", setup=setup)
PY
```

```shell
uv run --python 3.14t benchmark.py -q -o copy3.14t.json && \
COPIUM_PATCH_DEEPCOPY=1 PYTHON_GIL=0 \
uv run --python 3.14t benchmark.py -q -o copium3.14t.json --copy-env && \
uvx pyperf compare_to copy3.14t.json copium3.14t.json --table
```

Output:

```shell
deepcopy: Mean +- std dev: 20.8 us +- 1.6 us
deepcopy: Mean +- std dev: 928 ns +- 11 ns
+--------------+---------+--------------------+
| Benchmark | copy    | copium                |
+===========+=========+=======================+
| deepcopy  | 20.8 us | 928 ns: 22.40x faster |
+-----------+---------+-----------------------+
```

```shell
❯ uv run --python 3.13 benchmark.py -q -o copy3.13.json && \
COPIUM_PATCH_DEEPCOPY=1 \
uv run --python 3.13 benchmark.py -q -o copium3.13.json --copy-env && \
uvx pyperf compare_to copy3.13.json copium3.13.json --table
```

```shell
deepcopy: Mean +- std dev: 10.8 us +- 0.9 us
deepcopy: Mean +- std dev: 880 ns +- 23 ns
+-----------+-----------+-----------------------+
| Benchmark | copy3.13t | copium3.13t           |
+===========+===========+=======================+
| deepcopy  | 10.8 us   | 880 ns: 12.26x faster |
+-----------+-----------+-----------------------+
```

```shell
❯ uv run --python 3.13t benchmark.py -q -o copy3.13t.json && \
COPIUM_PATCH_DEEPCOPY=1 PYTHON_GIL=0 \
uv run --python 3.13t benchmark.py -q -o copium3.13t.json --copy-env && \
uvx pyperf compare_to copy3.13t.json copium3.13t.json --table
```

```shell
deepcopy: Mean +- std dev: 29.0 us +- 6.7 us
deepcopy: Mean +- std dev: 942 ns +- 29 ns
+-----------+-----------+-----------------------+
| Benchmark | copy3.13t | copium3.13t           |
+===========+===========+=======================+
| deepcopy  | 29.0 us   | 942 ns: 30.84x faster |
+-----------+-----------+-----------------------+
```

</details>

## Development

- Install Task: https://taskfile.dev
- All checks: `task` / `task MATRIX=1`
