Skip to main content

concurrent-c-node

Call Node (and npm packages) from Python. Native types, exceptions, callbacks, and async all cross the boundary.

Part of Concurrent-C — a strict C11-superset preprocessor: .ccs lowers to plain C and compiles with your host C compiler. (This bridge itself is pure Python stdlib — no native build.)

Map of the three boundaries (CC hosts JS, native modules, this package bridge): JS / Python interop.

import cc_node

js = cc_node.create()                # always a child `node` process
_ = js.require('lodash')             # cwd node_modules
_.chunk([1, 2, 3, 4, 5], 2)          # [[1, 2], [3, 4], [5]]

semver = js.require('semver')
semver.satisfies('1.2.3', '^1.0.0')  # True

js.destroy()                         # or: with cc_node.create() as js:

Unlike concurrent-c-python (in-process by default), every create() here is a separate Node — real addons, crash isolation, measurable wire. N domains = N processes.

this package CC hosted (cc_js_new(false, …))
API cc_node.create() .ccs program
Where child node libnode in-process
Hot call ~105µs RTT sub-µs (needs libnode)
Bulk shm (~9.5ms / 8MB) in-process
Parallelism N children one process
Crash child dies; parent lives shared fate
pip install concurrent-c-node          # needs node on PATH
python -m cc_node.examples.use_node
python -m cc_node.examples.bench_wire
python -m cc_node.benchmarks.multi_domain

Measured

bench_wire · cc_node_bridge_py_20260810.txt:

what result
spawn (first eval) 28ms
wire RTT 105µs
Python callback round trip 153µs
8MB array('d') via shm 9.5ms
same 8MB as JSON list 499ms (~52×)

Wire: line-JSON on dedicated fds (stdio stays yours). Bulk spill: private 0700 dir, 0600 files, removed with the bridge.

Surface

  • Plain data (numbers, str, bool, None, lists, non-empty dicts) by value; else a domain-owned handle (attrs, calls, str()String()). Non-finite floats are tagged.
  • Handles are per-domain. stats() / release() / idempotent destroy(); afterwards: bridge is closed.
  • Crash isolation, not a sandbox. destroy() is cooperative; an in-flight CPU-bound call finishes or you kill the child (bridge_stress.md).

Promises

Awaited in the child before the reply — no async/await on the Python side (opposite of concurrent-c-python isolated):

fetchish = js.eval('async (x) => { return { doubled: x * 2 } }')
fetchish(21)   # {'doubled': 42}

Callbacks

mapped = js.eval('(f) => [1, 2, 3].map(f)')(lambda x, *rest: x * 10)
# map passes (value, index, array) — take *rest

Exceptions cross both ways with messages intact.

Buffers

bytes / array.array / 1-D numpy → typed arrays (and back). Small inline; large via shm.

import array
total = js.eval('(a) => a.reduce((s, x) => s + x, 0)')
total(array.array('d', range(1_000_000)))

Common issues

Cannot find module. require / import resolve from the Python process cwd (node_modules next to your program), not from this wheel’s site-packages. npm install lodash in the project directory is the fix; or create(node=…) / CC_NODE_BIN when the wrong Node is on PATH.

Empty {} stays a handle

An empty object has to stay on the Node side — a materialized Python dict would lose later property use that matches Node. So js.eval('({})') returns a live handle:

o = js.eval('({})')                    # JsHandle, not {}
js.eval('(o) => { o.x = 1; return o.x }')(o)   # 1
js.eval('({a: 1})')                    # {'a': 1} — data return

Non-empty plain objects still cross as Python dicts. Same-domain handles chain (h.update(…).digest(…)).

Wire cost vs tiny work. Round trip is ~100µs; a one-line JS helper on three numbers loses to pure Python. Prefer Python (or a native CC module) for small/hot work; use the bridge when Node/npm owns the kernel. Multi-core: python -m cc_node.benchmarks.multi_domain (~2.8× on 3 domains here).

Choosing node

  1. create(node='/path/to/node')
  2. CC_NODE_BIN
  3. node on PATH

Packages: cwd node_modules, same as Node itself.

From Concurrent-C (not Python): cc_js_new(false, &a) hosted (libnode), or cc_js_new(true, &a) for this wire — jsdemo.shcc.

Publishing

PyPI Trusted Publishing (OIDC) — no API token:

  1. Publishing settings: owner sreekotay, repo concurrent-c, workflow publish-cc-node.yml, environment pypi
  2. GitHub Environment pypi
  3. Bump pyproject.toml, push, then:
gh workflow run publish-cc-node.yml

Both bridges (npm OIDC + PyPI OIDC):

./scripts/publish_bridges.sh --publish --minor
# fallbacks: --npm-local / --pypi-twine

Examples: use_node, bench_wire, benchmarks.multi_domain.
Stress: stress/bridge/.
Own hot path in C/CC → native module (40–90ns) — JS / Python interop.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

concurrent_c_node-0.17.5.tar.gz (16.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

concurrent_c_node-0.17.5-py3-none-any.whl (16.0 kB view details)

Uploaded Python 3

File details

Details for the file concurrent_c_node-0.17.5.tar.gz.

File metadata

  • Download URL: concurrent_c_node-0.17.5.tar.gz
  • Upload date:
  • Size: 16.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for concurrent_c_node-0.17.5.tar.gz
Algorithm Hash digest
SHA256 6e924cf7c1578baa85381b39c510be7789203fed0ecc21cca1c4550313cbd18b
MD5 26e073964e139f80ca28039a1f5442df
BLAKE2b-256 3fce5d38d682eafc669d10730d7aec6a3d3fde3a72831ff25ad3e854450b7b74

See more details on using hashes here.

Provenance

The following attestation bundles were made for concurrent_c_node-0.17.5.tar.gz:

Publisher: publish-cc-node.yml on sreekotay/concurrent-c

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file concurrent_c_node-0.17.5-py3-none-any.whl.

File metadata

File hashes

Hashes for concurrent_c_node-0.17.5-py3-none-any.whl
Algorithm Hash digest
SHA256 d0ba4b9756d41819122b89e2b866c911865bb8fdc3e7762fa7455e9d2dc619e5
MD5 d8df14b6bea5ec084c28413413f9555a
BLAKE2b-256 aeebf142733cb9314459eb16a45da3e67e2078ba73aa559bc1f2d9da1f5c08f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for concurrent_c_node-0.17.5-py3-none-any.whl:

Publisher: publish-cc-node.yml on sreekotay/concurrent-c

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.23.3

2 files

0.23.2

2 files

0.23.1

2 files

0.23.0

2 files

0.22.1

2 files

0.22.0

2 files

0.21.0

2 files

0.20.0

2 files

0.19.0

2 files

0.18.0

2 files

0.17.11

2 files

0.17.10

2 files

0.17.9

2 files

0.17.8

2 files

0.17.7

2 files

0.17.6

2 files

This release

0.17.5 This release

2 files

0.17.4

2 files

0.17.3

2 files

0.17.2

2 files

0.17.1

2 files

0.17.0

2 files

0.16.0

2 files

0.15.0

2 files

0.14.0

2 files

0.12.0

2 files

0.11.0

2 files

0.10.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page