Graphtik
========
|pypi-version| |gh-version| (build-version: x.x.x, build-date: 2023-04-25T21:27:33.616654)
|python-ver| |dev-status|
|ci-status| |doc-status| |cover-status| |codestyle| |proj-lic|
|gh-watch| |gh-star| |gh-fork| |gh-issues|
.. epigraph::
It's a DAG all the way down!
|sample-plot|
Computation graphs for Python & Pandas
--------------------------------------
**Graphtik** is a library to compose, solve, execute & plot *graphs of python functions*
(a.k.a pipelines) that consume and populate named data
(a.k.a dependencies), whose names may be nested (such as. *pandas* dataframe columns),
based on whether values for those dependencies exist in the inputs or
have been calculated earlier.
In mathematical terms, given:
- a partially populated data-tree, and
- a set of functions operating on (consuming/producing) branches of the data tree,
*graphtik* collects a subset of functions in a graph that when executed
consume & produce as many values as possible in the data-tree.
|usage-overview|
- Its primary use case is building flexible algorithms for data science/machine learning projects.
- It should be extendable to implement the following:
- an `IoC dependency resolver <https://en.wikipedia.org/wiki/Dependency_injection>`_
(e.g. Java Spring, Google Guice);
- an executor of interdependent tasks based on files (e.g. GNU Make);
- a custom ETL engine;
- a spreadsheet calculation engine.
*Graphtik* `sprang <https://docs.google.com/spreadsheets/d/1HPgtg2l6v3uDS81hLOcFOZxIBLCnHGrcFOh3pFRIDio/edit#gid=0>`_
from `Graphkit`_ (summer 2019, v1.2.2) to `experiment
<https://github.com/yahoo/graphkit/issues/>`_ with Python 3.6+ features,
but has diverged significantly with enhancements ever since.
.. _features:
Features
--------
- Deterministic pre-decided `execution plan` (unless *partial-outputs* or
*endured operations* defined, see below).
- Can assemble existing functions without modifications into `pipeline`\s.
- `dependency` resolution can bypass calculation cycles based on data given and asked.
- Support functions with `optional <optionals>` input args and/or `varargs <varargish>`.
- Support functions with `partial outputs`; keep working even if certain `endured` operations fail.
- Facilitate trivial `conveyor operation`\s and `alias` on `provides`.
- Support cycles, by annotating repeated updates of `dependency` values as `sideffects`,
(e.g. to add columns into *pandas.DataFrame*\s).
- `Hierarchical dependencies <subdoc>` may access data values deep in `solution`
with `json pointer path` expressions.
- Hierarchical dependencies annotated as `implicit` imply which subdoc dependency
the function reads or writes in the parent-doc.
- `Merge <operation merging>` or `nest <operation nesting>` sub-pipelines.
- Early `eviction` of intermediate results from `solution`, to optimize memory footprint.
- Solution tracks all intermediate `overwritten <overwrite>` values for the same dependency.
- Elaborate `Graphviz`_ plotting with configurable `plot theme`\s.
- Integration with Sphinx sites with the new *graphtik* directive.
- Authored with *debugging* in mind.
- Parallel execution (but underdeveloped & DEPRECATED).
Anti-features
^^^^^^^^^^^^^
- It's not meant to follow complex conditional logic based on `dependency` values
(though it does support that to `a limited degree <partial outputs>`).
- It's not an orchestrator for long-running tasks, nor a calendar scheduler -
`Apache Airflow <https://airflow.apache.org/>`_, `Dagster
<https://github.com/dagster-io/dagster>`_ or `Luigi <https://luigi.readthedocs.io/>`_
may help for that.
- It's not really a parallelizing optimizer, neither a map-reduce framework - look
additionally at `Dask <https://dask.org/>`_, `IpyParallel
<https://ipyparallel.readthedocs.io/en/latest/>`_, `Celery
<https://docs.celeryproject.org/en/stable/getting-started/introduction.html>`_,
Hive, Pig, Hadoop, etc.
- It's not a stream/batch processor, like Spark, Storm, Fink, Kinesis,
because it pertains function-call semantics, calling only once each function
to process data-items.
Differences with *schedula*
%%%%%%%%%%%%%%%%%%%%%%%%%%%
`schedula <https://schedula.readthedocs.io/>`_ is a powerful library written roughly
for the same purpose, and works differently along these lines
(ie features below refer to *schedula*):
- terminology (<graphtik> := <schedula>):
- pipeline := dispatcher
- plan := workflow
- solution := solution
- Dijkstra planning runs while calling operations:
- Powerful & flexible (ie all operations are dynamic, *domains* are possible, etc).
- Supports *weights*.
- Cannot pre-calculate & cache execution plans (slow).
- Calculated values are stored inside a graph (mimicking the structure of the functions):
- graph visualizations absolutely needed to inspect & debug its solutions.
- graphs imply complex pre/post processing & traversal algos
(vs constructing/traversing data-trees).
- Reactive plotted diagrams, web-server runs behind the scenes.
- Operation graphs are stackable:
- plotted nested-graphs support drill-down.
- *graphtik* emulates that with data/operation names (`operation nesting`),
but always a unified graph is solved at once,
bc it is impossible to dress *nesting-funcs* as a *python-funcs* and pre-solve plan
(*schedula* does not pre-solve plan, Dijkstra runs all the time).
See TODO about plotting such nested graphs.
- *Schedula* does not calculate all possible values (ie no `overwrite`\s).
- *Schedula* computes precedence based on weights and lexicographical order of function name.
- Re-inserting operation does not overrides its current function - must remove it first.
- *graphtik* precedence based insertion order during `composition`.
- Virtual *start* and *end* data-nodes needed for Dijkstra to solve the dag.
- No domains (execute-time conditionals deciding whether a function must run).
- Probably *recompute* is more straightforward in *graphtik*.
- TODO: more differences with *schedula* exist.
Quick start
-----------
Here’s how to install:
::
pip install graphtik
OR with various "extras" dependencies, such as, for plotting::
pip install graphtik[plot]
. Tip::
Supported extras:
**plot**
for plotting with `Graphviz`_,
**matplot**
for plotting in *maplotlib* windows
**sphinx**
for embedding plots in *sphinx*\-generated sites,
**test**
for running *pytest*\s,
**dill**
may help for pickling `parallel` tasks - see `marshalling` term
and ``set_marshal_tasks()`` configuration.
**all**
all of the above, plus development libraries, eg *black* formatter.
**dev**
like *all*
Let's build a *graphtik* computation graph that produces x3 outputs
out of 2 inputs `α` and `β`:
- `α x β`
- `α - αxβ`
- `|α - αxβ| ^ 3`
..
>>> from graphtik import compose, operation
>>> from operator import mul, sub
>>> @operation(name="abs qubed",
... needs=["α-α×β"],
... provides=["|α-α×β|³"])
... def abs_qubed(a):
... return abs(a) ** 3
Compose the ``abs_qubed`` function along the ``mul`` & ``sub`` built-ins
into a computation graph:
>>> graphop = compose("graphop",
... operation(needs=["α", "β"], provides=["α×β"])(mul),
... operation(needs=["α", "α×β"], provides=["α-α×β"])(sub),
... abs_qubed,
... )
>>> graphop
Pipeline('graphop', needs=['α', 'β', 'α×β', 'α-α×β'],
provides=['α×β', 'α-α×β', '|α-α×β|³'],
x3 ops: mul, sub, abs qubed)
Run the graph and request all of the outputs
(notice that unicode characters work also as Python identifiers):
>>> graphop(α=2, β=5)
{'α': 2, 'β': 5, 'α×β': 10, 'α-α×β': -8, '|α-α×β|³': 512}
... or request a subset of outputs:
>>> solution = graphop.compute({'α': 2, 'β': 5}, outputs=["α-α×β"])
>>> solution
{'α-α×β': -8}
... and plot the results (if in *jupyter*, no need to create the file):
>>> solution.plot('executed_3ops.svg') # doctest: +SKIP
|sample-sol|
|plot-legend|
.. |sample-plot| image:: docs/source/images/sample.svg
:alt: sample graphtik plot
:width: 380px
:align: middle
.. |usage-overview| image:: docs/source/images/GraphkitUsageOverview.svg
:alt: Usage overview of graphtik library
:width: 640px
:align: middle
.. |sample-sol| image:: docs/source/images/executed_3ops.svg
:alt: sample graphtik plot
:width: 380px
:align: middle
.. |plot-legend| image:: docs/source/images/GraphtikLegend.svg
:alt: graphtik legend
:align: middle
.. _Graphkit: https://github.com/yahoo/graphkit
.. _Graphviz: https://graphviz.org
.. _badges_substs:
.. |ci-status| image:: https://github.com/pygraphkit/graphtik/actions/workflows/ci.yaml/badge.svg
:alt: GitHub Actions CI testing ok? (Linux)
:target: https://github.com/pygraphkit/graphtik/actions
.. |doc-status| image:: https://img.shields.io/readthedocs/graphtik?branch=master
:alt: ReadTheDocs ok?
:target: https://graphtik.readthedocs.org
.. |cover-status| image:: https://img.shields.io/codecov/c/github/pygraphkit/graphtik
:target: https://codecov.io/gh/pygraphkit/graphtik
.. |gh-version| image:: https://img.shields.io/github/v/release/pygraphkit/graphtik?label=GitHub%20release&include_prereleases
:target: https://github.com/pygraphkit/graphtik/releases
:alt: Latest release in GitHub
.. |pypi-version| image:: https://img.shields.io/pypi/v/graphtik?label=PyPi%20version
:target: https://pypi.python.org/pypi/graphtik/
:alt: Latest version in PyPI
.. |python-ver| image:: https://img.shields.io/pypi/pyversions/graphtik?label=Python
:target: https://pypi.python.org/pypi/graphtik/
:alt: Supported Python versions of latest release in PyPi
.. |dev-status| image:: https://img.shields.io/pypi/status/graphtik
:target: https://pypi.python.org/pypi/graphtik/
:alt: Development Status
.. |codestyle| image:: https://img.shields.io/badge/code%20style-black-black
:target: https://github.com/ambv/black
:alt: Code Style
.. |gh-watch| image:: https://img.shields.io/github/watchers/pygraphkit/graphtik?style=social
:target: https://github.com/pygraphkit/graphtik
:alt: Github watchers
.. |gh-star| image:: https://img.shields.io/github/stars/pygraphkit/graphtik?style=social
:target: https://github.com/pygraphkit/graphtik
:alt: Github stargazers
.. |gh-fork| image:: https://img.shields.io/github/forks/pygraphkit/graphtik?style=social
:target: https://github.com/pygraphkit/graphtik
:alt: Github forks
.. |gh-issues| image:: http://img.shields.io/github/issues/pygraphkit/graphtik?style=social
:target: https://github.com/pygraphkit/graphtik/issues
:alt: Issues count
.. |proj-lic| image:: https://img.shields.io/pypi/l/graphtik
:target: https://www.apache.org/licenses/LICENSE-2.0
:alt: Apache License, version 2.0
Raw data
{
"_id": null,
"home_page": "http://github.com/pygraphkit/graphtik",
"name": "graphtik",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "graph,computation graph,DAG,directed acyclic graph,executor,scheduler,etl,workflow,pipeline",
"author": "Kostis Anagnostopoulos, Huy Nguyen, Arel Cordero, Pierre Garrigues, Rob Hess, Tobi Baumgartner, Clayton Mellina",
"author_email": "ankostis@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/7f/00/a579f9350ef68660b84e4b49123cd4f1c7b54ab0ebd55b9d2a0f6cfd77a7/graphtik-10.5.0.tar.gz",
"platform": "Windows",
"description": "Graphtik\n========\n\n|pypi-version| |gh-version| (build-version: x.x.x, build-date: 2023-04-25T21:27:33.616654)\n|python-ver| |dev-status|\n|ci-status| |doc-status| |cover-status| |codestyle| |proj-lic|\n\n|gh-watch| |gh-star| |gh-fork| |gh-issues|\n\n.. epigraph::\n\n It's a DAG all the way down!\n\n |sample-plot|\n\nComputation graphs for Python & Pandas\n--------------------------------------\n\n**Graphtik** is a library to compose, solve, execute & plot *graphs of python functions*\n(a.k.a pipelines) that consume and populate named data\n(a.k.a dependencies), whose names may be nested (such as. *pandas* dataframe columns),\nbased on whether values for those dependencies exist in the inputs or\nhave been calculated earlier.\n\nIn mathematical terms, given:\n\n- a partially populated data-tree, and\n- a set of functions operating on (consuming/producing) branches of the data tree,\n\n*graphtik* collects a subset of functions in a graph that when executed\nconsume & produce as many values as possible in the data-tree.\n\n|usage-overview|\n\n- Its primary use case is building flexible algorithms for data science/machine learning projects.\n- It should be extendable to implement the following:\n\n - an `IoC dependency resolver <https://en.wikipedia.org/wiki/Dependency_injection>`_\n (e.g. Java Spring, Google Guice);\n - an executor of interdependent tasks based on files (e.g. GNU Make);\n - a custom ETL engine;\n - a spreadsheet calculation engine.\n\n*Graphtik* `sprang <https://docs.google.com/spreadsheets/d/1HPgtg2l6v3uDS81hLOcFOZxIBLCnHGrcFOh3pFRIDio/edit#gid=0>`_\nfrom `Graphkit`_ (summer 2019, v1.2.2) to `experiment\n<https://github.com/yahoo/graphkit/issues/>`_ with Python 3.6+ features,\nbut has diverged significantly with enhancements ever since.\n\n.. _features:\n\nFeatures\n--------\n\n- Deterministic pre-decided `execution plan` (unless *partial-outputs* or\n *endured operations* defined, see below).\n- Can assemble existing functions without modifications into `pipeline`\\s.\n- `dependency` resolution can bypass calculation cycles based on data given and asked.\n- Support functions with `optional <optionals>` input args and/or `varargs <varargish>`.\n- Support functions with `partial outputs`; keep working even if certain `endured` operations fail.\n- Facilitate trivial `conveyor operation`\\s and `alias` on `provides`.\n- Support cycles, by annotating repeated updates of `dependency` values as `sideffects`,\n (e.g. to add columns into *pandas.DataFrame*\\s).\n- `Hierarchical dependencies <subdoc>` may access data values deep in `solution`\n with `json pointer path` expressions.\n- Hierarchical dependencies annotated as `implicit` imply which subdoc dependency\n the function reads or writes in the parent-doc.\n- `Merge <operation merging>` or `nest <operation nesting>` sub-pipelines.\n- Early `eviction` of intermediate results from `solution`, to optimize memory footprint.\n- Solution tracks all intermediate `overwritten <overwrite>` values for the same dependency.\n- Elaborate `Graphviz`_ plotting with configurable `plot theme`\\s.\n- Integration with Sphinx sites with the new *graphtik* directive.\n- Authored with *debugging* in mind.\n- Parallel execution (but underdeveloped & DEPRECATED).\n\nAnti-features\n^^^^^^^^^^^^^\n\n- It's not meant to follow complex conditional logic based on `dependency` values\n (though it does support that to `a limited degree <partial outputs>`).\n\n- It's not an orchestrator for long-running tasks, nor a calendar scheduler -\n `Apache Airflow <https://airflow.apache.org/>`_, `Dagster\n <https://github.com/dagster-io/dagster>`_ or `Luigi <https://luigi.readthedocs.io/>`_\n may help for that.\n\n- It's not really a parallelizing optimizer, neither a map-reduce framework - look\n additionally at `Dask <https://dask.org/>`_, `IpyParallel\n <https://ipyparallel.readthedocs.io/en/latest/>`_, `Celery\n <https://docs.celeryproject.org/en/stable/getting-started/introduction.html>`_,\n Hive, Pig, Hadoop, etc.\n\n- It's not a stream/batch processor, like Spark, Storm, Fink, Kinesis,\n because it pertains function-call semantics, calling only once each function\n to process data-items.\n\nDifferences with *schedula*\n%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n`schedula <https://schedula.readthedocs.io/>`_ is a powerful library written roughly\nfor the same purpose, and works differently along these lines\n(ie features below refer to *schedula*):\n\n- terminology (<graphtik> := <schedula>):\n\n - pipeline := dispatcher\n - plan := workflow\n - solution := solution\n\n- Dijkstra planning runs while calling operations:\n\n - Powerful & flexible (ie all operations are dynamic, *domains* are possible, etc).\n - Supports *weights*.\n - Cannot pre-calculate & cache execution plans (slow).\n\n- Calculated values are stored inside a graph (mimicking the structure of the functions):\n\n - graph visualizations absolutely needed to inspect & debug its solutions.\n - graphs imply complex pre/post processing & traversal algos\n (vs constructing/traversing data-trees).\n\n- Reactive plotted diagrams, web-server runs behind the scenes.\n- Operation graphs are stackable:\n\n - plotted nested-graphs support drill-down.\n - *graphtik* emulates that with data/operation names (`operation nesting`),\n but always a unified graph is solved at once,\n bc it is impossible to dress *nesting-funcs* as a *python-funcs* and pre-solve plan\n (*schedula* does not pre-solve plan, Dijkstra runs all the time).\n See TODO about plotting such nested graphs.\n\n- *Schedula* does not calculate all possible values (ie no `overwrite`\\s).\n- *Schedula* computes precedence based on weights and lexicographical order of function name.\n\n - Re-inserting operation does not overrides its current function - must remove it first.\n - *graphtik* precedence based insertion order during `composition`.\n\n- Virtual *start* and *end* data-nodes needed for Dijkstra to solve the dag.\n- No domains (execute-time conditionals deciding whether a function must run).\n- Probably *recompute* is more straightforward in *graphtik*.\n- TODO: more differences with *schedula* exist.\n\nQuick start\n-----------\nHere\u2019s how to install:\n\n::\n\n pip install graphtik\n\nOR with various \"extras\" dependencies, such as, for plotting::\n\n pip install graphtik[plot]\n\n. Tip::\n Supported extras:\n\n **plot**\n for plotting with `Graphviz`_,\n **matplot**\n for plotting in *maplotlib* windows\n **sphinx**\n for embedding plots in *sphinx*\\-generated sites,\n **test**\n for running *pytest*\\s,\n **dill**\n may help for pickling `parallel` tasks - see `marshalling` term\n and ``set_marshal_tasks()`` configuration.\n **all**\n all of the above, plus development libraries, eg *black* formatter.\n **dev**\n like *all*\n\nLet's build a *graphtik* computation graph that produces x3 outputs\nout of 2 inputs `\u03b1` and `\u03b2`:\n\n- `\u03b1 x \u03b2`\n- `\u03b1 - \u03b1x\u03b2`\n- `|\u03b1 - \u03b1x\u03b2| ^ 3`\n\n..\n\n>>> from graphtik import compose, operation\n>>> from operator import mul, sub\n\n>>> @operation(name=\"abs qubed\",\n... needs=[\"\u03b1-\u03b1\u00d7\u03b2\"],\n... provides=[\"|\u03b1-\u03b1\u00d7\u03b2|\u00b3\"])\n... def abs_qubed(a):\n... return abs(a) ** 3\n\nCompose the ``abs_qubed`` function along the ``mul`` & ``sub`` built-ins\ninto a computation graph:\n\n>>> graphop = compose(\"graphop\",\n... operation(needs=[\"\u03b1\", \"\u03b2\"], provides=[\"\u03b1\u00d7\u03b2\"])(mul),\n... operation(needs=[\"\u03b1\", \"\u03b1\u00d7\u03b2\"], provides=[\"\u03b1-\u03b1\u00d7\u03b2\"])(sub),\n... abs_qubed,\n... )\n>>> graphop\nPipeline('graphop', needs=['\u03b1', '\u03b2', '\u03b1\u00d7\u03b2', '\u03b1-\u03b1\u00d7\u03b2'],\n provides=['\u03b1\u00d7\u03b2', '\u03b1-\u03b1\u00d7\u03b2', '|\u03b1-\u03b1\u00d7\u03b2|\u00b3'],\n x3 ops: mul, sub, abs qubed)\n\nRun the graph and request all of the outputs\n(notice that unicode characters work also as Python identifiers):\n\n>>> graphop(\u03b1=2, \u03b2=5)\n{'\u03b1': 2, '\u03b2': 5, '\u03b1\u00d7\u03b2': 10, '\u03b1-\u03b1\u00d7\u03b2': -8, '|\u03b1-\u03b1\u00d7\u03b2|\u00b3': 512}\n\n... or request a subset of outputs:\n\n>>> solution = graphop.compute({'\u03b1': 2, '\u03b2': 5}, outputs=[\"\u03b1-\u03b1\u00d7\u03b2\"])\n>>> solution\n{'\u03b1-\u03b1\u00d7\u03b2': -8}\n\n... and plot the results (if in *jupyter*, no need to create the file):\n\n>>> solution.plot('executed_3ops.svg') # doctest: +SKIP\n\n|sample-sol|\n\n|plot-legend|\n\n.. |sample-plot| image:: docs/source/images/sample.svg\n :alt: sample graphtik plot\n :width: 380px\n :align: middle\n.. |usage-overview| image:: docs/source/images/GraphkitUsageOverview.svg\n :alt: Usage overview of graphtik library\n :width: 640px\n :align: middle\n.. |sample-sol| image:: docs/source/images/executed_3ops.svg\n :alt: sample graphtik plot\n :width: 380px\n :align: middle\n.. |plot-legend| image:: docs/source/images/GraphtikLegend.svg\n :alt: graphtik legend\n :align: middle\n\n\n.. _Graphkit: https://github.com/yahoo/graphkit\n.. _Graphviz: https://graphviz.org\n.. _badges_substs:\n\n.. |ci-status| image:: https://github.com/pygraphkit/graphtik/actions/workflows/ci.yaml/badge.svg\n :alt: GitHub Actions CI testing ok? (Linux)\n :target: https://github.com/pygraphkit/graphtik/actions\n\n.. |doc-status| image:: https://img.shields.io/readthedocs/graphtik?branch=master\n :alt: ReadTheDocs ok?\n :target: https://graphtik.readthedocs.org\n\n.. |cover-status| image:: https://img.shields.io/codecov/c/github/pygraphkit/graphtik\n :target: https://codecov.io/gh/pygraphkit/graphtik\n\n.. |gh-version| image:: https://img.shields.io/github/v/release/pygraphkit/graphtik?label=GitHub%20release&include_prereleases\n :target: https://github.com/pygraphkit/graphtik/releases\n :alt: Latest release in GitHub\n\n.. |pypi-version| image:: https://img.shields.io/pypi/v/graphtik?label=PyPi%20version\n :target: https://pypi.python.org/pypi/graphtik/\n :alt: Latest version in PyPI\n\n.. |python-ver| image:: https://img.shields.io/pypi/pyversions/graphtik?label=Python\n :target: https://pypi.python.org/pypi/graphtik/\n :alt: Supported Python versions of latest release in PyPi\n\n.. |dev-status| image:: https://img.shields.io/pypi/status/graphtik\n :target: https://pypi.python.org/pypi/graphtik/\n :alt: Development Status\n\n.. |codestyle| image:: https://img.shields.io/badge/code%20style-black-black\n :target: https://github.com/ambv/black\n :alt: Code Style\n\n.. |gh-watch| image:: https://img.shields.io/github/watchers/pygraphkit/graphtik?style=social\n :target: https://github.com/pygraphkit/graphtik\n :alt: Github watchers\n\n.. |gh-star| image:: https://img.shields.io/github/stars/pygraphkit/graphtik?style=social\n :target: https://github.com/pygraphkit/graphtik\n :alt: Github stargazers\n\n.. |gh-fork| image:: https://img.shields.io/github/forks/pygraphkit/graphtik?style=social\n :target: https://github.com/pygraphkit/graphtik\n :alt: Github forks\n\n.. |gh-issues| image:: http://img.shields.io/github/issues/pygraphkit/graphtik?style=social\n :target: https://github.com/pygraphkit/graphtik/issues\n :alt: Issues count\n\n.. |proj-lic| image:: https://img.shields.io/pypi/l/graphtik\n :target: https://www.apache.org/licenses/LICENSE-2.0\n :alt: Apache License, version 2.0\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "A Python lib for solving & executing graphs of functions, with `pandas` in mind",
"version": "10.5.0",
"split_keywords": [
"graph",
"computation graph",
"dag",
"directed acyclic graph",
"executor",
"scheduler",
"etl",
"workflow",
"pipeline"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "62e4e114627ea89216fa1f74c9daec32861d948ada3beae87c7068df6daca3f3",
"md5": "4653d0f229806b2aad52b75ca8e65b73",
"sha256": "d20a87139c9473cef50ac77f9ffea66e93a74d54e53345e9cbd43957f3cb76db"
},
"downloads": -1,
"filename": "graphtik-10.5.0-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "4653d0f229806b2aad52b75ca8e65b73",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": ">=3.6",
"size": 122309,
"upload_time": "2023-04-25T21:27:36",
"upload_time_iso_8601": "2023-04-25T21:27:36.115893Z",
"url": "https://files.pythonhosted.org/packages/62/e4/e114627ea89216fa1f74c9daec32861d948ada3beae87c7068df6daca3f3/graphtik-10.5.0-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "7f00a579f9350ef68660b84e4b49123cd4f1c7b54ab0ebd55b9d2a0f6cfd77a7",
"md5": "f8adfe860b486af096818b247d6fbf05",
"sha256": "890075835194f66a4f036085c338890356ec112b07adb4829b7613bc0a5bda3b"
},
"downloads": -1,
"filename": "graphtik-10.5.0.tar.gz",
"has_sig": false,
"md5_digest": "f8adfe860b486af096818b247d6fbf05",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 188301,
"upload_time": "2023-04-25T21:27:37",
"upload_time_iso_8601": "2023-04-25T21:27:37.595084Z",
"url": "https://files.pythonhosted.org/packages/7f/00/a579f9350ef68660b84e4b49123cd4f1c7b54ab0ebd55b9d2a0f6cfd77a7/graphtik-10.5.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-04-25 21:27:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "pygraphkit",
"github_project": "graphtik",
"travis_ci": true,
"coveralls": false,
"github_actions": true,
"lcname": "graphtik"
}