geff 0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geff-0.0/.gitattributes +2 -0
- geff-0.0/.github/PULL_REQUEST_TEMPLATE.md +26 -0
- geff-0.0/.github/workflows/ci.yaml +165 -0
- geff-0.0/.github/workflows/gh-pages.yaml +86 -0
- geff-0.0/.github/workflows/test.yaml +83 -0
- geff-0.0/.gitignore +27 -0
- geff-0.0/.pre-commit-config.yaml +32 -0
- geff-0.0/CONTRIBUTING +41 -0
- geff-0.0/LICENSE +21 -0
- geff-0.0/PKG-INFO +64 -0
- geff-0.0/README.md +19 -0
- geff-0.0/docs/index.md +7 -0
- geff-0.0/docs/specification.md +74 -0
- geff-0.0/docs/what-is-geff.md +12 -0
- geff-0.0/geff-schema.json +1 -0
- geff-0.0/mkdocs.yml +44 -0
- geff-0.0/pyproject.toml +185 -0
- geff-0.0/scripts/benchmark-pr.py +49 -0
- geff-0.0/scripts/export_json_schema.py +12 -0
- geff-0.0/setup.cfg +4 -0
- geff-0.0/src/geff/__init__.py +6 -0
- geff-0.0/src/geff/metadata_schema.py +94 -0
- geff-0.0/src/geff/networkx/__init__.py +9 -0
- geff-0.0/src/geff/networkx/io.py +256 -0
- geff-0.0/src/geff/supported_versions.yml +1 -0
- geff-0.0/src/geff/utils.py +92 -0
- geff-0.0/src/geff.egg-info/PKG-INFO +64 -0
- geff-0.0/src/geff.egg-info/SOURCES.txt +34 -0
- geff-0.0/src/geff.egg-info/dependency_links.txt +1 -0
- geff-0.0/src/geff.egg-info/requires.txt +29 -0
- geff-0.0/src/geff.egg-info/top_level.txt +1 -0
- geff-0.0/tests/bench.py +60 -0
- geff-0.0/tests/test_agnostic/test_metadata_schema.py +149 -0
- geff-0.0/tests/test_agnostic/test_utils.py +130 -0
- geff-0.0/tests/test_networkx/test_nx_basics.py +79 -0
- geff-0.0/tests/test_networkx/test_nx_missing_attrs.py +104 -0
geff-0.0/.gitattributes
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Proposed Change
|
|
2
|
+
Briefly describe the contribution. If it resolves an issue or feature request, be sure to link to that issue.
|
|
3
|
+
|
|
4
|
+
# Types of Changes
|
|
5
|
+
What types of changes does your code introduce? Delete those that do not apply.
|
|
6
|
+
- Bugfix (non-breaking change which fixes an issue)
|
|
7
|
+
- New feature or enhancement
|
|
8
|
+
- Documentation update
|
|
9
|
+
- Tests
|
|
10
|
+
- Maintenance (e.g. dependencies, CI, releases, etc.)
|
|
11
|
+
|
|
12
|
+
Which topics does your change affect? Delete those that do not apply.
|
|
13
|
+
- Specification
|
|
14
|
+
- `networkx` implementation
|
|
15
|
+
|
|
16
|
+
# Checklist
|
|
17
|
+
Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.
|
|
18
|
+
|
|
19
|
+
- [ ] I have read the developer/contributing docs.
|
|
20
|
+
- [ ] I have added tests that prove that my feature works in various situations or tests the bugfix (if appropriate).
|
|
21
|
+
- [ ] I have checked that I maintained or improved code coverage.
|
|
22
|
+
- [ ] I have written docstrings and checked that they render correctly.
|
|
23
|
+
- [ ] If I changed the specification, I have checked that any validation functions and tests reflect the changes.
|
|
24
|
+
|
|
25
|
+
# Further Comments
|
|
26
|
+
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
name: Test geff
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
tags: [v*]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
env:
|
|
18
|
+
SETUPTOOLS_SCM_PRETEND_VERSION: "0.0"
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
tests:
|
|
22
|
+
uses: ./.github/workflows/test.yaml
|
|
23
|
+
with:
|
|
24
|
+
test-target: "tests"
|
|
25
|
+
witty-cache: false
|
|
26
|
+
install-extras: "dev"
|
|
27
|
+
|
|
28
|
+
schema:
|
|
29
|
+
name: Check json schema
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
env:
|
|
32
|
+
testjson: check-json.json
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
|
|
36
|
+
- name: Set up Python 3.12
|
|
37
|
+
uses: actions/setup-python@v5
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.12"
|
|
40
|
+
cache-dependency-path: "pyproject.toml"
|
|
41
|
+
cache: "pip"
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: |
|
|
45
|
+
python -m pip install -U pip
|
|
46
|
+
pip install .
|
|
47
|
+
|
|
48
|
+
- name: Generate json
|
|
49
|
+
run: python scripts/export_json_schema.py --filename $testjson
|
|
50
|
+
|
|
51
|
+
- run: cat $testjson
|
|
52
|
+
|
|
53
|
+
- name: Compare hashes
|
|
54
|
+
if: ${{ hashFiles( env.testjson ) != hashFiles('geff-schema.json') }}
|
|
55
|
+
uses: actions/github-script@v3
|
|
56
|
+
with:
|
|
57
|
+
script: |
|
|
58
|
+
core.setFailed('geff-schema.json needs to be updated by locally running `pixi run update-json`. ${{ hashFiles( env.testjson ) }} vs ${{ hashFiles('geff-schema.json') }}')
|
|
59
|
+
|
|
60
|
+
benchmark:
|
|
61
|
+
name: Benchmark
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
if: github.event_name == 'pull_request'
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v4
|
|
67
|
+
with:
|
|
68
|
+
fetch-depth: 50 # this is to make sure we obtain the target base commit
|
|
69
|
+
|
|
70
|
+
- name: Set up Python
|
|
71
|
+
uses: actions/setup-python@v5
|
|
72
|
+
with:
|
|
73
|
+
python-version: 3.13
|
|
74
|
+
cache-dependency-path: "pyproject.toml"
|
|
75
|
+
cache: "pip"
|
|
76
|
+
|
|
77
|
+
- name: Install dependencies
|
|
78
|
+
run: |
|
|
79
|
+
python -m pip install -U pip
|
|
80
|
+
python -m pip install -e .[bench,dev]
|
|
81
|
+
|
|
82
|
+
- name: Retrieve cached baseline if available
|
|
83
|
+
uses: actions/cache/restore@v4
|
|
84
|
+
id: cache_baseline
|
|
85
|
+
with:
|
|
86
|
+
path: baseline.json
|
|
87
|
+
key: ${{ github.event.pull_request.base.sha }}
|
|
88
|
+
|
|
89
|
+
- name: Run baseline benchmark if not in cache
|
|
90
|
+
if: steps.cache_baseline.outputs.cache-hit != 'true'
|
|
91
|
+
run: |
|
|
92
|
+
git checkout ${{ github.event.pull_request.base.sha }}
|
|
93
|
+
pytest tests/bench.py -v --benchmark-json baseline.json
|
|
94
|
+
|
|
95
|
+
- name: Cache baseline results
|
|
96
|
+
uses: actions/cache/save@v4
|
|
97
|
+
if: steps.cache_baseline.outputs.cache-hit != 'true'
|
|
98
|
+
with:
|
|
99
|
+
path: baseline.json
|
|
100
|
+
key: ${{ github.event.pull_request.base.sha }}
|
|
101
|
+
|
|
102
|
+
- name: Run benchmark on PR head commit
|
|
103
|
+
run: |
|
|
104
|
+
git checkout ${{ github.event.pull_request.head.sha }}
|
|
105
|
+
pytest tests/bench.py -v --benchmark-json pr.json
|
|
106
|
+
|
|
107
|
+
- name: Generate report
|
|
108
|
+
run: python scripts/benchmark-pr.py baseline.json pr.json report.md
|
|
109
|
+
|
|
110
|
+
- name: Comment on commit with report for non-forks
|
|
111
|
+
uses: peter-evans/commit-comment@v3
|
|
112
|
+
if: github.event.pull_request.head.repo.fork == false
|
|
113
|
+
with:
|
|
114
|
+
body-path: report.md
|
|
115
|
+
token: ${{ secrets.COMMIT_MESSAGE_TOKEN }}
|
|
116
|
+
|
|
117
|
+
deploy:
|
|
118
|
+
name: Deploy
|
|
119
|
+
# TODO: Add back successful test requirement once package is more stable
|
|
120
|
+
# needs: test
|
|
121
|
+
# if: success() && startsWith(github.ref, 'refs/tags/') && github.event_name != 'schedule'
|
|
122
|
+
if: startsWith(github.ref, 'refs/tags/') && github.event_name != 'schedule'
|
|
123
|
+
runs-on: ubuntu-latest
|
|
124
|
+
|
|
125
|
+
permissions:
|
|
126
|
+
id-token: write
|
|
127
|
+
contents: write
|
|
128
|
+
|
|
129
|
+
steps:
|
|
130
|
+
- uses: actions/checkout@v4
|
|
131
|
+
with:
|
|
132
|
+
fetch-depth: 0
|
|
133
|
+
|
|
134
|
+
- name: 🐍 Set up Python
|
|
135
|
+
uses: actions/setup-python@v5
|
|
136
|
+
with:
|
|
137
|
+
python-version: "3.x"
|
|
138
|
+
|
|
139
|
+
- name: Install geff
|
|
140
|
+
run: pip install .
|
|
141
|
+
|
|
142
|
+
- run: echo ${{ github.ref_name }}
|
|
143
|
+
|
|
144
|
+
- name: Check supported_versions.yml
|
|
145
|
+
shell: python
|
|
146
|
+
run: |
|
|
147
|
+
import re; from geff.metadata_schema import SUPPORTED_VERSIONS_REGEX
|
|
148
|
+
|
|
149
|
+
if re.search(SUPPORTED_VERSIONS_REGEX, "${{ github.ref_name }}") is None:
|
|
150
|
+
sys.exit("`supported_versions.yml` needs to be updated to include new release ${{ github.ref_name }}")
|
|
151
|
+
|
|
152
|
+
- name: 👷 Build
|
|
153
|
+
run: |
|
|
154
|
+
python -m pip install build
|
|
155
|
+
python -m build
|
|
156
|
+
|
|
157
|
+
- name: 🚢 Publish to PyPI
|
|
158
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
159
|
+
with:
|
|
160
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
161
|
+
|
|
162
|
+
- uses: softprops/action-gh-release@v2
|
|
163
|
+
with:
|
|
164
|
+
generate_release_notes: true
|
|
165
|
+
files: "./dist/*"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
name: Push gh-pages updates update
|
|
2
|
+
|
|
3
|
+
# push to the gh-pages branch whenever there is a new push to main or a new tag
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
tags: ["*"]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
deployments: write
|
|
14
|
+
|
|
15
|
+
env:
|
|
16
|
+
TAG: ${{ contains(github.ref, 'tags') && 'latest' || 'dev'}}
|
|
17
|
+
SETUPTOOLS_SCM_PRETEND_VERSION: "0.0"
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
push-docs:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
concurrency:
|
|
23
|
+
group: gh-pages
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout repository
|
|
26
|
+
uses: actions/checkout@v3
|
|
27
|
+
|
|
28
|
+
- name: Set up Python
|
|
29
|
+
uses: actions/setup-python@v3
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.12"
|
|
32
|
+
|
|
33
|
+
- name: Install dependencies
|
|
34
|
+
run: |
|
|
35
|
+
pip install -e ".[docs]"
|
|
36
|
+
|
|
37
|
+
- id: get_version
|
|
38
|
+
uses: battila7/get-version-action@v2
|
|
39
|
+
|
|
40
|
+
- name: configure git
|
|
41
|
+
run: |
|
|
42
|
+
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
|
43
|
+
git config --local user.name "github-actions[bot]"
|
|
44
|
+
git fetch origin gh-pages --depth=1
|
|
45
|
+
|
|
46
|
+
- name: Update schema docs
|
|
47
|
+
run: |
|
|
48
|
+
mkdir docs/schema
|
|
49
|
+
generate-schema-doc geff-schema.json docs/schema/schema.html
|
|
50
|
+
|
|
51
|
+
- name: Push changes to gh-pages branch
|
|
52
|
+
run: mike deploy ${{ steps.get_version.outputs.version }} $TAG -u -p
|
|
53
|
+
|
|
54
|
+
benchmark:
|
|
55
|
+
name: Report benchmarks on gh-pages
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
concurrency:
|
|
58
|
+
group: gh-pages
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
|
|
62
|
+
- name: Set up Python
|
|
63
|
+
uses: actions/setup-python@v5
|
|
64
|
+
with:
|
|
65
|
+
python-version: 3.12
|
|
66
|
+
cache-dependency-path: "pyproject.toml"
|
|
67
|
+
cache: "pip"
|
|
68
|
+
|
|
69
|
+
- name: Install dependencies
|
|
70
|
+
run: |
|
|
71
|
+
python -m pip install -U pip
|
|
72
|
+
python -m pip install -e .[dev,bench]
|
|
73
|
+
|
|
74
|
+
- name: Run benchmark
|
|
75
|
+
run: |
|
|
76
|
+
pytest tests/bench.py --benchmark-json output.json
|
|
77
|
+
|
|
78
|
+
- name: Store benchmark results
|
|
79
|
+
uses: benchmark-action/github-action-benchmark@v1
|
|
80
|
+
with:
|
|
81
|
+
name: Python Benchmark with pytest-benchmark
|
|
82
|
+
tool: 'pytest'
|
|
83
|
+
output-file-path: output.json
|
|
84
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
85
|
+
auto-push: true
|
|
86
|
+
benchmark-data-dir-path: bench/
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
on:
|
|
2
|
+
workflow_call:
|
|
3
|
+
inputs:
|
|
4
|
+
test-target:
|
|
5
|
+
required: true
|
|
6
|
+
type: string
|
|
7
|
+
witty-cache:
|
|
8
|
+
required: true
|
|
9
|
+
type: boolean
|
|
10
|
+
install-extras:
|
|
11
|
+
required: true
|
|
12
|
+
type: string
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
SETUPTOOLS_SCM_PRETEND_VERSION: "0.0"
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
name: ${{ matrix.platform }} ${{ matrix.python-version }} zarr ${{ matrix.zarr-version }}
|
|
20
|
+
runs-on: ${{ matrix.platform }}
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
25
|
+
platform: [ubuntu-latest, macos-latest, windows-latest]
|
|
26
|
+
zarr-version: ["2.*", "3.*"]
|
|
27
|
+
exclude:
|
|
28
|
+
# Zarr 3 doesn't support 3.10
|
|
29
|
+
- zarr-version: "3.*"
|
|
30
|
+
python-version: "3.10"
|
|
31
|
+
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v4
|
|
34
|
+
|
|
35
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
36
|
+
uses: actions/setup-python@v5
|
|
37
|
+
with:
|
|
38
|
+
python-version: ${{ matrix.python-version }}
|
|
39
|
+
cache-dependency-path: "pyproject.toml"
|
|
40
|
+
cache: "pip"
|
|
41
|
+
|
|
42
|
+
- name: Install dependencies
|
|
43
|
+
run: |
|
|
44
|
+
python -m pip install -U pip
|
|
45
|
+
python -m pip install zarr==${{ matrix.zarr-version }}
|
|
46
|
+
python -m pip install -e .[${{ inputs.install-extras }}]
|
|
47
|
+
python -m pip list
|
|
48
|
+
|
|
49
|
+
- name: Get witty cache directory
|
|
50
|
+
if: ${{ inputs.witty-cache }}
|
|
51
|
+
id: cache-path
|
|
52
|
+
run: |
|
|
53
|
+
import Cython.Utils
|
|
54
|
+
import os
|
|
55
|
+
|
|
56
|
+
cache_path = os.path.join(Cython.Utils.get_cython_cache_dir(), "witty")
|
|
57
|
+
|
|
58
|
+
with open(os.environ["GITHUB_OUTPUT"], "a") as fh:
|
|
59
|
+
print(f"path={cache_path}", file=fh)
|
|
60
|
+
shell: python
|
|
61
|
+
|
|
62
|
+
- name: Check for witty cache
|
|
63
|
+
uses: actions/cache/restore@v4
|
|
64
|
+
id: witty-cache
|
|
65
|
+
if: ${{ inputs.witty-cache }}
|
|
66
|
+
with:
|
|
67
|
+
path: ${{ steps.cache-path.outputs.path }}
|
|
68
|
+
key: ${{ matrix.platform }} - ${{ matrix.python-version }}
|
|
69
|
+
|
|
70
|
+
- name: Test
|
|
71
|
+
run: pytest --color=yes --cov --cov-report=xml --cov-report=term-missing ${{ inputs.test-target }}
|
|
72
|
+
|
|
73
|
+
- name: Coverage
|
|
74
|
+
uses: codecov/codecov-action@v5
|
|
75
|
+
with:
|
|
76
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
77
|
+
|
|
78
|
+
- name: Save witty cache
|
|
79
|
+
uses: actions/cache/save@v4
|
|
80
|
+
if: ${{ inputs.witty-cache }}
|
|
81
|
+
with:
|
|
82
|
+
path: ${{ steps.cache-path.outputs.path }}
|
|
83
|
+
key: ${{ matrix.platform }} - ${{ matrix.python-version }}
|
geff-0.0/.gitignore
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Temporary files
|
|
10
|
+
*.sw[pmno]
|
|
11
|
+
*.zarr
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv
|
|
15
|
+
|
|
16
|
+
# pixi environments
|
|
17
|
+
.pixi
|
|
18
|
+
*.egg-info
|
|
19
|
+
pixi.lock
|
|
20
|
+
|
|
21
|
+
.DS_Store
|
|
22
|
+
|
|
23
|
+
# Autogenerated docs files
|
|
24
|
+
docs/schema/*
|
|
25
|
+
|
|
26
|
+
# Pytest coverage local files
|
|
27
|
+
.coverage*
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
ci:
|
|
2
|
+
autoupdate_schedule: monthly
|
|
3
|
+
autofix_commit_msg: "style(pre-commit.ci): auto fixes [...]"
|
|
4
|
+
autoupdate_commit_msg: "ci(pre-commit.ci): autoupdate"
|
|
5
|
+
autofix_prs: false
|
|
6
|
+
|
|
7
|
+
repos:
|
|
8
|
+
- repo: https://github.com/crate-ci/typos
|
|
9
|
+
rev: v1
|
|
10
|
+
hooks:
|
|
11
|
+
- id: typos
|
|
12
|
+
|
|
13
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
14
|
+
rev: v0.11.4
|
|
15
|
+
hooks:
|
|
16
|
+
- id: ruff
|
|
17
|
+
args: [--fix]
|
|
18
|
+
- id: ruff-format
|
|
19
|
+
|
|
20
|
+
- repo: https://github.com/abravalheri/validate-pyproject
|
|
21
|
+
rev: v0.24.1
|
|
22
|
+
hooks:
|
|
23
|
+
- id: validate-pyproject
|
|
24
|
+
|
|
25
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
26
|
+
rev: v1.15.0
|
|
27
|
+
hooks:
|
|
28
|
+
- id: mypy
|
|
29
|
+
files: "^src/"
|
|
30
|
+
# # you have to add the things you want to type check against here
|
|
31
|
+
additional_dependencies:
|
|
32
|
+
- types-pyyaml
|
geff-0.0/CONTRIBUTING
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# CONTRIBUTING
|
|
2
|
+
|
|
3
|
+
We recommend using `pixi` for environment management while developing `geff`. See the [pixi docs](https://pixi.sh/dev/) for installation instructions. The following instructions will be focused on pixi-based development, but all of the same tasks can be completed with pip and another environment manager.
|
|
4
|
+
|
|
5
|
+
For local development, clone the repo and install in editable mode.
|
|
6
|
+
```
|
|
7
|
+
git clone https://github.com/funkelab/geff.git
|
|
8
|
+
pixi install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Testing
|
|
12
|
+
To run tests
|
|
13
|
+
```
|
|
14
|
+
pixi run test
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Style
|
|
18
|
+
We utilize `pre-commit` with ruff for linting and formatting. If you would like to run `pre-commit` locally:
|
|
19
|
+
```
|
|
20
|
+
pixi run -e dev pre-commit install
|
|
21
|
+
```
|
|
22
|
+
Alternatively [pre-commit.ci](https://pre-commit.ci/), will run and commit changes on any open PRs.
|
|
23
|
+
|
|
24
|
+
## Releases
|
|
25
|
+
In order to deploy a new version, tag the commit with a version number and push it to github. This will trigger a github action that will build and deploy to PyPI. (see the "deploy" step in workflows/ci.yml). The version number is determined automatically based on the tag.
|
|
26
|
+
|
|
27
|
+
Prior to making a release that bumps the major or minor number, the `supported_versions.yml` needs to be updated and the json schema updated by running `pixi run update-json`.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
git tag -a v0.1.0 -m v0.1.0
|
|
31
|
+
git push --follow-tags
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Docs
|
|
35
|
+
|
|
36
|
+
Docs are written with MkDocs
|
|
37
|
+
|
|
38
|
+
Relevant commends can be run using `pixi run -e docs <mkdocs command>`
|
|
39
|
+
* `mkdocs serve` - Start the live-reloading docs server.
|
|
40
|
+
* `mkdocs build` - Build the documentation site.
|
|
41
|
+
* `mkdocs -h` - Print help message and exit.
|
geff-0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Funke lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
geff-0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: geff
|
|
3
|
+
Version: 0.0
|
|
4
|
+
Summary: Reference implementation of the Graph Exchange File Format
|
|
5
|
+
License: MIT License
|
|
6
|
+
Project-URL: repository, https://github.com/live-image-tracking-tools/geff
|
|
7
|
+
Project-URL: homepage, https://github.com/live-image-tracking-tools/geff
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Natural Language :: English
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: zarr<4,>2
|
|
19
|
+
Requires-Dist: pydantic
|
|
20
|
+
Requires-Dist: pyyaml
|
|
21
|
+
Requires-Dist: numcodecs<0.16
|
|
22
|
+
Requires-Dist: networkx
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=8.3.4; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
26
|
+
Requires-Dist: mypy; extra == "dev"
|
|
27
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
28
|
+
Requires-Dist: ruff; extra == "dev"
|
|
29
|
+
Requires-Dist: ipython; extra == "dev"
|
|
30
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
31
|
+
Provides-Extra: docs
|
|
32
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
33
|
+
Requires-Dist: mkdocstrings[python]; extra == "docs"
|
|
34
|
+
Requires-Dist: mkdocs-api-autonav; extra == "docs"
|
|
35
|
+
Requires-Dist: mkdocs-include-markdown-plugin; extra == "docs"
|
|
36
|
+
Requires-Dist: mike; extra == "docs"
|
|
37
|
+
Requires-Dist: json-schema-for-humans; extra == "docs"
|
|
38
|
+
Requires-Dist: typing-extensions; extra == "docs"
|
|
39
|
+
Provides-Extra: bench
|
|
40
|
+
Requires-Dist: pytest-benchmark; extra == "bench"
|
|
41
|
+
Requires-Dist: tabulate; extra == "bench"
|
|
42
|
+
Requires-Dist: pandas; extra == "bench"
|
|
43
|
+
Requires-Dist: typer; extra == "bench"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# Graph Exchange File Format (geff)
|
|
47
|
+
|
|
48
|
+
<!--intro-start-->
|
|
49
|
+
|
|
50
|
+
[](https://github.com/funkelab/geff/raw/main/LICENSE)
|
|
51
|
+
[](https://pypi.org/project/geff)
|
|
52
|
+
[](https://python.org)
|
|
53
|
+
[](https://github.com/funkelab/geff/actions/workflows/ci.yaml)
|
|
54
|
+
|
|
55
|
+
geff is a specification for a file format for **exchanging** spatial graph data. It is not intended to be mutable, editable, chunked, or optimized for use in an application setting.
|
|
56
|
+
|
|
57
|
+
geff is the specification of the file format, but the library also includes implementations for writing from and reading to a networkx graph, a common Python in-memory graph data structure. The library uses semantic versioning, where changes to the specification bump the major or minor versions, and bugfixes for the example implementation bumps the patch version.
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
pip install geff
|
|
63
|
+
```
|
|
64
|
+
<!--intro-end-->
|
geff-0.0/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Graph Exchange File Format (geff)
|
|
2
|
+
|
|
3
|
+
<!--intro-start-->
|
|
4
|
+
|
|
5
|
+
[](https://github.com/funkelab/geff/raw/main/LICENSE)
|
|
6
|
+
[](https://pypi.org/project/geff)
|
|
7
|
+
[](https://python.org)
|
|
8
|
+
[](https://github.com/funkelab/geff/actions/workflows/ci.yaml)
|
|
9
|
+
|
|
10
|
+
geff is a specification for a file format for **exchanging** spatial graph data. It is not intended to be mutable, editable, chunked, or optimized for use in an application setting.
|
|
11
|
+
|
|
12
|
+
geff is the specification of the file format, but the library also includes implementations for writing from and reading to a networkx graph, a common Python in-memory graph data structure. The library uses semantic versioning, where changes to the specification bump the major or minor versions, and bugfixes for the example implementation bumps the patch version.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
pip install geff
|
|
18
|
+
```
|
|
19
|
+
<!--intro-end-->
|
geff-0.0/docs/index.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Geff specification
|
|
2
|
+
|
|
3
|
+
The graph exchange file format is `zarr` based. A graph is stored in a zarr group, which can have any name. This allows storing multiple `geff` graphs inside the same zarr root directory. A `geff` group is identified by the presence of a `geff_version` attribute in the `.zattrs`. Other `geff` metadata is also stored in the `.zattrs` file of the `geff` group. The `geff` group must contain a `nodes` group and an `edges` group.
|
|
4
|
+
|
|
5
|
+
## Geff metadata
|
|
6
|
+
|
|
7
|
+
{%
|
|
8
|
+
include "schema/schema.html"
|
|
9
|
+
%}
|
|
10
|
+
|
|
11
|
+
## The `nodes` group
|
|
12
|
+
The nodes group will contain an `ids` array and an `attrs` group.
|
|
13
|
+
|
|
14
|
+
### The `ids` array
|
|
15
|
+
The `nodes\ids` array is a 1D array of node IDs of length `N` > 0, where `N` is the number of nodes in the graph. Node ids must be unique. Node IDs can have any type supported by zarr, but we recommend integer dtypes. For large graphs, `uint64` might be necessary to provide enough range for every node to have a unique ID.
|
|
16
|
+
|
|
17
|
+
### The `attrs` group and `node attribute` groups
|
|
18
|
+
The `nodes\attrs` group will contain one or more `node attribute` groups, each with a `values` array and an optional `missing` array.
|
|
19
|
+
|
|
20
|
+
- `values` arrays can be any zarr supported dtype, and can be N-dimensional. The first dimension of the `values` array must have the same length as the node `ids` array, such that each row of the attribute `values` array stores the attribute for the node at that index in the ids array.
|
|
21
|
+
- The `missing` array is an optional, a one dimensional boolean array to support attributes that are not present on all nodes. A 1 at an index in the `missing` array indicates that the `value` of that attribute for the node at that index is None, and the value in the `values` array at that index should be ignored. If the `missing` array is not present, that means that all nodes have values for the attribute.
|
|
22
|
+
|
|
23
|
+
!!! note
|
|
24
|
+
When writing a graph with missing attributes to the geff format, you must fill in a dummy value in the `values` array for the nodes that are missing the attribute, in order to keep the indices aligned with the node ids.
|
|
25
|
+
|
|
26
|
+
- The `position` group is a special node attribute group that must be present and does not allow missing attributes.
|
|
27
|
+
- The `seg_id` group is an optional, special node attribute group that stores the segmenatation label for each node. The `seg_id` values do not need to be unique, in case labels are repeated between time points. If the `seg_id` group is not present, it is assumed that the graph is not associated with a segmentation.
|
|
28
|
+
<!-- Perhaps we just let the user specify the seg id attribute in the metadata instead? Then you can point it to the node ids if you wanted to -->
|
|
29
|
+
|
|
30
|
+
## The `edges` group
|
|
31
|
+
Similar to the `nodes` group, the `edges` group will contain an `ids` array and an `attrs` group. If there are no edges in the graph, the edge group is not created.
|
|
32
|
+
|
|
33
|
+
### The `ids` array
|
|
34
|
+
The `edges\ids` array is a 2D array with the same dtype as the `nodes\ids` array. It has shape `(2, E)`, where `E` is the number of edges in the graph. All elements in the `edges\ids` array must also be present in the `nodes\ids` array.
|
|
35
|
+
Each row represents an edge between two nodes. For directed graphs, the first column is the source nodes and the second column holds the target nodes. For undirected graphs, the order is arbitrary.
|
|
36
|
+
Edges should be unique (no multiple edges between the same two nodes) and edges from a node to itself are not supported.
|
|
37
|
+
|
|
38
|
+
### The `attrs` group and `edge attribute` groups
|
|
39
|
+
The `edges\attrs` group will contain zero or more `edge attribute` groups, each with a `values` array and an optional `missing` array.
|
|
40
|
+
|
|
41
|
+
- `values` arrays can be any zarr supported dtype, and can be N-dimensional. The first dimension of the `values` array must have the same length as the `edges\ids` array, such that each row of the attribute `values` array stores the attribute for the edge at that index in the ids array.
|
|
42
|
+
- The `missing` array is an optional, a one dimensional boolean array to support attributes that are not present on all edges. A 1 at an index in the `missing` array indicates that the `value` of that attribute for the edge at that index is missing, and the value in the `values` array at that index should be ignored. If the `missing` array is not present, that means that all edges have values for the attribute.
|
|
43
|
+
|
|
44
|
+
If you do not have any edge attributes, the `edges\attrs` group should still be present, but empty.
|
|
45
|
+
|
|
46
|
+
## Example file structure and metadata
|
|
47
|
+
|
|
48
|
+
TODO: Example metadata for this file structure
|
|
49
|
+
``` python
|
|
50
|
+
/path/to.zarr
|
|
51
|
+
/tracking_graph
|
|
52
|
+
.zattrs # graph metadata with `geff_version`
|
|
53
|
+
nodes/
|
|
54
|
+
ids # shape: (N,) dtype: uint64
|
|
55
|
+
attrs/
|
|
56
|
+
position/
|
|
57
|
+
values # shape: (N, 3) dtype: float16
|
|
58
|
+
color/
|
|
59
|
+
values # shape: (N, 4) dtype: float16
|
|
60
|
+
missing # shape: (N,) dtype: bool
|
|
61
|
+
edges/
|
|
62
|
+
ids # shape: (E, 2) dtype: uint64
|
|
63
|
+
attrs/
|
|
64
|
+
distance/
|
|
65
|
+
values # shape: (E,) dtype: float16
|
|
66
|
+
score/
|
|
67
|
+
values # shape: (E,) dtype: float16
|
|
68
|
+
missing # shape: (E,) dtype: bool
|
|
69
|
+
# optional:
|
|
70
|
+
/segmentation
|
|
71
|
+
|
|
72
|
+
# unspecified, but totally okay:
|
|
73
|
+
/raw
|
|
74
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# What is geff?
|
|
2
|
+
|
|
3
|
+
`geff` is a graph exchange file format that seeks to fulfill the following needs:
|
|
4
|
+
- Provide a storage/exchange format for graphs and optional segmentation
|
|
5
|
+
- Provide a common API with reference implementations for use in other projects
|
|
6
|
+
|
|
7
|
+
## Design Decisions and Assumptions
|
|
8
|
+
|
|
9
|
+
- Raw image data is not included in the `geff` spec. However, to keep nodes linked to segmentation labels, support for specifying the seg_id of each node in a standard way, along with the path to the segmentation, are included in the `spec`.
|
|
10
|
+
- Since `geff` is an exchange format, we do not provide support for searching or filtering.
|
|
11
|
+
- We do not provide support for editing or changing the graph on the fly.
|
|
12
|
+
- In order to support efficient reading/writing, we assume the graph can fit into memory.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"description": "Geff metadata schema to validate the attributes json file in a geff zarr", "properties": {"geff_version": {"pattern": "(0\\.0)|(0\\.1)", "title": "Geff Version", "type": "string"}, "directed": {"title": "Directed", "type": "boolean"}, "roi_min": {"items": {"type": "number"}, "title": "Roi Min", "type": "array"}, "roi_max": {"items": {"type": "number"}, "title": "Roi Max", "type": "array"}, "position_attr": {"default": "position", "title": "Position Attr", "type": "string"}, "axis_names": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "default": null, "title": "Axis Names"}, "axis_units": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "default": null, "title": "Axis Units"}}, "required": ["geff_version", "directed", "roi_min", "roi_max"], "title": "geff_metadata", "type": "object"}
|