Skip to main content

Hybrid SPARQL query engine for timeseries data

Project description

chrontext: High-performance hybrid query engine for knowledge graphs and analytical data (e.g. time-series)

Chrontext allows you to use your knowledge graph to access large amounts of time-series or other analytical data. It uses a commodity SPARQL Triplestore and your existing data storage infrastructure. It currently supports time-series stored in a PostgreSQL-compatible Database such as DuckDB, Google Cloud BigQuery (SQL) and OPC UA HA, but can easily be extended to other APIs and databases. Chrontext Architecture

Chrontext forms a semantic layer that allows self-service data access, abstracting away technical infrastructure. Users can create query-based inputs for data products, that maintains these data products as the knowledge graph is maintained, and that can be deployed across heterogeneous on-premise and cloud infrastructures with the same API.

Chrontext is a high-performance Python library built in Rust using Polars, and relies heavily on packages from the Oxigraph project. Chrontext works with Apache Arrow, prefers time-series transport using Apache Arrow Flight and delivers results as Polars DataFrames.

Please reach out to Data Treehouse if you would like help trying Chrontext, or require support for a different database backend.

Installing

Chrontext is in pip, just use:

pip install chrontext

The API is documented HERE.

Example query in Python

The code assumes that we have a SPARQL-endpoint and BigQuery set up with time-series.

...
q = """
PREFIX xsd:<http://www.w3.org/2001/XMLSchema#>
PREFIX ct:<https://github.com/DataTreehouse/chrontext#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> 
PREFIX rds: <https://github.com/DataTreehouse/solar_demo/rds_power#> 
SELECT ?path ?t ?ts_pow_value ?ts_irr_value
WHERE {
    ?site a rds:Site;
    rdfs:label "Jonathanland";
    rds:functionalAspect ?block.
    # At the Block level there is an irradiation measurement:
    ?block a rds:A;
    ct:hasTimeseries ?ts_irr.
    ?ts_irr rdfs:label "RefCell1_Wm2".
    
    # At the Inverter level, there is a Power measurement
    ?block rds:functionalAspect+ ?inv.
    ?inv a rds:TBB;
    rds:path ?path;
    ct:hasTimeseries ?ts_pow.
    ?ts_pow rdfs:label "InvPDC_kW".
    
    ?ts_pow ct:hasDataPoint ?ts_pow_datapoint.
    ?ts_pow_datapoint ct:hasValue ?ts_pow_value;
        ct:hasTimestamp ?t.
    ?ts_irr ct:hasDataPoint ?ts_irr_datapoint.
    ?ts_irr_datapoint ct:hasValue ?ts_irr_value;
        ct:hasTimestamp ?t.
    FILTER(
        ?t >= "2018-08-24T12:00:00+00:00"^^xsd:dateTime && 
        ?t <= "2018-08-24T13:00:00+00:00"^^xsd:dateTime)
} ORDER BY ?path ?t 
"""
df = engine.query(q)

This produces the following DataFrame:

path t ts_pow_value ts_irr_value
str datetime[ns, UTC] f64 f64
=.A1.RG1.TBB1 2018-08-24 12:00:00 UTC 39.74 184.0
=.A1.RG1.TBB1 2018-08-24 12:00:01 UTC 39.57 184.0
=.A1.RG1.TBB1 2018-08-24 12:00:02 UTC 40.1 184.0
=.A1.RG1.TBB1 2018-08-24 12:00:03 UTC 40.05 184.0
=.A1.RG1.TBB1 2018-08-24 12:00:04 UTC 40.02 184.0
=.A5.RG9.TBB1 2018-08-24 12:59:56 UTC 105.5 427.5
=.A5.RG9.TBB1 2018-08-24 12:59:57 UTC 104.9 427.6
=.A5.RG9.TBB1 2018-08-24 12:59:58 UTC 105.6 428.0
=.A5.RG9.TBB1 2018-08-24 12:59:59 UTC 105.9 428.0
=.A5.RG9.TBB1 2018-08-24 13:00:00 UTC 105.7 428.5

API

The API is documented HERE.

Tutorial using DuckDB

In the following tutorial, we assume that you have a couple of CSV-files on disk that you want to query. We assume that you have DuckDB and chrontext installed, if not, do pip install chrontext duckdb. Installing chrontext will also install sqlalchemy, which we rely on to define the virtualized DuckDB tables.

CSV files

Our csv files look like this.

ts1.csv :

timestamp,value
2022-06-01T08:46:52,1
2022-06-01T08:46:53,10
..
2022-06-01T08:46:59,105

ts2.csv:

timestamp,value
2022-06-01T08:46:52,2
2022-06-01T08:46:53,20
...
2022-06-01T08:46:59,206

DuckDB setup:

We need to create a class with a method query that takes a SQL string its argument, returning a Polars DataFrame. In this class, we just hard code the DuckDB setup in the constructor.

import duckdb
import polars as pl

class MyDuckDB():
    def __init__(self):
        con = duckdb.connect()
        con.execute("SET TIME ZONE 'UTC';")
        con.execute("""CREATE TABLE ts1 ("timestamp" TIMESTAMPTZ, "value" INTEGER)""")
        ts_1 = pl.read_csv("ts1.csv", try_parse_dates=True).with_columns(pl.col("timestamp").dt.replace_time_zone("UTC"))
        con.append("ts1", df=ts_1.to_pandas())
        con.execute("""CREATE TABLE ts2 ("timestamp" TIMESTAMPTZ, "value" INTEGER)""")
        ts_2 = pl.read_csv("ts2.csv", try_parse_dates=True).with_columns(pl.col("timestamp").dt.replace_time_zone("UTC"))
        con.append("ts2", df=ts_2.to_pandas())
        self.con = con


    def query(self, sql:str) -> pl.DataFrame:
        # We execute the query and return it as a Polars DataFrame.
        # Chrontext expects this method to exist in the provided class.
        df = self.con.execute(sql).pl()
        return df

my_db = MyDuckDB()

Defining a virtualized SQL

We first define a sqlalchemy select query involving the two tables. It is crucial that we have a column labelled "id" here. Chrontext will modify this query when executing hybrid queries.

from sqlalchemy import MetaData, Table, Column, bindparam
metadata = MetaData()
ts1_table = Table(
    "ts1",
    metadata,
    Column("timestamp"),
    Column("value")
)
ts2_table = Table(
    "ts2",
    metadata,
    Column("timestamp"),
    Column("value")
)
ts1 = ts1_table.select().add_columns(
    bindparam("id1", "ts1").label("id"),
)
ts2 = ts2_table.select().add_columns(
    bindparam("id2", "ts2").label("id"),
)
sql = ts1.union(ts2)

Now, we are ready to define the virtualized backend. We will annotate nodes of the graph with a resource data property. These data properties will be linked to virtualized RDF triples in the DuckDB backend. The resource_sql_map decides which SQL is used for each resource property.

from chrontext import VirtualizedPythonDatabase

vdb = VirtualizedPythonDatabase(
    database=my_db,
    resource_sql_map={"my_resource": sql},
    sql_dialect="postgres"
)

The triple below will link the ex:myWidget1 to triples defined by the above sql.

ex:myWidget1 ct:hasResource "my_resource" . 

However, it will only be linked to those triples corresponding to rows where the identifier column equals the identifier associated with ex:myWidget1. Below, we define that ex:instanceA is only linked to those rows where the id column is ts1.

ex:myWidget1 ct:hasIdentifier "ts1" . 

In any such resource sql, the id column is mandatory.

Relating the Database to RDF Triples

Next, we want to relate the rows in this sql, each containing id, timestamp, value to RDF triples, using a template. It is crucial to have the column id.

from chrontext import Prefix, Variable, Template, Parameter, RDFType, Triple, XSD
ct = Prefix("ct", "https://github.com/DataTreehouse/chrontext#")
xsd = XSD()
id = Variable("id")
timestamp = Variable("timestamp")
value = Variable("value")
dp = Variable("dp")
resources = {
    "my_resource": Template(
        iri=ct.suf("my_resource"),
        parameters=[
            Parameter(id, rdf_type=RDFType.Literal(xsd.string)),
            Parameter(timestamp, rdf_type=RDFType.Literal(xsd.dateTime)),
            Parameter(value, rdf_type=RDFType.Literal(xsd.double)),
        ],
        instances=[
            Triple(id, ct.suf("hasDataPoint"), dp),
            Triple(dp, ct.suf("hasValue"), value),
            Triple(dp, ct.suf("hasTimestamp"), timestamp)
        ]
)}

This means that our instance ex:myWidget1, will be associated with a value and a timestamp (and a blank data point) for each row in ts1.csv. For instance, the first row means we have:

ex:widget1 ct:hasDataPoint _:b1 .
_:b1 ct:hasTimestamp "2022-06-01T08:46:52Z"^^xsd:dateTime .
_:b1 ct:hasValue 1 .

Chrontext is created for those cases when this is infeasibly many triples, so we do not want to materialize them, but query them.

Creating the engine and querying:

The context for our analytical data (e.g. a model of an industrial asset) has to be stored in a SPARQL endpoint. In this case, we use an embedded Oxigraph engine that comes with chrontext. Now we assemble the pieces and create the engine.

from chrontext import Engine, SparqlEmbeddedOxigraph
oxigraph_store = SparqlEmbeddedOxigraph(rdf_file="my_graph.ttl", path="oxigraph_db_tutorial")
engine = Engine(
    resources,
    virtualized_python_database=vdb,
    sparql_embedded_oxigraph=oxigraph_store)
engine.init()

Now we can use our context to query the dataset. The aggregation below are pushed into DuckDB. The example below is a bit simple, but complex conditions can identify the ?w and ?s.

q = """
    PREFIX xsd:<http://www.w3.org/2001/XMLSchema#>
    PREFIX chrontext:<https://github.com/DataTreehouse/chrontext#>
    PREFIX types:<http://example.org/types#>
    SELECT ?w (SUM(?v) as ?sum_v) WHERE {
        ?w types:hasSensor ?s .
        ?s a types:ThingCounter .
        ?s chrontext:hasTimeseries ?ts .
        ?ts chrontext:hasDataPoint ?dp .
        ?dp chrontext:hasTimestamp ?t .
        ?dp chrontext:hasValue ?v .
        FILTER(?t > "2022-06-01T08:46:53Z"^^xsd:dateTime) .
    } GROUP BY ?w
    """
df = engine.query(q)
print(df)

This produces the following result:

w sum_v
str decimal[38,0]
http://example.org/case#myWidget1 1215
http://example.org/case#myWidget2 1216

Roadmap in brief

Let us know if you have suggestions!

Stabilization

Chrontext will be put into use in the energy industry during the period, and will be stabilized as part of this process. We are very interested in your bug reports!

Support for Azure Data Explorer / KustoQL

We are likely adding support for ADX/KustoQL. Let us know if this is something that would be useful for you.

Support for Databricks SQL

We are likely adding support for Databricks SQL as the virtualization backend.

Generalization to analytical data (not just time series!)

While chrontext is currently focused on time series data, we are incrementally adding support for contextualization of arbitrary analytical data.

Support for multiple databases

Currently, we only support one database backend at a given time. We plan to support hybrid queries across multiple virtualized databases.

References

Chrontext is joint work by Magnus Bakken and Professor Ahmet Soylu at OsloMet. To read more about Chrontext, read the article Chrontext: Portable Sparql Queries Over Contextualised Time Series Data in Industrial Settings.

License

All code produced since August 1st. 2023 is copyrighted to Data Treehouse AS with an Apache 2.0 license unless otherwise noted.

All code which was produced before August 1st. 2023 copyrighted to Prediktor AS with an Apache 2.0 license unless otherwise noted, and has been financed by The Research Council of Norway (grant no. 316656) and Prediktor AS as part of a PhD Degree. The code at this state is archived in the repository at https://github.com/DataTreehouse/chrontext.

Project details


Download files

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

Source Distribution

chrontext-0.9.10.tar.gz (193.3 kB view details)

Uploaded Source

Built Distributions

chrontext-0.9.10-cp312-cp312-manylinux_2_28_x86_64.whl (32.2 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.28+ x86-64

chrontext-0.9.10-cp311-none-win_amd64.whl (26.7 MB view details)

Uploaded CPython 3.11 Windows x86-64

chrontext-0.9.10-cp311-cp311-manylinux_2_28_x86_64.whl (32.2 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.28+ x86-64

chrontext-0.9.10-cp311-cp311-macosx_12_0_arm64.whl (27.2 MB view details)

Uploaded CPython 3.11 macOS 12.0+ ARM64

chrontext-0.9.10-cp311-cp311-macosx_11_0_arm64.whl (27.2 MB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

chrontext-0.9.10-cp310-none-win_amd64.whl (26.7 MB view details)

Uploaded CPython 3.10 Windows x86-64

chrontext-0.9.10-cp310-cp310-manylinux_2_28_x86_64.whl (32.2 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.28+ x86-64

chrontext-0.9.10-cp310-cp310-macosx_12_0_arm64.whl (27.2 MB view details)

Uploaded CPython 3.10 macOS 12.0+ ARM64

chrontext-0.9.10-cp310-cp310-macosx_11_0_arm64.whl (27.2 MB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

chrontext-0.9.10-cp39-none-win_amd64.whl (26.7 MB view details)

Uploaded CPython 3.9 Windows x86-64

chrontext-0.9.10-cp39-cp39-manylinux_2_28_x86_64.whl (32.2 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.28+ x86-64

chrontext-0.9.10-cp39-cp39-macosx_12_0_arm64.whl (27.2 MB view details)

Uploaded CPython 3.9 macOS 12.0+ ARM64

chrontext-0.9.10-cp39-cp39-macosx_11_0_arm64.whl (27.2 MB view details)

Uploaded CPython 3.9 macOS 11.0+ ARM64

chrontext-0.9.10-cp38-none-win_amd64.whl (26.7 MB view details)

Uploaded CPython 3.8 Windows x86-64

chrontext-0.9.10-cp38-cp38-manylinux_2_28_x86_64.whl (32.2 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.28+ x86-64

chrontext-0.9.10-cp38-cp38-macosx_12_0_arm64.whl (27.2 MB view details)

Uploaded CPython 3.8 macOS 12.0+ ARM64

chrontext-0.9.10-cp38-cp38-macosx_11_0_arm64.whl (27.2 MB view details)

Uploaded CPython 3.8 macOS 11.0+ ARM64

File details

Details for the file chrontext-0.9.10.tar.gz.

File metadata

  • Download URL: chrontext-0.9.10.tar.gz
  • Upload date:
  • Size: 193.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.7.1

File hashes

Hashes for chrontext-0.9.10.tar.gz
Algorithm Hash digest
SHA256 2af663e5e9eff9f8f9c09a06eccaae189b151d350a8fa6f6382f7497edf3ce5e
MD5 8aa966468bbe90e26ade8083fabaa266
BLAKE2b-256 cb01968a9f7bb5206c1f49e79ef3bd8ffc3647faab9989db8c4d34a4dedd48fc

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ab309919134bd8c34e9ebe8e4a9c0978dec0478eb4b8ef3865e3d7341b61d4fd
MD5 41af8fbd3495a0aebb82b247a09b8a78
BLAKE2b-256 45550052b6a036b8eee46ba2e717fb22cb562a12b191fb72a1b2a73efaa8d2a9

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp311-none-win_amd64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp311-none-win_amd64.whl
Algorithm Hash digest
SHA256 31b885ac389a5b08f6741f748b7b66f44fa65d7bcf4f333b0fa3ba0d8fea439c
MD5 b965c8c86baf4d9e26c2228ae01a6f0c
BLAKE2b-256 aeecae04ea7476547a179f023002c1ae4fb1a989fdc11351ab74f09bfb7bb7f6

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 61fdd38a14e0ae4f1270274fe5848b05b64d7a8c64dbd5444b0d96a1b52f2c67
MD5 8e086039d4cc7aed651eae55f2c1105c
BLAKE2b-256 96bf481b4b28e6f81e413f462e30d14fdc4901e97d229dd2fd4204c40bbd0519

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp311-cp311-macosx_12_0_arm64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp311-cp311-macosx_12_0_arm64.whl
Algorithm Hash digest
SHA256 751ef35d5dad99f02e54f78a98ed26c56f697431d32c381d0b90d2b578578d37
MD5 bafa111c1260bbda894850a798b414cc
BLAKE2b-256 5c3eb948eb22e3e4626c78cffffe8677b9066299577de9e944fb8432aa334a43

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f17a69f9b63ae7d65b74d6a1c7b6e4a846cea90ce72f600320c68a3aa5f8bcd5
MD5 e60209b2abf59ba5e1cd07b356f2ec74
BLAKE2b-256 1fd90ef0db8a0b24e6bba6c222a2ba16bcc89871e80a50062cd21ea50ea6947a

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp310-none-win_amd64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp310-none-win_amd64.whl
Algorithm Hash digest
SHA256 5dd62af3ce6f6d7dd30a2efc30030dbb99eff154242b75d6d37492616c196077
MD5 b456a79747348400296ee04af0a0dc35
BLAKE2b-256 cddbcaa91b6aa0bd40bade16774e8a7ee9ba22a4a61e60daac5238b675411f38

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e13cb7671d69696994a77b11f5252da27d8d9ef14b40e68215358d26ad03f914
MD5 be6f25a5c13d4c122fdb8819bf6c1bb2
BLAKE2b-256 ac7e9fc11eed7ef556636e162b3bbbc3295d2599e69c8dad7eeab4d8892a380e

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp310-cp310-macosx_12_0_arm64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp310-cp310-macosx_12_0_arm64.whl
Algorithm Hash digest
SHA256 823b9c69363783478558072310bcbb0e0ecdf3abc738be9447b11304b99268a9
MD5 1af9146e3176206554129d5b74683446
BLAKE2b-256 aab4e664402a02b05eb299a4a23ac54d17d7b121e0e2fbb475dd5ccbb9ea4b12

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 167216dee8451769e7600a9efb9833834581c912915a6fc2ddabe0bb1adc4364
MD5 8511e3af96f33dd891cd0d62c1a3df70
BLAKE2b-256 d5e2dd6bb6cee19750a7f8a19a7d241069282bda938abaa6eada20f2cf8bc4be

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp39-none-win_amd64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp39-none-win_amd64.whl
Algorithm Hash digest
SHA256 d35748e27511e433d3fc01a27e32ae975f38b524420ba08cb2db3137cc497b30
MD5 4a046640b3371388e5e1019392a22c46
BLAKE2b-256 aee850dcf698c705e1d65cc445d20d77e2fcb40fa16f1174ded9edfd77fbc27f

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp39-cp39-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp39-cp39-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 4c08422f88f756c5e3acff02eba373c8d2f24d6aee3c55fea290d282b8dcbfe4
MD5 08380ad7973d7dbfcd37eb51babc7768
BLAKE2b-256 04c84091c214be43dc11079499c97b81248ee44536ffc77568583a8fac93bdae

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp39-cp39-macosx_12_0_arm64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp39-cp39-macosx_12_0_arm64.whl
Algorithm Hash digest
SHA256 1db303c9873a16d8d061b7b01d9bde14cbe045bd87d526aae04f940f6b350484
MD5 0fcb0efe687ed1fc2473d13302f97d3a
BLAKE2b-256 55677763848f26793bb77cdcd360d068c40746c5ab9350b83afedf5eff90ae59

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 277bfee9c79bad707906f6951122378bcad4f102e37e279918f13aa0c0d77ae5
MD5 671f6cd468b87b9bcca0d065f7890ef2
BLAKE2b-256 1f96a80a0566843a2613dfd8eb32be61b3953b91866c3c19d2849dd4a3990cf7

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp38-none-win_amd64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp38-none-win_amd64.whl
Algorithm Hash digest
SHA256 ea30b573127ae55c42ba79d10e96ed1c955509958c9d922693966b6e1f387bdd
MD5 4903e190547799fee7110c242b65c9cd
BLAKE2b-256 561e044266c7b5706ddc17ca2038da2261940f9e5da0a730b4ee58b1c1d2bba0

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp38-cp38-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp38-cp38-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2af69f156ec017a8e7a5d03bd9725f8cf92e234bfa74dc22f596119a01017f2c
MD5 53d4d38c49962345ce330f19cb43f495
BLAKE2b-256 abab40875d7fe480b79063c6eda7db42353343d5707e8e982eb2fcdcfbff651b

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp38-cp38-macosx_12_0_arm64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp38-cp38-macosx_12_0_arm64.whl
Algorithm Hash digest
SHA256 660f27067c0f74e08686670a1a6bcabc0f12013e1fcb1b448f2a8a3972fcdee5
MD5 cde8986059afffadb2c0e6eed2c29adc
BLAKE2b-256 1bc8445bc170fd36989b1e424a363759d8518501a72b23c5b4b128ec12894301

See more details on using hashes here.

File details

Details for the file chrontext-0.9.10-cp38-cp38-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chrontext-0.9.10-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 12e688cbf8632e5b320b9a6369c676ad2b1c01b28c062a87a11bd7e235d57432
MD5 5ae2a3dfd2d80c2d596edba94d9e7a55
BLAKE2b-256 3b4fb5584e74bf561e8ad649f88c01403ce92e115d9bb61292f0331150e001ed

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page