{"id":37085380,"url":"https://github.com/artigraph/artigraph","last_synced_at":"2026-01-14T10:29:49.750Z","repository":{"id":37236177,"uuid":"292762394","full_name":"artigraph/artigraph","owner":"artigraph","description":"Batteries included toolkit for data engineering.","archived":false,"fork":false,"pushed_at":"2024-12-30T13:54:07.000Z","size":5009,"stargazers_count":36,"open_issues_count":23,"forks_count":8,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-12-22T10:04:42.613Z","etag":null,"topics":["data","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/artigraph.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":"GOVERNANCE.md","roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-04T05:57:36.000Z","updated_at":"2025-10-17T22:09:20.000Z","dependencies_parsed_at":"2023-10-11T01:11:36.209Z","dependency_job_id":"7fe1c6e0-1c7f-4dd0-a15b-f7fa402113ed","html_url":"https://github.com/artigraph/artigraph","commit_stats":{"total_commits":573,"total_committers":7,"mean_commits":81.85714285714286,"dds":0.4101221640488656,"last_synced_commit":"d71e4be9714d29450e63e9a396a6a09970fd3746"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/artigraph/artigraph","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artigraph%2Fartigraph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artigraph%2Fartigraph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artigraph%2Fartigraph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artigraph%2Fartigraph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/artigraph","download_url":"https://codeload.github.com/artigraph/artigraph/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artigraph%2Fartigraph/sbom","scorecard":{"id":209558,"data":{"date":"2025-08-11","repo":{"name":"github.com/artigraph/artigraph","commit":"a158a7eae0406c35905d8bb3b2f27a733c2c18bc"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.7,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/10 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Security-Policy","score":4,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Warn: no linked content found","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql-analysis.yaml:17","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql-analysis.yaml:18","Warn: no topLevel permission defined: .github/workflows/ci.yaml:1","Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yaml:1","Warn: no topLevel permission defined: .github/workflows/weekly-analysis.yaml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"CII-Best-Practices","score":5,"reason":"badge detected: Passing","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/ci.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/ci.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yaml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/ci.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yaml:48: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/ci.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:60: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/ci.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yaml:68: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/ci.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yaml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/codeql-analysis.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yaml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/codeql-analysis.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yaml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/codeql-analysis.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yaml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/codeql-analysis.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/weekly-analysis.yaml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/weekly-analysis.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/weekly-analysis.yaml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/artigraph/artigraph/weekly-analysis.yaml/main?enable=pin","Warn: containerImage not pinned by hash: docs/examples/spend/Dockerfile:1: pin your Docker image by updating python:3.10 to python:3.10@sha256:4481586e00db3555bc31dc5f83cf5bba63f54555301b685ed7e461eb8f192eb5","Warn: pipCommand not pinned by hash: docs/examples/spend/Dockerfile:11","Warn: downloadThenRun not pinned by hash: .envrc:32","Warn: npmCommand not pinned by hash: .github/workflows/weekly-analysis.yaml:20","Info:   0 out of   9 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   0 out of   1 containerImage dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":7,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 0 commits out of 23 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T00:30:07.863Z","repository_id":37236177,"created_at":"2025-08-17T00:30:07.863Z","updated_at":"2025-08-17T00:30:07.863Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28417308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T10:25:19.714Z","status":"ssl_error","status_checked_at":"2026-01-14T10:22:49.371Z","response_time":107,"last_error":"SSL_read: 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":["data","python"],"created_at":"2026-01-14T10:29:49.105Z","updated_at":"2026-01-14T10:29:49.741Z","avatar_url":"https://github.com/artigraph.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# artigraph\n\n[![pypi](https://img.shields.io/pypi/v/arti.svg)](https://pypi.python.org/pypi/arti)\n[![changelog](https://img.shields.io/github/v/release/artigraph/artigraph?label=changelog)](https://github.com/artigraph/artigraph/releases)\n[![downloads](https://pepy.tech/badge/arti/month)](https://pepy.tech/project/arti)\n[![versions](https://img.shields.io/pypi/pyversions/arti.svg)](https://github.com/artigraph/artigraph)\n[![license](https://img.shields.io/github/license/artigraph/artigraph.svg)](https://github.com/artigraph/artigraph/blob/main/LICENSE)\n[![CI](https://github.com/artigraph/artigraph/actions/workflows/ci.yaml/badge.svg)](https://github.com/artigraph/artigraph/actions/workflows/ci.yaml)\n[![codecov](https://codecov.io/gh/artigraph/artigraph/branch/main/graph/badge.svg?token=6LUCpjcGdN)](https://codecov.io/gh/artigraph/artigraph)\n[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/5561/badge)](https://bestpractices.coreinfrastructure.org/projects/5561)\n\nDeclarative Data Production\n\nArtigraph is a tool to improve the authorship, management, and quality of data. It emphasizes that the core deliverable of a data pipeline or workflow is the data, not the tasks.\n\nArtigraph is hosted by the [LF AI and Data Foundation](https://lfaidata.foundation) as a Sandbox project. See our [deck](https://docs.google.com/presentation/d/1KLM9r0L5sTbpb_UPR5nx4fil-7fO-UnmhTeatSiaN3Y) or [presentation](https://wiki.lfaidata.foundation/download/attachments/7733341/GMT20220127-140219_Recording_3840x2160.mp4?version=1\u0026modificationDate=1643716019000\u0026api=v2) (@6m35s) requesting Sandbox incubation.\n\n## Community\n\nWe're excited to hear from anyone interested in the project - feel free to introduce yourself over in the [Intro Discussions](https://github.com/artigraph/artigraph/discussions/categories/intros)! See our [support page](SUPPORT.md) for help or our [contributing page](CONTRIBUTING.md) for guidelines.\n\n## Installation\n\nArtigraph can be installed from PyPI with `pip install arti`.\n\n## Example\n\nThis sample from the [spend example](docs/examples/spend/demo.py) highlights computing the total amount spent from a series of purchase transactions:\n\n```python\nfrom pathlib import Path\nfrom typing import Annotated\n\nfrom arti import Annotation, Artifact, Graph, producer\nfrom arti.formats.json import JSON\nfrom arti.storage.local import LocalFile\nfrom arti.types import Collection, Date, Float64, Int64, Struct\nfrom arti.versions import SemVer\n\nDIR = Path(__file__).parent\n\n\nclass Vendor(Annotation):\n    name: str\n\n\nclass Transactions(Artifact):\n    \"\"\"Transactions partitioned by day.\"\"\"\n\n    type = Collection(\n        element=Struct(fields={\"id\": Int64(), \"date\": Date(), \"amount\": Float64()}),\n        partition_by=(\"date\",),\n    )\n\n\nclass TotalSpend(Artifact):\n    \"\"\"Aggregate spend over all time.\"\"\"\n\n    type = Float64()\n    format = JSON()\n    storage = LocalFile()\n\n\n@producer(version=SemVer(major=1, minor=0, patch=0))\ndef aggregate_transactions(\n    transactions: Annotated[list[dict], Transactions]\n) -\u003e Annotated[float, TotalSpend]:\n    return sum(txn[\"amount\"] for txn in transactions)\n\n\nwith Graph(name=\"test-graph\") as g:\n    g.artifacts.vendor.transactions = Transactions(\n        annotations=[Vendor(name=\"Acme\")],\n        format=JSON(),\n        storage=LocalFile(path=str(DIR / \"transactions\" / \"{date.iso}.json\")),\n    )\n    g.artifacts.spend = aggregate_transactions(\n        transactions=g.artifacts.vendor.transactions\n    )\n```\n\nThe full example can be run easily with `docker run --rm artigraph/example-spend`:\n```\nINFO:root:Writing mock Transactions data:\nINFO:root:      /usr/src/app/transactions/2021-10-01.json: [{'id': 1, 'amount': 9.95}, {'id': 2, 'amount': 7.5}]\nINFO:root:      /usr/src/app/transactions/2021-10-02.json: [{'id': 3, 'amount': 5.0}, {'id': 4, 'amount': 12.0}, {'id': 4, 'amount': 7.55}]\nINFO:root:Building aggregate_transactions(transactions=Transactions(format=JSON(), storage=LocalFile(path='/usr/src/app/transactions/{date.iso}.json'), annotations=(Vendor(name='Acme'),)))...\nINFO:root:Build finished.\nINFO:root:Final Spend data:\nINFO:root:      /tmp/test-graph/spend/7564053533177891797/spend.json: 42.0\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartigraph%2Fartigraph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartigraph%2Fartigraph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartigraph%2Fartigraph/lists"}