Skip to main content

datalogic-py

PyPI CI License: Apache 2.0

Part of datalogic-rs: one engine, every runtime.

Python bindings for datalogic-rs, a Rust implementation of JSONLogic. Same rules, same semantics as the Rust crate, with the compile-once / evaluate-many pattern exposed natively: compile a rule once and evaluate it against thousands of data inputs without re-parsing. Every binding runs the same core and passes the same 2,128-case conformance battery (66 suites).

For the cross-runtime overview and the API-tier model every binding implements, see the repo README.

New in v5. There is no v4 Python package. If you called the v4 Rust crate or the v4 @goplasmatic/datalogic WASM package, see MIGRATION.md for the engine's v4 → v5 changes.

Install

pip install datalogic-py

PyPI carries pre-built wheels for:

Platform Architectures
Linux (manylinux) x86_64, aarch64
Linux (musllinux) x86_64, aarch64
macOS x86_64, arm64
Windows x86_64, arm64

The package supports Python 3.10 and newer through the PEP 384 stable ABI (abi3): one wheel per platform covers every CPython release from 3.10 on, and the package metadata lists 3.10 through 3.14.

Every wheel ships type stubs and a py.typed marker (PEP 561), so mypy, pyright and IDE autocomplete see the whole API.

The PyPI distribution is datalogic-py and the module is datalogic_py: pip install datalogic-py, then import datalogic_py. Python module names cannot contain hyphens.

Quick start

from datalogic_py import apply

result = apply(
    {"if": [{">": [{"var": "score"}, 50]}, "pass", "fail"]},
    {"score": 75},
)
# -> "pass"

API reference

The Python binding mirrors the Rust engine's API tier model; the API surface table below lists every tier.

One-shot: apply(rule, data)

from datalogic_py import apply

apply({"+": [1, 2, 3]}, {})                                # 6
apply({"var": "user.age"}, {"user": {"age": 25}})          # 25
apply({"and": [{">": [{"var": "x"}, 0]}, True]}, {"x": 5}) # True

Both arguments accept Python dict / list values. The binding walks them straight into the engine's arena values, with no JSON text and no intermediate tree, which beats a json.dumps → evaluate_str → json.loads round trip at every payload size the boundary benchmark measures. Conversion work scales with node count, so large payloads cost more (see Performance). If your data is already JSON text, call the *_str entry points (Rule.evaluate_str, Session.evaluate_str) and skip conversion; if you evaluate the same payload repeatedly, parse it once into a DataHandle. For payloads with types the walk doesn't cover, see Type conversion below.

Engine: Engine().eval(rule, data)

Construct an Engine when you need templating mode or any non-default configuration:

from datalogic_py import Engine

engine = Engine()                          # default config
engine.eval({"==": [1, 1]}, {})            # True

# Templating mode: multi-key objects become output templates
templating_engine = Engine(templating=True)
templating_engine.eval(
    {"name": {"var": "user.name"}, "ok": {">": [{"var": "score"}, 50]}},
    {"user": {"name": "Ada"}, "score": 99},
)
# {"name": "Ada", "ok": True}

Engine(...) takes keyword arguments only:

Argument Default Effect
templating False Multi-key objects compile as output templates (Templating mode)
config None Evaluation semantics, as a dict or JSON str (Engine configuration)
custom_operators None {name: callable} host operators (Custom operators)
strict_operator_names False Refuse a custom operator named like a built-in
template_key_escape None One character that marks a template key as a literal field
families None (every family) The operator families the engine has besides the JSONLogic core (Operator families)

Compile once: Engine().compile(rule) → Rule.evaluate(data)

Compile the rule once when you'll evaluate it against many data inputs.

from datalogic_py import Engine

engine = Engine()
rule = engine.compile({"if": [{">": [{"var": "score"}, 50]}, "pass", "fail"]})

for payload in batch:
    result = rule.evaluate(payload)         # accepts a dict
    fast   = rule.evaluate_str(json_text)   # accepts a JSON string (skips dict conversion)

Rule is thread-safe: hand the same instance to worker threads and evaluate concurrently. The binding releases the GIL for each Rust evaluate call, so a multi-threaded server runs evaluations in parallel. Compiling and check release it too, once the binding has read the rule into Rust.

compile_template(rule) and compile_strict(rule) choose the templating mode for one compile, whatever the engine was built with. The engine's custom operators, template key escape and families still apply. See Templating mode.

Checking a rule before it runs

compile accepts a rule that will fail at evaluation, such as one that calls an operator the engine doesn't have. check reports every problem the engine can see before the rule runs, each with an RFC 6901 JSON Pointer into the rule:

engine.check({"if": [True, {"vr": "x"}, {"map": [1]}]})
# [{"code": "UnknownOperator", "severity": "error", "pointer": "/if/1",
#   "message": "unknown operator `vr`; did you mean `var`?", "operator": "vr"},
#  {"code": "ArgumentCount", "severity": "error", "pointer": "/if/2",
#   "message": "`map` takes exactly 2 arguments, not 1", "operator": "map"}]

engine.check({"a": {"var": "x"}, "b": 1}, "template")   # [] (mode: "engine", "strict" or "template")

An "error" will fail; a "warning" runs but is probably a mistake (for example an argument the operator never evaluates). compile_checked(rule) compiles only a rule with no error diagnostic and otherwise raises CompileError, whose .diagnostics holds the same list:

from datalogic_py import CompileError

try:
    engine.compile_checked({"vr": "x"})
except CompileError as e:
    print(e.diagnostics[0]["code"])   # "UnknownOperator"

Three more calls describe rules and the engine without running anything:

rule = engine.compile({"if": [{">": [{"var": "user.age"}, 18]}, "adult", {"var": "fallback"}]})
rule.facts()
# {"reads": [["fallback"], ["user", "age"]], "computed_reads": False,
#  "reads_complete": True, "reads_data": True,
#  "operators": [">", "if", "val"], "custom_operators": [], "deterministic": True}

engine.operators()   # one dict per built-in operator: name, aliases, family, min_args, ...
engine.truthy({})    # False: the engine's truthiness (an empty dict is falsy, like [])
engine.truthy("[]")  # False: a str is JSON text

facts() lists each data path the rule reads as its segments, after the optimizer, so a folded branch is not listed. reads_complete is False when a path is computed at runtime or a custom operator runs, and deterministic is False for now and any custom operator. operators() returns a list in the schema of the operator catalogue.

Session: hot loops

For batches, open a Session: it keeps one arena and resets it at the start of each evaluate call, so steady-state evaluation reuses memory instead of allocating per call.

from datalogic_py import Engine

engine = Engine()
rule = engine.compile({"+": [{"var": "x"}, 1]})

with engine.session() as sess:
    for payload in batch:
        result = sess.evaluate(rule, payload)

Open one Session per worker thread: only the thread that created a session may call it. Engine and Rule are both thread-safe, so share those.

Data handles, typed results, and batch evaluation

The ABI v2 tiers. A DataHandle is an immutable, pre-parsed JSON document: parse a payload once and every evaluation against it skips JSON parsing and dict conversion. Handles are engine-independent (one handle can feed rules compiled by different engines), safe to share across threads for reads, and not consumed by evaluation; the binding frees the native memory when Python garbage-collects the handle.

from datalogic_py import DataHandle

data = DataHandle('{"age": 25, "status": "active"}')  # raises ParseError on bad JSON
data = DataHandle({"age": 25, "status": "active"})    # or any JSON-shaped value, copied once
data.allocated_bytes                    # bytes held by the handle's arena

rule.evaluate_data(data)                # thread-safe, like rule.evaluate
rule.evaluate_data_str(data)            # same, JSON str out
sess.evaluate_data(rule, data)          # hot path: session arena + no parse
sess.evaluate_data_str(rule, data)

For predicates and scalar results, the typed session evaluations skip the result conversion too:

ok = sess.evaluate_bool(rule, data)     # strict JSON boolean
n  = sess.evaluate_int(rule, data)      # exact integer result
f  = sess.evaluate_float(rule, data)    # any JSON number
t  = sess.evaluate_truthy(rule, data)   # JSONLogic truthiness, never mismatches

evaluate_bool, evaluate_int, and evaluate_float raise EvaluateError with error_type == "TypeMismatch" when the rule evaluates fine but the result is not of the requested type. A datetime or duration result counts as a string, the JSON type it serialises to, so the message reads result is not a boolean (got string). evaluate_truthy coerces any result through the engine's configured truthiness rules (the same coercion if/and/or apply).

The batch entry points evaluate a whole set in one native call and report failures per item, so one bad input leaves its neighbours unaffected:

from datalogic_py import BatchItemError

# One rule, many payloads:
results = sess.evaluate_batch(rule, [d0, d1, d2])
# Many rules, one payload (the rule-set / feature-flag shape):
results = sess.evaluate_many([r0, r1], data)

for i, r in enumerate(results):
    if isinstance(r, BatchItemError):   # not raised; a result object
        print(f"item {i} failed: {r.message} ({r.tag}, operator={r.operator})")
    else:
        print(f"item {i}: {r}")         # the item's JSON string

Typed and batch evaluations take data handles only, and sessions stay single-threaded. A typed call or evaluate_batch raises EvaluateError with error_type == "InvalidArgument" when the rule was compiled by a different engine than the session's; evaluate_many reports such a rule as its item's BatchItemError (tag == "InvalidArgument") and evaluates the rest.

API surface

Tier Entry point Use when
One-shot apply(rule, data) Ad-hoc evaluation, one rule + one data shape
Engine Engine().eval(rule, data) Custom configuration (templating, custom operators, config)
Compile once Engine().compile(rule).evaluate(data) Same rule evaluated against many data inputs
Compile mode engine.compile_template(rule) / engine.compile_strict(rule) One rule in a templating mode other than the engine's
Checked engine.check(rule, mode=None) / engine.compile_checked(rule) Find every problem in a rule before it runs
Introspection rule.facts() / engine.operators() / engine.truthy(value) What a rule reads, which operators exist, the engine's truthiness
Session with engine.session() as sess: … Hot loops: reuse one arena across evaluations
Data handle DataHandle(json or value) → sess.evaluate_data(rule, data) Same payload evaluated many times: parse or convert once, zero work per call
Typed sess.evaluate_bool/int/float/truthy(rule, data) Predicates and scalar results, no JSON decode on the way out
Batch sess.evaluate_batch(rule, datas) / sess.evaluate_many(rules, data) Many evaluations per native call, per-item errors
Metered engine.eval_metered(rule, data, budget=None) / rule.evaluate_metered(data, budget=None) The operations an evaluation charges, optionally capped
Traced engine.evaluate_with_trace(logic_json, data_json, mode=None) Step-by-step debugging; feeds the React debugger

datalogic_py.__version__ reports the installed version.

Custom operators

Pass custom_operators={"name": callable} to Engine(...). Each callable receives the operator's pre-evaluated arguments as a JSON-array string and returns a JSON string of the result:

import json
from datalogic_py import Engine

engine = Engine(custom_operators={
    "double": lambda args_json: json.dumps(json.loads(args_json)[0] * 2),
})
engine.eval_str('{"double": [21]}', '{}')  # "42"

Built-ins win: a custom registration of a built-in name (+, if, var, ...) never dispatches. With strict_operator_names=True the engine refuses such a name instead: Engine(...) raises EvaluateError with error_type == "ConfigurationError". The option also refuses a name that begins with the template key escape. A name whose family you leave out with families is free for a custom operator. Callbacks run with the GIL held.

Engine configuration

Pass config= to Engine(...) to change evaluation semantics. The value is a dict (or a JSON string) with an optional preset plus per-field overrides. Unknown keys and values raise EvaluateError with error_type == "ConfigurationError":

from datalogic_py import Engine, EvaluateError

strict = Engine(config={"preset": "strict"})
try:
    strict.eval({"+": ["", 1]}, {})   # strict rejects non-numeric coercion
except EvaluateError as e:
    print(e.error_type)               # "Thrown" (a NaN payload)

lenient = Engine(config={"division_by_zero": "return_null"})
lenient.eval({"/": [1.5, 0]}, {})     # None
Key Values
preset "default", "safe_arithmetic", "strict"
arithmetic_nan_handling "throw_error", "ignore_value", "coerce_to_zero", "return_null"
division_by_zero "return_saturated", "throw_error", "return_null", "return_infinity"
loose_equality_errors bool
missing_var "null" (default: a missing variable reads as null), "error" (raises VariableNotFound)
truthy_evaluator "javascript", "python", "strict_boolean"
numeric_coercion object of bools: empty_string_to_zero, null_to_zero, bool_to_number, reject_non_numeric
max_recursion_depth integer >= 1
ops_budget integer >= 1, or null for unbounded (caps the work one evaluation may do; crossing it raises BudgetExceeded)

The preset applies first; the remaining keys override individual fields on top of it. Every binding parses this JSON with the same core code, so a config that works here works in every other binding. The Rust crate's EvaluationConfig documents the full semantics of each knob.

"missing_var": "error" turns a typo in a path into an error instead of a None that flows on. A default ({"var": ["x", 0]}), a present null, missing, missing_some and exists are not misses, and try catches the error:

engine = Engine(config={"missing_var": "error"})
engine.eval({"var": "user.nmae"}, {"user": {"name": "Ada"}})
# EvaluateError: Variable not found: user.nmae (error_type "VariableNotFound")
engine.eval({"var": ["user.nmae", "anon"]}, {"user": {"name": "Ada"}})   # "anon"

Operator families

families=[...] keeps the engine to the JSONLogic core plus the families you name, using the family names of engine.operators(): "ExtString", "ExtArray", "ExtObject", "ExtMath", "ExtControl", "ErrorHandling", "DateTime", "Tensor", "Flagd" ("Core" is always there). A family you leave out is not there for that engine: its names compile as unknown operators, which fail at evaluation with InvalidOperator (and are errors in check and compile_checked), and a custom operator may take them. An unknown family name raises EvaluateError with error_type == "ConfigurationError".

strings_only = Engine(families=["ExtString"])
strings_only.eval({"upper": "abc"}, None)   # "ABC"
strings_only.eval({"abs": -1}, None)        # EvaluateError, error_type "InvalidOperator"

Metering: what a rule costs

eval_metered returns (result_json, ops): the result as a JSON str and the operations the evaluation charged, so you can see what a rule costs whether or not a budget is set. Rule.evaluate_metered(data, budget=None) does the same on an already-compiled rule.

engine = Engine()
engine.eval_metered({"map": [{"var": "xs"}, {"*": [{"var": ""}, 2]}]}, {"xs": [1, 2, 3]})
# ('[2,4,6]', 10)

# The optional `budget` argument caps the operations for that one call,
# overriding the engine's `ops_budget` config key.
engine.eval_metered(rule, data, budget=100_000)

One operation is one node the engine dispatches, one item an iterator walks, or whatever an operator charges for the data it moves (the tensor family prices itself in elements). Literals and constant-folded subtrees cost nothing. The count is deterministic for a given rule, data and engine version. Exceeding the budget raises EvaluateError with .error_type == "BudgetExceeded", carrying .budget and .spent. The engine refuses the evaluation before doing the work, and a try in the rule cannot recover from it. A budget of 0 raises EvaluateError with error_type == "InvalidArgument"; pass None for the engine's own budget.

Error handling

All exceptions descend from DataLogicError:

Exception When
ParseError Malformed rule or data JSON, or an unsupported Python type in the input
EvaluateError Every other engine failure: runtime operator errors, unknown operators (InvalidOperator), invalid configuration (ConfigurationError)
CompileError compile_checked refused the rule; .diagnostics lists every problem and error_type is "CompileError"

Every exception carries .error_type (the engine's error tag), .operator (the innermost failing operator, or None), .node_ids (a leaf-to-root breadcrumb of compiled-node ids) and .path (a root-to-leaf list of step dicts with node_id, operator, arg_index and json_pointer, or None when no compiled rule was in scope).

Two error_type tags come from the binding itself rather than the engine, as in the C ABI: "TypeMismatch" (a typed evaluation whose result has the wrong type) and "InvalidArgument" (for example a rule compiled by a different engine passed to a session's handle-based entry points). Per-item batch failures don't raise; they surface as BatchItemError values (.tag, .message, .operator) in the result list.

from datalogic_py import Engine, EvaluateError

engine = Engine()
try:
    engine.eval({"+": [1, {"*": ["x", 2]}]}, {})  # arithmetic on a non-numeric string
except EvaluateError as e:
    print(e.error_type)  # "Thrown" (a NaN payload under the default config)
    print(e.operator)    # "*", the innermost operator that failed
    print(e.path)        # [{"operator": "+", "json_pointer": "", ...},
                         #  {"operator": "*", "json_pointer": "/+/1", ...}]

Threading

Type Pattern
Engine Build once; share across threads
Rule Compile once; share across threads: evaluate releases the GIL for parallelism
Session One per worker thread; only its creating thread may call it
DataHandle Parse once; immutable, share across threads for reads (evaluation never mutates it)

Type conversion

The dict-input path walks Python objects into the engine's arena representation, with a pythonize fallback for the shapes the walk doesn't cover. Both give the same results; only speed differs.

Fast direct walk: dict, list, tuple, str, int, float, bool, None.

Handled by the fallback: set/frozenset (become JSON arrays, in iteration order), container and scalar subclasses (IntEnum, OrderedDict, …), mappings and dataclasses.

Conversion details:

  • float('nan') / float('inf') become JSON null (they have no JSON encoding)
  • ints above 2^63 - 1 up to 2^64 - 1 become float; larger ones raise ParseError
  • dict keys must be str (anything else raises ParseError), and the engine sees object keys in sorted order, so object-iteration results are deterministic
  • result dicts come back key-sorted
  • a datetime or duration result comes back as a string

Not supported. These raise ParseError:

  • datetime.datetime, datetime.date: convert to ISO string at the Python edge
  • decimal.Decimal: convert to float or str
  • bytes, bytearray

For payloads with exotic types, use rule.evaluate_str(json_text) and bring your own JSON encoder (for example with default=str).

Templating mode

In templating mode a multi-key object is an output template and an unknown key an output field. Engine(templating=True) sets the mode for every compile on that engine; compile_template and compile_strict set it for one compile, so one engine can check a condition strictly and build an output template:

engine = Engine()
engine.compile({"user": {"var": "name"}, "source": "api"})   # raises EvaluateError ("InvalidOperator")
engine.compile_template({"user": {"var": "name"}, "source": "api"}).evaluate({"name": "ana"})
# {"source": "api", "user": "ana"}

To emit a key that is also an operator name, set template_key_escape to one character; a key that starts with it becomes a literal field with the character stripped:

engine = Engine(templating=True, template_key_escape="$")
engine.eval({"$type": "user", "id": {"var": "id"}}, {"id": 7})
# {"id": 7, "type": "user"}

Execution tracing

Engine.evaluate_with_trace(logic, data, mode=None) evaluates with step-by-step tracing and returns a JSON string envelope. The shape is identical to the WASM binding's evaluateWithTrace, so the React debugger component can consume it:

import json
from datalogic_py import Engine

engine = Engine()
trace = json.loads(engine.evaluate_with_trace(
    '{">": [{"var": "score"}, 50]}',
    '{"score": 75}',
))
trace["result"]           # True
trace["expression_tree"]  # {"id", "expression", "children"} tree
trace["steps"]            # per-node execution log, in evaluation order
trace["pointers"]         # {"<node id>": "<JSON Pointer into the rule>", ...}

Both arguments are JSON strings. mode is "engine" (the default), "strict" or "template", so you can trace a rule you compile with compile_template. Runtime failures do not raise: the envelope carries an error message and a structured_error object instead, alongside the steps recorded up to the failure. pointers maps each node id to the JSON Pointer of the rule value it was compiled from, and is absent when the rule does not compile. The result keeps the key order the rule produced. Tracing skips the optimizer so every operator in the rule appears in the trace; use it for debugging, not hot paths.

Performance

Geomean across 51 operator benchmark suites (Apple M2 Pro, median of 3 runs; pairwise shared-suite ratios per the methodology): the native Rust core evaluates at 10.3 ns/op, 7.0× faster than json-logic-engine (compiled, the fastest JS engine), 28.1× faster than jsonlogic-rs (the closest Rust alternative), and 83.6× faster than the json-logic-js reference implementation. The WASM build under Node measures 900.5 ns geomean (88× native); on Node servers, prefer @goplasmatic/datalogic-node.

The pyo3 boundary adds a per-call marshalling cost on top of the core numbers; the dict paths use direct Python ↔ arena walks, so that cost scales with payload node count. Use rule.evaluate_str(json_text) when you already have a JSON string, and a DataHandle when you evaluate the same payload repeatedly. On the boundary harness's 8 KB workload, session.evaluate_data_str measures about 1.4 µs/op against about 12 µs for session.evaluate_str (the per-call JSON parse) and about 25 µs for the dict path (the per-call conversion walk). Every evaluate call releases the GIL, so a multi-threaded server runs evaluations in parallel.

Building from source

The binding lives in bindings/python/ and builds with maturin (needs a Rust toolchain and Python 3.10+):

git clone https://github.com/GoPlasmatic/datalogic-rs
cd datalogic-rs/bindings/python
python -m venv .venv && source .venv/bin/activate
pip install maturin pytest
maturin develop --release   # build + install into the venv
pytest                      # run the test suite

Learn more

License

Apache-2.0. See the main repository for source and contribution guidelines.

Metadata

Release files for datalogic-py 5.8.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for datalogic-py 5.8.1
File Size Uploaded
datalogic_py-5.8.1.tar.gz 662.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for datalogic-py 5.8.1
File
datalogic_py-5.8.1-cp310-abi3-win_arm64.whl CPython 3.10 abi3 Windows ARM64 Details
datalogic_py-5.8.1-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
datalogic_py-5.8.1-cp310-abi3-musllinux_1_2_x86_64.whl CPython 3.10 abi3 Linux musl 1.2+ x86-64 Details
datalogic_py-5.8.1-cp310-abi3-musllinux_1_2_aarch64.whl CPython 3.10 abi3 Linux musl 1.2+ ARM64 Details
datalogic_py-5.8.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
datalogic_py-5.8.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
datalogic_py-5.8.1-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
datalogic_py-5.8.1-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 20.4 MB

Release files / datalogic_py-5.8.1.tar.gz

Download URL datalogic_py-5.8.1.tar.gz
Size 662.4 kB
Tags Source
SHA-256 checksum
How to use checksums
6aad0baca9fe519634263a138b7f4c5557f18a0e623e33711c1221762251beb3
BLAKE2b-256 checksum
How to use checksums
d938776b4c7cbd436ce21a524828bc25ff34b37ea30bfe8d81a84e9a5afe024f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / datalogic_py-5.8.1-cp310-abi3-win_arm64.whl

Download URL datalogic_py-5.8.1-cp310-abi3-win_arm64.whl
Size 2.2 MB
Tags CPython 3.10 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
82e81799053f13f1f2c9aee6d18b4c4d60585617936658651e2cc255952aa7d3
BLAKE2b-256 checksum
How to use checksums
91c92f87c41cf3cf1101b6744e6d60d776ef12ec77d6f2d7e575c0ee221eca8b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / datalogic_py-5.8.1-cp310-abi3-win_amd64.whl

Download URL datalogic_py-5.8.1-cp310-abi3-win_amd64.whl
Size 2.7 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
af5ba4631a9cb901a5d9283d14f3993930766c540d0a11f3533ad4156f9d3cb5
BLAKE2b-256 checksum
How to use checksums
0b5b85022eeabd9453ee33388005d7e1028945759f8bf2ee1b6e06753dc5c3ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / datalogic_py-5.8.1-cp310-abi3-musllinux_1_2_x86_64.whl

Download URL datalogic_py-5.8.1-cp310-abi3-musllinux_1_2_x86_64.whl
Size 2.9 MB
Tags CPython 3.10 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
c322de360b65427c198ec3c18b129cffcc35a79564775dba941f472ab26cf7a4
BLAKE2b-256 checksum
How to use checksums
cfc4ab19157dee95b6277eb3b716dbf5fb25fc6c8e3783c30a06864deba2beea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / datalogic_py-5.8.1-cp310-abi3-musllinux_1_2_aarch64.whl

Download URL datalogic_py-5.8.1-cp310-abi3-musllinux_1_2_aarch64.whl
Size 2.4 MB
Tags CPython 3.10 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
ec6c249e59c6c0ab22bdb61a0d406e8e7322ed071eb16d46657023bda4a5e80b
BLAKE2b-256 checksum
How to use checksums
53abc3b34ceba0946ca3c367b74ecb1474b556b1cd6c165a76ce4df1a75026f0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / datalogic_py-5.8.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL datalogic_py-5.8.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.7 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
e777a9089087bee0a619067cba23306272788d82c1871ca6a8635282f85b0b39
BLAKE2b-256 checksum
How to use checksums
f858a4fc2614b51099b2517ca3c53dd45afa61de9bd5443b48201ece3df052ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / datalogic_py-5.8.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL datalogic_py-5.8.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 2.2 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
71d957877bc99bd354533adbd845b83f33f86bb0b1a2f1878b1d38bf4f8be7af
BLAKE2b-256 checksum
How to use checksums
55ac65dd1ab0b9ff4582e9bd02de8f5929b6f40c758ed64b14b3e782489cf80a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / datalogic_py-5.8.1-cp310-abi3-macosx_11_0_arm64.whl

Download URL datalogic_py-5.8.1-cp310-abi3-macosx_11_0_arm64.whl
Size 2.1 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
07772127c79ff255943fbd9443fd600ab07c26ce4393dbdd62a46abc14bd7602
BLAKE2b-256 checksum
How to use checksums
a00cbe55ceee22f1d9cfe092e3194bbfc0440c0c46ad0948b6268c5c8d5f4dc5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / datalogic_py-5.8.1-cp310-abi3-macosx_10_12_x86_64.whl

Download URL datalogic_py-5.8.1-cp310-abi3-macosx_10_12_x86_64.whl
Size 2.6 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
7d03dd2dcfd1c986effedd363f242c1778e3ba0149b518d669c765bccf8da47b
BLAKE2b-256 checksum
How to use checksums
84cc78f36c4335f832de989c5cb8a3580e0b572c2a2e8a4a7677551e3563b6b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

5.8.1 This release

9 release files

5.8.0

9 release files

5.7.1

9 release files

5.7.0

9 release files

5.6.0

9 release files

5.5.0

9 release files

5.4.0

9 release files

5.3.0

9 release files

5.2.0

9 release files

5.1.1

9 release files

5.1.0

9 release files

5.0.1

9 release files

5.0.0

8 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page