labapi 1.0.3__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.
- labapi-1.0.3/.github/ISSUE_TEMPLATE/bug_report.yml +110 -0
- labapi-1.0.3/.github/ISSUE_TEMPLATE/config.yml +8 -0
- labapi-1.0.3/.github/ISSUE_TEMPLATE/feature_request.yml +50 -0
- labapi-1.0.3/.github/workflows/docs.yml +29 -0
- labapi-1.0.3/.github/workflows/format.yml +13 -0
- labapi-1.0.3/.github/workflows/integration_tests.yml +43 -0
- labapi-1.0.3/.github/workflows/lint.yml +13 -0
- labapi-1.0.3/.github/workflows/publish.yml +40 -0
- labapi-1.0.3/.github/workflows/python_check.yml +47 -0
- labapi-1.0.3/.github/workflows/typecheck.yml +19 -0
- labapi-1.0.3/.github/workflows/unit_tests.yml +12 -0
- labapi-1.0.3/.gitignore +55 -0
- labapi-1.0.3/.mockenv +10 -0
- labapi-1.0.3/.pre-commit-config.yaml +27 -0
- labapi-1.0.3/.zenodo.json +20 -0
- labapi-1.0.3/CLAUDE.md +73 -0
- labapi-1.0.3/CONTRIBUTING.md +70 -0
- labapi-1.0.3/LICENSE +121 -0
- labapi-1.0.3/PKG-INFO +210 -0
- labapi-1.0.3/README.md +172 -0
- labapi-1.0.3/conftest.py +391 -0
- labapi-1.0.3/docs/Makefile +20 -0
- labapi-1.0.3/docs/make.bat +35 -0
- labapi-1.0.3/docs/source/_static/.gitkeep +1 -0
- labapi-1.0.3/docs/source/_templates/custom-class-template.rst +32 -0
- labapi-1.0.3/docs/source/_templates/custom-module-template.rst +68 -0
- labapi-1.0.3/docs/source/conf.py +66 -0
- labapi-1.0.3/docs/source/examples/csv_table.rst +174 -0
- labapi-1.0.3/docs/source/examples/folder_download.rst +153 -0
- labapi-1.0.3/docs/source/examples/index.rst +81 -0
- labapi-1.0.3/docs/source/examples/json_sync.rst +95 -0
- labapi-1.0.3/docs/source/faq.rst +123 -0
- labapi-1.0.3/docs/source/guide/api_calls.rst +136 -0
- labapi-1.0.3/docs/source/guide/architecture.rst +257 -0
- labapi-1.0.3/docs/source/guide/auth.rst +186 -0
- labapi-1.0.3/docs/source/guide/clearing_cache.rst +175 -0
- labapi-1.0.3/docs/source/guide/contributing.rst +158 -0
- labapi-1.0.3/docs/source/guide/entries.rst +165 -0
- labapi-1.0.3/docs/source/guide/exceptions.rst +61 -0
- labapi-1.0.3/docs/source/guide/index.rst +38 -0
- labapi-1.0.3/docs/source/guide/index_access.rst +89 -0
- labapi-1.0.3/docs/source/guide/integration_design.rst +59 -0
- labapi-1.0.3/docs/source/guide/json_entries.rst +63 -0
- labapi-1.0.3/docs/source/guide/limitations.rst +105 -0
- labapi-1.0.3/docs/source/guide/paths.rst +250 -0
- labapi-1.0.3/docs/source/index.rst +60 -0
- labapi-1.0.3/docs/source/quick_start/copying.rst +117 -0
- labapi-1.0.3/docs/source/quick_start/creating_pages.rst +113 -0
- labapi-1.0.3/docs/source/quick_start/deleting.rst +75 -0
- labapi-1.0.3/docs/source/quick_start/first_calls.rst +211 -0
- labapi-1.0.3/docs/source/quick_start/index.rst +37 -0
- labapi-1.0.3/docs/source/quick_start/installation.rst +123 -0
- labapi-1.0.3/docs/source/quick_start/navigating.rst +180 -0
- labapi-1.0.3/docs/source/quick_start/tutorial.rst +91 -0
- labapi-1.0.3/docs/source/quick_start/uploading_files.rst +76 -0
- labapi-1.0.3/docs/source/quick_start/writing_rich_text.rst +114 -0
- labapi-1.0.3/docs/source/reference/index.rst +24 -0
- labapi-1.0.3/examples/csv_table/README.md +58 -0
- labapi-1.0.3/examples/csv_table/csv_table.py +299 -0
- labapi-1.0.3/examples/csv_table/pyproject.toml +10 -0
- labapi-1.0.3/examples/csv_table/sample_data.csv +5 -0
- labapi-1.0.3/examples/folder_download/README.md +60 -0
- labapi-1.0.3/examples/folder_download/folder_download.py +224 -0
- labapi-1.0.3/examples/folder_download/populate_notebook.py +102 -0
- labapi-1.0.3/examples/folder_download/pyproject.toml +9 -0
- labapi-1.0.3/examples/json_sync/README.md +55 -0
- labapi-1.0.3/examples/json_sync/json_sync.py +212 -0
- labapi-1.0.3/examples/json_sync/pyproject.toml +9 -0
- labapi-1.0.3/examples/json_sync/sample_data/config.json +8 -0
- labapi-1.0.3/examples/json_sync/sample_data/results.json +6 -0
- labapi-1.0.3/examples/model_logging/README.md +41 -0
- labapi-1.0.3/examples/model_logging/model_logger.py +142 -0
- labapi-1.0.3/examples/model_logging/pyproject.toml +9 -0
- labapi-1.0.3/examples/model_logging/run_test.py +48 -0
- labapi-1.0.3/examples/model_logging/test_data/dummy_figure.png +0 -0
- labapi-1.0.3/examples/model_logging/test_data/metrics.json +7 -0
- labapi-1.0.3/examples/model_logging/test_data/results.csv +6 -0
- labapi-1.0.3/examples/notebook_logging/.gitignore +2 -0
- labapi-1.0.3/examples/notebook_logging/README.md +87 -0
- labapi-1.0.3/examples/notebook_logging/example.ipynb +171 -0
- labapi-1.0.3/examples/notebook_logging/notebook_logger.py +340 -0
- labapi-1.0.3/examples/notebook_logging/pyproject.toml +11 -0
- labapi-1.0.3/pyproject.toml +157 -0
- labapi-1.0.3/pyrightconfig.json +14 -0
- labapi-1.0.3/setup.cfg +4 -0
- labapi-1.0.3/src/labapi/__init__.py +77 -0
- labapi-1.0.3/src/labapi/client.py +835 -0
- labapi-1.0.3/src/labapi/entry/__init__.py +28 -0
- labapi-1.0.3/src/labapi/entry/attachment.py +191 -0
- labapi-1.0.3/src/labapi/entry/collection.py +209 -0
- labapi-1.0.3/src/labapi/entry/comment.py +15 -0
- labapi-1.0.3/src/labapi/entry/entries/__init__.py +22 -0
- labapi-1.0.3/src/labapi/entry/entries/attachment.py +148 -0
- labapi-1.0.3/src/labapi/entry/entries/base.py +139 -0
- labapi-1.0.3/src/labapi/entry/entries/text.py +69 -0
- labapi-1.0.3/src/labapi/entry/entries/unknown.py +41 -0
- labapi-1.0.3/src/labapi/entry/entries/widget.py +29 -0
- labapi-1.0.3/src/labapi/exceptions.py +80 -0
- labapi-1.0.3/src/labapi/py.typed +1 -0
- labapi-1.0.3/src/labapi/tree/__init__.py +21 -0
- labapi-1.0.3/src/labapi/tree/collection.py +163 -0
- labapi-1.0.3/src/labapi/tree/directory.py +57 -0
- labapi-1.0.3/src/labapi/tree/mixins.py +852 -0
- labapi-1.0.3/src/labapi/tree/notebook.py +69 -0
- labapi-1.0.3/src/labapi/tree/page.py +218 -0
- labapi-1.0.3/src/labapi/user.py +146 -0
- labapi-1.0.3/src/labapi/util/__init__.py +45 -0
- labapi-1.0.3/src/labapi/util/browser.py +125 -0
- labapi-1.0.3/src/labapi/util/extract.py +124 -0
- labapi-1.0.3/src/labapi/util/path.py +367 -0
- labapi-1.0.3/src/labapi/util/types.py +76 -0
- labapi-1.0.3/src/labapi.egg-info/PKG-INFO +210 -0
- labapi-1.0.3/src/labapi.egg-info/SOURCES.txt +146 -0
- labapi-1.0.3/src/labapi.egg-info/dependency_links.txt +1 -0
- labapi-1.0.3/src/labapi.egg-info/requires.txt +10 -0
- labapi-1.0.3/src/labapi.egg-info/top_level.txt +1 -0
- labapi-1.0.3/tests/__init__.py +1 -0
- labapi-1.0.3/tests/conftest.py +43 -0
- labapi-1.0.3/tests/entry/__init__.py +1 -0
- labapi-1.0.3/tests/entry/entries/__init__.py +1 -0
- labapi-1.0.3/tests/entry/entries/test_attachment.py +173 -0
- labapi-1.0.3/tests/entry/entries/test_base.py +66 -0
- labapi-1.0.3/tests/entry/entries/test_text.py +115 -0
- labapi-1.0.3/tests/entry/entries/test_widget.py +49 -0
- labapi-1.0.3/tests/entry/test_attachment.py +179 -0
- labapi-1.0.3/tests/entry/test_collection.py +456 -0
- labapi-1.0.3/tests/examples/__init__.py +1 -0
- labapi-1.0.3/tests/examples/test_csv_table.py +153 -0
- labapi-1.0.3/tests/examples/test_folder_download.py +89 -0
- labapi-1.0.3/tests/examples/test_json_sync.py +149 -0
- labapi-1.0.3/tests/test_browser.py +175 -0
- labapi-1.0.3/tests/test_client.py +880 -0
- labapi-1.0.3/tests/test_entry.json +3 -0
- labapi-1.0.3/tests/test_integration.py +376 -0
- labapi-1.0.3/tests/test_user.py +139 -0
- labapi-1.0.3/tests/tree/__init__.py +1 -0
- labapi-1.0.3/tests/tree/test_collection.py +241 -0
- labapi-1.0.3/tests/tree/test_directory.py +121 -0
- labapi-1.0.3/tests/tree/test_mixins.py +752 -0
- labapi-1.0.3/tests/tree/test_notebook.py +47 -0
- labapi-1.0.3/tests/tree/test_page.py +376 -0
- labapi-1.0.3/tests/util/__init__.py +1 -0
- labapi-1.0.3/tests/util/test_behavior.py +23 -0
- labapi-1.0.3/tests/util/test_extract.py +298 -0
- labapi-1.0.3/tests/util/test_index.py +21 -0
- labapi-1.0.3/tests/util/test_notebookinit.py +49 -0
- labapi-1.0.3/tests/util/test_path.py +143 -0
- labapi-1.0.3/uv.lock +1683 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a reproducible problem in labapi.
|
|
3
|
+
title: "[Bug]: "
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to report a problem.
|
|
9
|
+
|
|
10
|
+
Please redact API credentials, auth keys, notebook content, and any other sensitive data before submitting.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: summary
|
|
13
|
+
attributes:
|
|
14
|
+
label: Summary
|
|
15
|
+
description: A short description of the problem and the impact it has on your workflow.
|
|
16
|
+
placeholder: default_authenticate() raises an exception after opening the browser callback flow.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: input
|
|
20
|
+
id: labapi-version
|
|
21
|
+
attributes:
|
|
22
|
+
label: labapi version
|
|
23
|
+
description: The package version you are using, or the commit/branch name if installed from source.
|
|
24
|
+
placeholder: 0.1.0, main, or a git commit SHA
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
- type: dropdown
|
|
28
|
+
id: python-version
|
|
29
|
+
attributes:
|
|
30
|
+
label: Python version
|
|
31
|
+
description: Which Python version reproduces the issue?
|
|
32
|
+
options:
|
|
33
|
+
- "3.12"
|
|
34
|
+
- "3.13"
|
|
35
|
+
- Other
|
|
36
|
+
validations:
|
|
37
|
+
required: true
|
|
38
|
+
- type: dropdown
|
|
39
|
+
id: install-profile
|
|
40
|
+
attributes:
|
|
41
|
+
label: Install profile
|
|
42
|
+
description: Which install path most closely matches your environment?
|
|
43
|
+
options:
|
|
44
|
+
- Installed from source with `uv sync`
|
|
45
|
+
- `pip install labapi`
|
|
46
|
+
- `pip install 'labapi[dotenv]'`
|
|
47
|
+
- `pip install 'labapi[builtin-auth]'`
|
|
48
|
+
- `pip install 'labapi[dotenv,builtin-auth]'`
|
|
49
|
+
- Other
|
|
50
|
+
validations:
|
|
51
|
+
required: true
|
|
52
|
+
- type: textarea
|
|
53
|
+
id: environment
|
|
54
|
+
attributes:
|
|
55
|
+
label: Environment
|
|
56
|
+
description: Include your OS, shell, and any other environment details that matter.
|
|
57
|
+
placeholder: |
|
|
58
|
+
Windows 11
|
|
59
|
+
PowerShell 7
|
|
60
|
+
API_URL=https://api.labarchives.com
|
|
61
|
+
Running behind a VPN
|
|
62
|
+
validations:
|
|
63
|
+
required: true
|
|
64
|
+
- type: textarea
|
|
65
|
+
id: steps
|
|
66
|
+
attributes:
|
|
67
|
+
label: Steps to reproduce
|
|
68
|
+
description: Share the smallest sequence of steps that reproduces the issue.
|
|
69
|
+
placeholder: |
|
|
70
|
+
1. Create a client with `Client()`
|
|
71
|
+
2. Call `default_authenticate()`
|
|
72
|
+
3. Complete the browser auth flow
|
|
73
|
+
4. Observe the exception
|
|
74
|
+
validations:
|
|
75
|
+
required: true
|
|
76
|
+
- type: textarea
|
|
77
|
+
id: expected
|
|
78
|
+
attributes:
|
|
79
|
+
label: Expected behavior
|
|
80
|
+
placeholder: The client should authenticate and return the current user object.
|
|
81
|
+
validations:
|
|
82
|
+
required: true
|
|
83
|
+
- type: textarea
|
|
84
|
+
id: actual
|
|
85
|
+
attributes:
|
|
86
|
+
label: Actual behavior
|
|
87
|
+
placeholder: The browser flow completes, but the callback server times out after 60 seconds.
|
|
88
|
+
validations:
|
|
89
|
+
required: true
|
|
90
|
+
- type: textarea
|
|
91
|
+
id: repro
|
|
92
|
+
attributes:
|
|
93
|
+
label: Minimal reproducible example
|
|
94
|
+
description: If possible, share a small script that reproduces the problem.
|
|
95
|
+
render: python
|
|
96
|
+
- type: textarea
|
|
97
|
+
id: logs
|
|
98
|
+
attributes:
|
|
99
|
+
label: Traceback or logs
|
|
100
|
+
description: Paste any error output, traceback, or debug logs that may help.
|
|
101
|
+
render: shell
|
|
102
|
+
- type: checkboxes
|
|
103
|
+
id: checks
|
|
104
|
+
attributes:
|
|
105
|
+
label: Checks
|
|
106
|
+
options:
|
|
107
|
+
- label: I searched the existing issues before opening this report.
|
|
108
|
+
required: true
|
|
109
|
+
- label: I redacted secrets and sensitive notebook data from the details above.
|
|
110
|
+
required: true
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Usage and setup docs
|
|
4
|
+
url: https://github.com/nimh-dsst/labapi/tree/main/docs/source
|
|
5
|
+
about: Start here for installation, authentication, quick-start, and FAQ guidance.
|
|
6
|
+
- name: Contributing guide
|
|
7
|
+
url: https://github.com/nimh-dsst/labapi/blob/main/CONTRIBUTING.md
|
|
8
|
+
about: Review local setup, testing commands, and code-quality expectations for contributions.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an improvement to the library, docs, or developer workflow.
|
|
3
|
+
title: "[Feature]: "
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for suggesting an improvement to labapi.
|
|
9
|
+
|
|
10
|
+
Clear examples of the workflow you want to support make it much easier to evaluate the request.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: problem
|
|
13
|
+
attributes:
|
|
14
|
+
label: Problem to solve
|
|
15
|
+
description: What are you trying to do, and what is hard or missing today?
|
|
16
|
+
placeholder: I need a simpler way to authenticate in a headless CI job without wiring my own callback server.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: proposal
|
|
21
|
+
attributes:
|
|
22
|
+
label: Proposed solution
|
|
23
|
+
description: Describe the API, behavior, or docs change you would like to see.
|
|
24
|
+
placeholder: Add a helper that exchanges a one-time auth token for a session using environment variables.
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: alternatives
|
|
29
|
+
attributes:
|
|
30
|
+
label: Alternatives considered
|
|
31
|
+
description: Share any workarounds, adjacent APIs, or alternative approaches you have tried.
|
|
32
|
+
placeholder: Today I build the auth URL myself and parse the callback in a separate script.
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: examples
|
|
35
|
+
attributes:
|
|
36
|
+
label: Example usage
|
|
37
|
+
description: If helpful, sketch the code or command-line flow you want.
|
|
38
|
+
render: python
|
|
39
|
+
- type: textarea
|
|
40
|
+
id: context
|
|
41
|
+
attributes:
|
|
42
|
+
label: Additional context
|
|
43
|
+
description: Add links, screenshots, docs references, or other details that would help.
|
|
44
|
+
- type: checkboxes
|
|
45
|
+
id: checks
|
|
46
|
+
attributes:
|
|
47
|
+
label: Checks
|
|
48
|
+
options:
|
|
49
|
+
- label: I searched the existing issues before opening this request.
|
|
50
|
+
required: true
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
docs:
|
|
9
|
+
name: Docs build
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout code
|
|
14
|
+
uses: actions/checkout@v5
|
|
15
|
+
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v7
|
|
18
|
+
with:
|
|
19
|
+
enable-cache: true
|
|
20
|
+
version: "latest"
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
run: uv python install 3.13
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: uv sync --all-groups
|
|
27
|
+
|
|
28
|
+
- name: Build Sphinx docs
|
|
29
|
+
run: uv run sphinx-build -b html docs/source docs/_build
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Integration Test Suite
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
la_key:
|
|
7
|
+
description: LabArchives Authentication Token
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
la_email:
|
|
11
|
+
description: LabArchives Authentication la_email
|
|
12
|
+
required: true
|
|
13
|
+
type: string
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout code
|
|
21
|
+
uses: actions/checkout@v5
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v7
|
|
25
|
+
with:
|
|
26
|
+
enable-cache: true
|
|
27
|
+
version: "latest"
|
|
28
|
+
|
|
29
|
+
- name: Set up Python
|
|
30
|
+
run: uv python install 3.13
|
|
31
|
+
|
|
32
|
+
- name: Install dependencies
|
|
33
|
+
run: uv sync --all-groups
|
|
34
|
+
|
|
35
|
+
- name: Run tests with pytest
|
|
36
|
+
env:
|
|
37
|
+
API_URL: ${{ secrets.API_URL }}
|
|
38
|
+
ACCESS_KEYID: ${{ secrets.AKID }}
|
|
39
|
+
ACCESS_PWD: ${{ secrets.AKPASS }}
|
|
40
|
+
AUTH_KEY: ${{ github.event.inputs.la_key }}
|
|
41
|
+
AUTH_EMAIL: ${{ github.event.inputs.la_email }}
|
|
42
|
+
NOTEBOOK: ${{ secrets.NOTEBOOK }}
|
|
43
|
+
run: uv run pytest tests/test_integration.py
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
name: Publish to PyPI
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
environment:
|
|
18
|
+
name: pypi
|
|
19
|
+
url: https://pypi.org/project/labapi/
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout code
|
|
23
|
+
uses: actions/checkout@v5
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
|
|
27
|
+
- name: Install uv
|
|
28
|
+
uses: astral-sh/setup-uv@v7
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
version: "latest"
|
|
32
|
+
|
|
33
|
+
- name: Set up Python
|
|
34
|
+
run: uv python install 3.13
|
|
35
|
+
|
|
36
|
+
- name: Build distributions
|
|
37
|
+
run: uv build --python 3.13 --clear --no-build-logs
|
|
38
|
+
|
|
39
|
+
- name: Publish to PyPI
|
|
40
|
+
run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Python Check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
job_name:
|
|
7
|
+
required: true
|
|
8
|
+
type: string
|
|
9
|
+
command:
|
|
10
|
+
required: true
|
|
11
|
+
type: string
|
|
12
|
+
append_python_version_arg:
|
|
13
|
+
required: false
|
|
14
|
+
type: boolean
|
|
15
|
+
default: false
|
|
16
|
+
python_versions:
|
|
17
|
+
required: false
|
|
18
|
+
type: string
|
|
19
|
+
default: '["3.12", "3.13"]'
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
check:
|
|
23
|
+
name: ${{ inputs.job_name }} (Python ${{ matrix.python-version }})
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
python-version: ${{ fromJSON(inputs.python_versions) }}
|
|
29
|
+
|
|
30
|
+
steps:
|
|
31
|
+
- name: Checkout code
|
|
32
|
+
uses: actions/checkout@v5
|
|
33
|
+
|
|
34
|
+
- name: Install uv
|
|
35
|
+
uses: astral-sh/setup-uv@v7
|
|
36
|
+
with:
|
|
37
|
+
enable-cache: true
|
|
38
|
+
version: "latest"
|
|
39
|
+
|
|
40
|
+
- name: Set up Python
|
|
41
|
+
run: uv python install ${{ matrix.python-version }}
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: uv sync --all-groups
|
|
45
|
+
|
|
46
|
+
- name: Run check
|
|
47
|
+
run: ${{ inputs.command }}${{ inputs.append_python_version_arg && format(' --python-version {0}', matrix.python-version) || '' }}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Type Check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
pyright:
|
|
9
|
+
uses: ./.github/workflows/python_check.yml
|
|
10
|
+
with:
|
|
11
|
+
job_name: Pyright
|
|
12
|
+
command: uv run pyright
|
|
13
|
+
|
|
14
|
+
ty:
|
|
15
|
+
uses: ./.github/workflows/python_check.yml
|
|
16
|
+
with:
|
|
17
|
+
job_name: ty
|
|
18
|
+
command: uv run ty check
|
|
19
|
+
append_python_version_arg: true
|
labapi-1.0.3/.gitignore
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
tests/__pycache__
|
|
7
|
+
wheels/
|
|
8
|
+
*.egg-info
|
|
9
|
+
|
|
10
|
+
# Virtual environments
|
|
11
|
+
.venv
|
|
12
|
+
|
|
13
|
+
.env
|
|
14
|
+
.python-version
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Coverage reports
|
|
20
|
+
.coverage
|
|
21
|
+
|
|
22
|
+
# IDE files
|
|
23
|
+
.vscode/
|
|
24
|
+
.idea/
|
|
25
|
+
*.iml
|
|
26
|
+
.idea
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
.claude/
|
|
30
|
+
.notes
|
|
31
|
+
.environment-*
|
|
32
|
+
.mcp.json
|
|
33
|
+
|
|
34
|
+
# Sandbox stub files (empty placeholders created by Claude Code's sandbox)
|
|
35
|
+
.gitconfig
|
|
36
|
+
.gitmodules
|
|
37
|
+
.zprofile
|
|
38
|
+
.zshrc
|
|
39
|
+
.bashrc
|
|
40
|
+
.bash_profile
|
|
41
|
+
.profile
|
|
42
|
+
.ripgreprc
|
|
43
|
+
HEAD
|
|
44
|
+
config
|
|
45
|
+
hooks
|
|
46
|
+
objects
|
|
47
|
+
refs
|
|
48
|
+
|
|
49
|
+
docs/build/
|
|
50
|
+
docs/_build/
|
|
51
|
+
docs/source/reference/generated/
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
.ipynb-checkpoints
|
|
55
|
+
.tmpdocs
|
labapi-1.0.3/.mockenv
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# LabArchives API Client credentials
|
|
2
|
+
API_URL=https://api.labarchives.com
|
|
3
|
+
ACCESS_KEYID=your_access_key_id_here
|
|
4
|
+
ACCESS_PWD=your_access_password_here
|
|
5
|
+
|
|
6
|
+
# Integration test settings
|
|
7
|
+
AUTH_EMAIL=your_email@example.com
|
|
8
|
+
AUTH_KEY=your_auth_key_here
|
|
9
|
+
AUTH_INTERACTIVE=false
|
|
10
|
+
NOTEBOOK=My Test Notebook
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: local
|
|
3
|
+
hooks:
|
|
4
|
+
- id: pyright-check
|
|
5
|
+
name: Run Pyright
|
|
6
|
+
entry: uv
|
|
7
|
+
args: [run, pyright]
|
|
8
|
+
language: system
|
|
9
|
+
pass_filenames: false
|
|
10
|
+
always_run: true
|
|
11
|
+
- id: pytest-check
|
|
12
|
+
name: Run Pytest (pre-push)
|
|
13
|
+
entry: uv
|
|
14
|
+
args: [run, pytest, --no-cov]
|
|
15
|
+
language: system
|
|
16
|
+
pass_filenames: false
|
|
17
|
+
always_run: true
|
|
18
|
+
stages: [pre-push]
|
|
19
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
20
|
+
# Ruff version.
|
|
21
|
+
rev: v0.14.11
|
|
22
|
+
hooks:
|
|
23
|
+
# Run the linter.
|
|
24
|
+
- id: ruff-check
|
|
25
|
+
args: [ --fix ]
|
|
26
|
+
# Run the formatter.
|
|
27
|
+
- id: ruff-format
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "labapi",
|
|
3
|
+
"description": "Python client for the LabArchives API",
|
|
4
|
+
"creators": [
|
|
5
|
+
{
|
|
6
|
+
"name": "Li, Christoph",
|
|
7
|
+
"affiliation": "National Institute of Mental Health",
|
|
8
|
+
"orcid": "0009-0009-4624-2578"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "Lawrimore, Josh",
|
|
12
|
+
"affiliation": "National Institute of Mental Health",
|
|
13
|
+
"orcid": "0000-0003-2301-9073"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"keywords": ["Electronic Lab Notebook", "ELN", "LabArchives", "API"],
|
|
17
|
+
"license": "CC0-1.0",
|
|
18
|
+
"access_right": "open",
|
|
19
|
+
"upload_type": "software"
|
|
20
|
+
}
|
labapi-1.0.3/CLAUDE.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
**Important:** Check `.environment-setup` if it exists - it contains host-specific instructions (e.g., using Nix instead of uv).
|
|
6
|
+
|
|
7
|
+
## Project Overview
|
|
8
|
+
|
|
9
|
+
`labapi` is a Python client library for the LabArchives API, providing an object-oriented interface for managing notebooks, folders, pages, and entries. The LabArchives API uses XML, and requests are signed with HMAC-SHA512.
|
|
10
|
+
|
|
11
|
+
## Build & Development Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Setup (using uv)
|
|
15
|
+
uv sync
|
|
16
|
+
source .venv/bin/activate
|
|
17
|
+
|
|
18
|
+
# Run all tests with coverage
|
|
19
|
+
pytest
|
|
20
|
+
|
|
21
|
+
# Run specific test file
|
|
22
|
+
pytest tests/test_unit.py
|
|
23
|
+
pytest tests/test_integration.py # requires LA_KEY and LA_EMAIL env vars
|
|
24
|
+
|
|
25
|
+
# Lint and format
|
|
26
|
+
ruff check .
|
|
27
|
+
ruff format .
|
|
28
|
+
ruff check --fix . # auto-fix linting issues
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Architecture
|
|
32
|
+
|
|
33
|
+
The codebase follows a hierarchical tree structure mirroring LabArchives organization:
|
|
34
|
+
|
|
35
|
+
**Core modules:**
|
|
36
|
+
- `src/labapi/client.py` - Main API client with HMAC-SHA512 request signing, authentication flows (`generate_auth_url`, `login_authcode`), and `api_get`/`api_post` methods
|
|
37
|
+
- `src/labapi/user.py` - Authenticated user session; provides access to notebooks via `user.notebooks`
|
|
38
|
+
- `src/labapi/tree/` - Hierarchical data model: `Notebook` → `NotebookDirectory` → `NotebookPage`
|
|
39
|
+
- `src/labapi/entry/` - Entry types on pages: `TextEntry`, `HeaderEntry`, `PlainTextEntry`, `AttachmentEntry`, `WidgetEntry`
|
|
40
|
+
- `src/labapi/util/extract.py` - XML extraction helpers (`extract_etree`, `to_bool`, `_flatten_dict`)
|
|
41
|
+
- `src/labapi/util/index.py` - Indexing enum for accessing items by ID or name: `notebook[Index.Id:"some_id"]` or `notebook[Index.Name:"some_name"]`
|
|
42
|
+
|
|
43
|
+
**Entry point pattern:**
|
|
44
|
+
```python
|
|
45
|
+
from labapi import Client
|
|
46
|
+
client = Client(base_url, akid, password) # or Client() to load from .env
|
|
47
|
+
auth_url = client.generate_auth_url(redirect_url)
|
|
48
|
+
user = client.login_authcode(user_email, auth_code)
|
|
49
|
+
notebooks = user.notebooks
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Development Conventions
|
|
53
|
+
|
|
54
|
+
- **Type hinting:** All new code must be fully type-hinted
|
|
55
|
+
- **XML handling:** Use `lxml` for all XML parsing; use helpers in `src/labapi/util/extract.py`
|
|
56
|
+
- **Testing:** Prefer unit tests with `MockClient` (in `tests/test_unit.py`) over integration tests to avoid hitting the live API
|
|
57
|
+
- **Error handling:** API errors are raised as `RuntimeError` (future: type these more specifically)
|
|
58
|
+
|
|
59
|
+
## Environment Variables
|
|
60
|
+
|
|
61
|
+
The `Client` class auto-loads from a `.env` file via `python-dotenv` when credentials aren't passed directly. Create a `.env` file (gitignored) with:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
API_URL=https://api.labarchives.com # optional, this is the default
|
|
65
|
+
ACCESS_KEYID=your_akid # required
|
|
66
|
+
ACCESS_PWD=your_password # required
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Other environment variables:**
|
|
70
|
+
- `LA_KEY`, `LA_EMAIL` - Required for integration tests
|
|
71
|
+
- `LA_AUTH_BROWSER` - Browser for OAuth flows (chrome, firefox, edge)
|
|
72
|
+
- `AUTH_INTERACTIVE` - Enable interactive authentication mode
|
|
73
|
+
- `NOTEBOOK` - Target notebook name for testing
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
uv sync --all-groups
|
|
7
|
+
pre-commit install --hook-type pre-commit --hook-type pre-push
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Running Tests
|
|
11
|
+
|
|
12
|
+
Unit tests run entirely offline using `MockClient`:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv run pytest
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Integration tests are opt-in and require live API credentials in `.env` or the environment:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Required
|
|
22
|
+
ACCESS_KEYID=your_akid
|
|
23
|
+
ACCESS_PWD=your_password
|
|
24
|
+
API_URL=https://api.labarchives.com
|
|
25
|
+
|
|
26
|
+
# Required for non-interactive login used by tests/test_integration.py
|
|
27
|
+
AUTH_EMAIL=your@email.com
|
|
28
|
+
AUTH_KEY=your_auth_key
|
|
29
|
+
|
|
30
|
+
# Optional: use the browser callback flow instead
|
|
31
|
+
# AUTH_INTERACTIVE=true
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv run pytest --integration tests/test_integration.py
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`Client()` only auto-loads `API_URL`, `ACCESS_KEYID`, and `ACCESS_PWD`; `AUTH_EMAIL` and `AUTH_KEY` are test-fixture conventions used by the integration suite.
|
|
39
|
+
|
|
40
|
+
## Code Style
|
|
41
|
+
|
|
42
|
+
Ruff handles linting, formatting, and branch-complexity checks. Pyright handles type checking. After installing both hook types:
|
|
43
|
+
|
|
44
|
+
- `ruff-check`, `ruff-format`, and `pyright-check` run on `pre-commit`
|
|
45
|
+
- `pytest-check` runs `uv run pytest --no-cov` on `pre-push`
|
|
46
|
+
|
|
47
|
+
Manual equivalents:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv run ruff check --fix . # lint
|
|
51
|
+
uv run ruff format . # format
|
|
52
|
+
uv run pyright # typecheck
|
|
53
|
+
uv run radon cc src tests -s -a # complexity report
|
|
54
|
+
uv run pytest --no-cov # pre-push test gate
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Type Annotations
|
|
58
|
+
|
|
59
|
+
Run type checking locally with:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv run pyright
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
All new code must be fully type-annotated. Key conventions:
|
|
66
|
+
|
|
67
|
+
- `from __future__ import annotations` in every module
|
|
68
|
+
- `override` on all method overrides
|
|
69
|
+
- `TYPE_CHECKING` guards to avoid circular imports
|
|
70
|
+
- Generics where they give callers concrete return types (e.g. `Entry[Attachment]`)
|