{"id":42643236,"url":"https://github.com/datatrails/datatrails-python","last_synced_at":"2026-01-29T06:34:34.925Z","repository":{"id":37479650,"uuid":"360918184","full_name":"datatrails/datatrails-python","owner":"datatrails","description":"The standard Python3 SDK for the DataTrails  system.","archived":false,"fork":false,"pushed_at":"2025-11-26T03:05:02.000Z","size":39396,"stargazers_count":5,"open_issues_count":12,"forks_count":7,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-12-11T08:35:49.885Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://python.datatrails.ai/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/datatrails.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-04-23T14:52:50.000Z","updated_at":"2025-04-22T15:20:55.000Z","dependencies_parsed_at":"2022-07-11T10:31:21.696Z","dependency_job_id":"cc0aa6c9-a4fc-4bfb-ac8f-b40cf2c2b4f7","html_url":"https://github.com/datatrails/datatrails-python","commit_stats":{"total_commits":231,"total_committers":17,"mean_commits":"13.588235294117647","dds":"0.49350649350649356","last_synced_commit":"59302cc493eb383b10ca2f0ac3083eef99166bd4"},"previous_names":["jitsuin-inc/archivist-python","datatrails/datatrails-python","rkvst/rkvst-python"],"tags_count":87,"template":false,"template_full_name":null,"purl":"pkg:github/datatrails/datatrails-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datatrails%2Fdatatrails-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datatrails%2Fdatatrails-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datatrails%2Fdatatrails-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datatrails%2Fdatatrails-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datatrails","download_url":"https://codeload.github.com/datatrails/datatrails-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datatrails%2Fdatatrails-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28867104,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-29T05:56:06.453Z","status":"ssl_error","status_checked_at":"2026-01-29T05:55:57.668Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-29T06:34:34.405Z","updated_at":"2026-01-29T06:34:34.915Z","avatar_url":"https://github.com/datatrails.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n.. _readme:\n\nDataTrails Python Client\n=========================\n\nThe standard DataTrails Python Client.\n\nPlease note that the canonical API for DataTrails is always the REST API\ndocumented at https://docs.datatrails.ai\n\nSupport\n=======\n\nThis package currently is tested against Python versions 3.9,3.10,3.11, 3.12 and 3.13.\n\nThe current default version is 3.9 - this means that this package will not\nuse any features specific to versions 3.10 and later.\n\nAfter End of Life of a particular Python version, support is offered on a best effort\nbasis. We may ask you to update your Python version to help solve the problem,\nif it cannot be reasonably resolved in your current version.\n\nInstallation\n=============\n\nUse standard python pip utility:\n\n.. code:: bash\n\n    python3 -m pip install datatrails-archivist\n\nIf your version of python3 is too old an error of this type or similar will be emitted:\n\n.. note:: \n\n    ERROR: Could not find a version that satisfies the requirement datatrails-archivist (from versions: none)\n    ERROR: No matching distribution found for datatrails-archivist\n\nExample\n=============\n\nYou can then use the examples code to create assets (see examples directory):\n\n.. code:: python\n\n    \"\"\"Create an asset in DataTrails with User Token.\n\n    The module contains two functions: main and create_asset. Main function parses in\n    a url to the Archivist and credentials, which is a user authorization.\n    The main function would initialize an archivist connection using the url and\n    the credentials, called \"arch\", then call arch.assets.create() and the asset will be created.\n    \"\"\"\n\n    from os import getenv\n\n    from archivist.archivist import Archivist\n\n\n    def create_asset(arch):\n        \"\"\"Create an asset using Archivist Connection.\n\n        Args:\n            arch: archivist connection.\n\n        Returns:\n            newasset: a new asset created.\n\n        \"\"\"\n        attrs = {\n            \"arc_display_name\": \"display_name\",  # Asset's display name in the user interface\n            \"arc_description\": \"display_description\",  # Asset's description in the user interface\n            \"arc_display_type\": \"display_type\",  # Arc_display_type is a free text field\n            # allowing the creator of\n            # an asset to specify the asset\n            # type or class. Be careful when setting this:\n            # assets are grouped by type and\n            # sharing policies can be\n            # configured to share assets based on\n            # their arc_display_type.\n            # So a mistake here can result in asset data being\n            # under- or over-shared.\n            \"some_custom_attribute\": \"value\"  # You can add any custom value as long as\n            # it does not start with arc_\n        }\n        #\n        # There are 3 alternatives\n        #\n        # 1. Create the asset:\n        #    The first argument is the attributes of the asset\n        return arch.assets.create(attrs=attrs)\n        #\n        # 2. alternatively one can wait for the asset to be confirmed in the\n        #    immutable store.\n        #    The second argument is wait for confirmation:\n        #      If @confirm@ is True then this function will not\n        #      return until the asset is confirmed.\n        #\n        # Confirmation guarantees that 3rd parties can retrieve and cryptographically\n        # verify your Assets, which can take a few seconds to propagate. It is typically\n        # not necessary to wait unless your workflow involves near-real-time\n        # communication with 3rd parties and the 3rd party needs immediate cryptographic\n        # verification of your new Asset.\n        return arch.assets.create(attrs=attrs, confirm=True)\n        #\n        # 3. lastly if some work can be done whilst the asset is confirmed then this call\n        # can be replaced by a two-step alternative:\n\n        asset = arch.assets.create(props=props, attrs=attrs)\n\n        # ... do something else here\n        # and then wait for confirmation\n\n        return arch.assets.wait_for_confirmation(asset['identity']))\n\n\n    def main():\n        \"\"\"Main function of create asset.\n\n        Parse in user input of url and client id/secrets and use them to\n        create an example archivist connection and create an asset.\n\n        \"\"\"\n\n        # client id and client secret is obtained from the appidp endpoint - see the\n        # application registrations example code in examples/applications_registration.py\n        #\n        # client id is an environment variable. client_secret is stored in a file in a\n        # directory that has 0700 permissions. The location of this file is set in\n        # the client_secret_filename environment variable.\n        client_id = getenv(\"DATATRAILS_APPREG_CLIENT\")\n        client_secret_file = getenv(\"DATATRAILS_APPREG_SECRET_FILENAME\")\n        with open(client_secret_file, mode=\"r\", encoding=\"utf-8\") as tokenfile:\n            client_secret = tokenfile.read().strip()\n\n        # Initialize connection to Archivist. max_time is the time to wait for confirmation\n        # of an asset or event creation - the default is 300 seconds but one can optionally\n        # specify a different value.\n        with arch = Archivist(\n            \"https://app.datatrails.ai\",\n            (client_id, client_secret),\n            max_time=300,\n        ) as arch:\n            # Create a new asset\n            asset = create_asset(arch)\n            print(\"Asset\", asset)\n\n\n    if __name__ == \"__main__\":\n        main()\n\n\nNotebooks\n=================\n\nSome jupyter notebooks are available to exercise the examples code.\nThese examples can be downloaded from python.datatrails.ai and run in a local install\nof jupyter notebook such as jupyterLabDesktop.\n\nPlease consult https://python.datatrails.ai/notebooks.html for details.\n\n\nFile Story Runner\n=================\n\nYou can run scenarios - a sequence of steps - from a python dictionary or from a yaml\nor json file.\n\nPython\n------\n\n.. code:: python\n\n    from logging import getLogger\n    from pyaml_env import parse_config\n    from sys import exit as sys_exit\n    from sys import stdout as sys_stdout\n\n    from archivist import about\n    from archivist.archivist import Archivist\n    from archivist.parser import common_parser, endpoint\n\n    LOGGER = getLogger(__name__)\n\n    def run(arch: Archivist, args):\n\n        LOGGER.info(\"Using version %s of datatrails-archivist\", about.__version__)\n        LOGGER.info(\"Namespace %s\", args.namespace)\n\n        with open(args.yamlfile, \"r\", encoding=\"utf-8\") as y:\n            arch.runner(parse_config(data=y)\n\n        sys_exit(0)\n\n    def main():\n        parser = common_parser(\"Executes the archivist runner from a yaml file\")\n\n        parser.add_argument(\n            \"yamlfile\", help=\"the yaml file describing the steps to conduct\"\n        )\n        args = parser.parse_args()\n\n        arch = endpoint(args)\n\n        run(arch, args)\n\n        parser.print_help(sys_stdout)\n        sys_exit(1)\n\n\nCommand Line\n------------\n\nThis functionality is also available with the CLI tool :code:`archivist_runner`, which is bundled with version v0.10 onwards of the :code:`datatrails-archivist`.\n\nYou can verify the installation by running the following:\n\n.. code-block:: shell\n\n   archivist_runner -h\n\nWhich will show you the available options when using :code:`archivist_runner`.\n\nTo use the :code:`archivist_runner` command you will need the following:\n\n    - A Client ID and Client Secret by creating an `App Registration`_\n    - The YAML file with the operations you wish to run\n    - The URL of your DataTrails instance, this is typically `https://app.datatrails.ai`\n\n.. _App Registration: https://docs.datatrails.ai/developers/developer-patterns/getting-access-tokens-using-app-registrations/\n\nExample usage:\n\n.. code-block:: shell\n\n   archivist_runner \\\n         -u https://app.datatrails.ai \\\n         --client-id \u003cyour-client-id\u003e \\\n         --client-secret \u003cyour-client-secret\u003e \\\n         functests/test_resources/subjects_story.yaml\n\n\nExample Yaml Snippet\n--------------------\n\nThis is an example of creating an asset and creating an event for that asset. The\nyaml file consists of a list of steps.\n\nEach step consists of control parameters (specified in the 'step' dictionary) and \nthe yaml representation of the request body for an asset or event.\n\nThe confirm: field is a control variable for the PythonSDK that ensures that the\nasset or event is confirmed before returning. This is optional and is only required\nif 3rd parties need to immediately retrieve and cryptographically\nverify your Assets, which can take a few seconds to propagate. It is typically\nnot necessary to wait unless your workflow involves near-real-time\ncommunication with 3rd parties and the 3rd party needs instant cryptographic\nverification of your new Asset.\n\n.. note::\n\n   The name of the asset is important. The value of the name is carried forward for\n   every operation - in this case the name of the asset is 'radiation bag 1'.\n\n   Arguments to the archivist are usually strings - in this example radioactive is \n   'true' which archivist will treat as a boolean.\n\n\n.. code:: yaml\n\n    ---\n    # The operation field is a string that represents the method bound to an endpoint and\n    # the args and kwargs correspond to the arguments to such a method.\n    #\n    # NB the assets and events endpoints require all values to be strings. Other values may\n    # be of the correct type such as confirm which is a boolean.\n    #\n    steps:\n\n      # note the values to the assets.create method are string representations of boolean\n      # and numbers\n      - step:\n          action: ASSETS_CREATE\n          description: Create an empty radiation bag with id 1.\n          asset_label: radiation bag 1\n        behaviours:\n          - RecordEvidence\n        attributes:\n          arc_display_name: radiation bag 1\n          radioactive: \"true\"\n          radiation_level: \"0\"\n          weight: \"0\"\n\n      # setup the radiation bags to have a varing amount of radiactive waste\n      # note the values to the events.create method are string representations of boolean\n      # and numbers\n      - step:\n          action: EVENTS_CREATE\n          description: Create Event adding 3 rads of radiation to bag 1, increasing its weight by 1kg.\n          asset_label: radiation bag 1\n        operation: Record\n        behaviour: RecordEvidence\n        event_attributes:\n          arc_description: add waste to bag\n          arc_evidence: see attached conformance report\n          conformance_report: blobs/e2a1d16c-03cd-45a1-8cd0-690831df1273\n        asset_attributes:\n          radiation_level: \"3\"\n          weight: \"1\"\n\nLogging\n========\n\nFollows the Django model as described here: https://docs.djangoproject.com/en/3.2/topics/logging/\n\nThe base logger for this package is rooted at \"archivist\" with subloggers for each endpoint:\n\n.. note::\n    archivist.archivist\n        sublogger for archivist submodule\n\n    archivist.assets\n        sublogger for assets submodule\n\nand for other endpoints.\n\nLogging is configured by either defining a root logger with suitable handlers, formatters etc. or\nby using dictionary configuration as described here: https://docs.python.org/3/library/logging.config.html#logging-config-dictschema\n\nA recommended minimum configuration would be:\n\n.. code:: python\n\n    import logging\n\n    logging.dictConfig({\n        \"version\": 1,\n        \"disable_existing_loggers\": False,\n        \"handlers\": {\n            \"console\": {\n                \"class\": \"logging.StreamHandler\",\n            },\n        },\n        \"root\": {\n            \"handlers\": [\"console\"],\n            \"level\": \"INFO\",\n        },\n    })\n\nFor convenience this has been encapsulated in a convenience function :code:`set_logger`\nwhich should be called before anything else:\n\n.. code:: python\n\n    from archivist.logger import set_logger\n    from archivist.archivist import Archivist\n\n    set_logger(\"DEBUG\")\n    client_id = getenv(\"DATATRAILS_APPREG_CLIENT\")\n    client_secret_file = getenv(\"DATATRAILS_APPREG_SECRET_FILENAME\")\n    with open(client_secret_file, mode=\"r\", encoding=\"utf-8\") as tokenfile:\n        client_secret = tokenfile.read().strip()\n\n    arch = Archivist(\n        \"https://app.datatrails.ai\",\n        (client_id, client_secret),\n        max_time=300,\n    )\n\nDevelopment\n===========\n\nFor instructions on contributing to the DataTrails SDK see DEVELOPMENT.md.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatatrails%2Fdatatrails-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatatrails%2Fdatatrails-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatatrails%2Fdatatrails-python/lists"}