atomscale 0.8.0__tar.gz → 0.8.2__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.
- {atomscale-0.8.0 → atomscale-0.8.2}/.github/workflows/release.yml +10 -6
- {atomscale-0.8.0 → atomscale-0.8.2}/.github/workflows/testing.yml +21 -22
- {atomscale-0.8.0 → atomscale-0.8.2}/.pre-commit-config.yaml +15 -14
- {atomscale-0.8.0/src/atomscale.egg-info → atomscale-0.8.2}/PKG-INFO +4 -3
- {atomscale-0.8.0 → atomscale-0.8.2}/pyproject.toml +11 -29
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/core/client.py +3 -3
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/__init__.py +3 -1
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/rheed_image.py +1 -3
- atomscale-0.8.2/src/atomscale/results/similarity_trajectory.py +34 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/__init__.py +2 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/align.py +24 -24
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/registry.py +2 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/rheed.py +6 -1
- atomscale-0.8.2/src/atomscale/timeseries/similarity.py +113 -0
- {atomscale-0.8.0 → atomscale-0.8.2/src/atomscale.egg-info}/PKG-INFO +4 -3
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale.egg-info/SOURCES.txt +3 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale.egg-info/requires.txt +3 -2
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/conftest.py +2 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_rheed_video.py +5 -1
- atomscale-0.8.2/tests/test_similarity_trajectory.py +97 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/.github/workflows/upgrade_dependencies.yml +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/.gitignore +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/CHANGELOG.md +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/LICENSE +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/MANIFEST.in +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/README.md +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/atomicds-shim-dist/pyproject.toml +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/Makefile +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/_templates/custom-class-template.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/_templates/custom-module-template.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/conf.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/guides/index.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/guides/inspect-results.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/guides/poll-timeseries.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/guides/quickstart.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/guides/search-data.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/guides/stream-rheed.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/guides/upload-data.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/index.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/make.bat +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/docs/modules.rst +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/examples/general_use.ipynb +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/examples/rheed_streaming.ipynb +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/examples/timeseries_polling.ipynb +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/examples/vxwse2-placeholder/task1_films.ipynb +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/examples/vxwse2-placeholder/task1_sapphire.ipynb +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/examples/vxwse2-placeholder/task2_composition.ipynb +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.10.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.10_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.11.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.11_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.12.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.12_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.9.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.9_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.10.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.10_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.11.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.11_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.12.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.12_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.9.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.9_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.10.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.10_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.11.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.11_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.12.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.12_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.9.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.9_extras.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/setup.cfg +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomicds/__init__.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/__init__.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/client.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/core/__init__.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/core/files.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/core/utils.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/group.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/metrology.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/optical.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/photoluminescence.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/raman.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/rheed_video.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/unknown.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/results/xps.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/streaming/Cargo.lock +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/streaming/Cargo.toml +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/streaming/__init__.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/streaming/rheed_stream.pyi +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/streaming/src/initialize.rs +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/streaming/src/lib.rs +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/streaming/src/upload.rs +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/streaming/src/utils.rs +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/metrology.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/optical.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/polling.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/provider.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale/timeseries/sample.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale.egg-info/dependency_links.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/src/atomscale.egg-info/top_level.txt +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/__init__.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/data/test_rheed.mp4 +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_atomicds_alias.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_client.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_core.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_metrology.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_optical.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_photoluminescence.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_polling.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_raman.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_rheed_image.py +0 -0
- {atomscale-0.8.0 → atomscale-0.8.2}/tests/test_xps.py +0 -0
|
@@ -139,17 +139,21 @@ jobs:
|
|
|
139
139
|
steps:
|
|
140
140
|
- uses: actions/checkout@v4
|
|
141
141
|
|
|
142
|
-
-
|
|
142
|
+
- name: Set up uv
|
|
143
|
+
uses: astral-sh/setup-uv@v5
|
|
144
|
+
with:
|
|
145
|
+
version: "latest"
|
|
146
|
+
|
|
147
|
+
- name: Set up Python
|
|
148
|
+
uses: actions/setup-python@v5
|
|
143
149
|
with:
|
|
144
150
|
python-version: "3.11"
|
|
145
151
|
|
|
146
152
|
- name: Install dependencies
|
|
147
153
|
run: |
|
|
148
|
-
|
|
149
|
-
pip install -r requirements/requirements-ubuntu-latest_py3.
|
|
150
|
-
pip install -
|
|
151
|
-
pip install sphinx
|
|
152
|
-
pip install -e .
|
|
154
|
+
uv pip install --system -r requirements/requirements-ubuntu-latest_py3.11.txt
|
|
155
|
+
uv pip install --system -r requirements/requirements-ubuntu-latest_py3.11_extras.txt
|
|
156
|
+
uv pip install --system -e .
|
|
153
157
|
|
|
154
158
|
- name: Build docs
|
|
155
159
|
run: sphinx-build ./docs ./docs/_build
|
|
@@ -17,30 +17,24 @@ jobs:
|
|
|
17
17
|
steps:
|
|
18
18
|
- uses: actions/checkout@v4
|
|
19
19
|
|
|
20
|
+
- name: Set up uv
|
|
21
|
+
uses: astral-sh/setup-uv@v5
|
|
22
|
+
with:
|
|
23
|
+
version: "latest"
|
|
24
|
+
|
|
20
25
|
- name: Set up Python
|
|
21
26
|
uses: actions/setup-python@v5
|
|
22
27
|
with:
|
|
23
28
|
python-version: "3.11"
|
|
24
29
|
|
|
25
|
-
- name: Install Python dependencies
|
|
26
|
-
run: |
|
|
27
|
-
python -m pip install --upgrade pip
|
|
28
|
-
pip install -r requirements/requirements-ubuntu-latest_py3.11.txt
|
|
29
|
-
pip install -r requirements/requirements-ubuntu-latest_py3.11_extras.txt
|
|
30
|
-
|
|
31
30
|
- name: Install dependencies
|
|
32
31
|
run: |
|
|
33
|
-
pip install
|
|
32
|
+
uv pip install --system -r requirements/requirements-ubuntu-latest_py3.11.txt
|
|
33
|
+
uv pip install --system -r requirements/requirements-ubuntu-latest_py3.11_extras.txt
|
|
34
|
+
uv pip install --system pre-commit ty
|
|
34
35
|
|
|
35
36
|
- name: Run pre-commit
|
|
36
|
-
run:
|
|
37
|
-
pre-commit run --all-files --show-diff-on-failure
|
|
38
|
-
|
|
39
|
-
- name: Run mypy
|
|
40
|
-
run: |
|
|
41
|
-
mypy --version
|
|
42
|
-
rm -rf .mypy_cache
|
|
43
|
-
mypy src/atomicds
|
|
37
|
+
run: pre-commit run --all-files --show-diff-on-failure
|
|
44
38
|
|
|
45
39
|
test:
|
|
46
40
|
needs: lint
|
|
@@ -55,16 +49,20 @@ jobs:
|
|
|
55
49
|
steps:
|
|
56
50
|
- uses: actions/checkout@v4
|
|
57
51
|
|
|
52
|
+
- name: Set up uv
|
|
53
|
+
uses: astral-sh/setup-uv@v5
|
|
54
|
+
with:
|
|
55
|
+
version: "latest"
|
|
56
|
+
|
|
58
57
|
- name: Set up Python ${{ matrix.python-version }}
|
|
59
58
|
uses: actions/setup-python@v5
|
|
60
59
|
with:
|
|
61
60
|
python-version: ${{ matrix.python-version }}
|
|
62
61
|
|
|
63
|
-
- name: Install
|
|
62
|
+
- name: Install dependencies
|
|
64
63
|
run: |
|
|
65
|
-
|
|
66
|
-
pip install -r requirements/requirements-${{ matrix.os }}_py${{ matrix.python-version }}.txt
|
|
67
|
-
pip install -r requirements/requirements-${{ matrix.os }}_py${{ matrix.python-version }}_extras.txt
|
|
64
|
+
uv pip install --system -r requirements/requirements-${{ matrix.os }}_py${{ matrix.python-version }}.txt
|
|
65
|
+
uv pip install --system -r requirements/requirements-${{ matrix.os }}_py${{ matrix.python-version }}_extras.txt
|
|
68
66
|
|
|
69
67
|
- name: Set SSL_CERT_FILE (Linux/MacOS)
|
|
70
68
|
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
|
|
@@ -74,13 +72,14 @@ jobs:
|
|
|
74
72
|
if: matrix.os == 'windows-latest'
|
|
75
73
|
run: echo "SSL_CERT_FILE=$(python -m certifi)" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
|
|
76
74
|
|
|
75
|
+
- name: Install package
|
|
76
|
+
run: uv pip install --system -e .
|
|
77
|
+
|
|
77
78
|
- name: Test with pytest
|
|
78
79
|
env:
|
|
79
80
|
AS_API_KEY: ${{ secrets.AS_API_KEY }}
|
|
80
81
|
AS_API_ENDPOINT: "https://api.atomscale.ai"
|
|
81
|
-
run:
|
|
82
|
-
pip install -e .
|
|
83
|
-
pytest -x
|
|
82
|
+
run: pytest -x
|
|
84
83
|
|
|
85
84
|
auto-gen-release:
|
|
86
85
|
needs: test
|
|
@@ -5,19 +5,8 @@ ci:
|
|
|
5
5
|
autoupdate_commit_msg: "chore: update pre-commit hooks"
|
|
6
6
|
|
|
7
7
|
repos:
|
|
8
|
-
- repo: https://github.com/psf/black
|
|
9
|
-
rev: 23.9.1
|
|
10
|
-
hooks:
|
|
11
|
-
- id: black
|
|
12
|
-
|
|
13
|
-
- repo: https://github.com/asottile/blacken-docs
|
|
14
|
-
rev: "1.16.0"
|
|
15
|
-
hooks:
|
|
16
|
-
- id: blacken-docs
|
|
17
|
-
additional_dependencies: [black>=23.7.0]
|
|
18
|
-
|
|
19
8
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
20
|
-
rev:
|
|
9
|
+
rev: v5.0.0
|
|
21
10
|
hooks:
|
|
22
11
|
- id: check-case-conflict
|
|
23
12
|
- id: check-symlinks
|
|
@@ -28,15 +17,27 @@ repos:
|
|
|
28
17
|
- id: trailing-whitespace
|
|
29
18
|
|
|
30
19
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
31
|
-
rev: v0.
|
|
20
|
+
rev: v0.9.4
|
|
32
21
|
hooks:
|
|
33
22
|
- id: ruff
|
|
34
23
|
args: [--fix, --show-fixes]
|
|
24
|
+
exclude: '\.ipynb$'
|
|
25
|
+
- id: ruff-format
|
|
26
|
+
exclude: '\.ipynb$'
|
|
35
27
|
|
|
36
28
|
- repo: https://github.com/codespell-project/codespell
|
|
37
|
-
rev: v2.
|
|
29
|
+
rev: v2.4.1
|
|
38
30
|
hooks:
|
|
39
31
|
- id: codespell
|
|
40
32
|
stages: [pre-commit, commit-msg]
|
|
41
33
|
exclude_types: [json, bib, svg]
|
|
42
34
|
args: [--ignore-words-list, "mater,fwe,te"]
|
|
35
|
+
|
|
36
|
+
- repo: local
|
|
37
|
+
hooks:
|
|
38
|
+
- id: ty
|
|
39
|
+
name: ty
|
|
40
|
+
entry: ty check src/atomicds
|
|
41
|
+
language: system
|
|
42
|
+
types: [python]
|
|
43
|
+
pass_filenames: false
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atomscale
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: Python SDK for Atomscale.
|
|
5
5
|
Author-email: Atomscale <info@atomscale.ai>
|
|
6
6
|
License: GPL-3.0-only
|
|
@@ -36,10 +36,11 @@ Requires-Dist: pytest-cov; extra == "dev"
|
|
|
36
36
|
Requires-Dist: pytest-order; extra == "dev"
|
|
37
37
|
Requires-Dist: pytest-dependency; extra == "dev"
|
|
38
38
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
39
|
-
Requires-Dist: ruff; extra == "dev"
|
|
40
|
-
Requires-Dist:
|
|
39
|
+
Requires-Dist: ruff>=0.9.0; extra == "dev"
|
|
40
|
+
Requires-Dist: ty; extra == "dev"
|
|
41
41
|
Requires-Dist: types-requests; extra == "dev"
|
|
42
42
|
Requires-Dist: pandas-stubs; extra == "dev"
|
|
43
|
+
Requires-Dist: pre-commit>=4.0.0; extra == "dev"
|
|
43
44
|
Provides-Extra: docs
|
|
44
45
|
Requires-Dist: sphinx>=6.2; extra == "docs"
|
|
45
46
|
Requires-Dist: sphinx-autodoc-typehints>=1.24; extra == "docs"
|
|
@@ -49,10 +49,11 @@ dev = [
|
|
|
49
49
|
"pytest-order",
|
|
50
50
|
"pytest-dependency",
|
|
51
51
|
"pytest-asyncio",
|
|
52
|
-
"ruff",
|
|
53
|
-
"
|
|
52
|
+
"ruff>=0.9.0",
|
|
53
|
+
"ty",
|
|
54
54
|
"types-requests",
|
|
55
55
|
"pandas-stubs",
|
|
56
|
+
"pre-commit>=4.0.0",
|
|
56
57
|
]
|
|
57
58
|
docs = ["sphinx>=6.2", "sphinx-autodoc-typehints>=1.24", "alabaster>=0.7"]
|
|
58
59
|
|
|
@@ -73,10 +74,6 @@ path = "src/atomscale/streaming/Cargo.toml"
|
|
|
73
74
|
binding = "PyO3"
|
|
74
75
|
|
|
75
76
|
|
|
76
|
-
[tool.pyright]
|
|
77
|
-
include = ["atomscale", "atomicds"]
|
|
78
|
-
exclude = ["**/__pycache__"]
|
|
79
|
-
|
|
80
77
|
[tool.pytest.ini_options]
|
|
81
78
|
minversion = "6.0"
|
|
82
79
|
addopts = ["-p no:warnings", "--import-mode=importlib"]
|
|
@@ -84,18 +81,6 @@ xfail_strict = true
|
|
|
84
81
|
log_cli_level = "warn"
|
|
85
82
|
testpaths = ["tests"]
|
|
86
83
|
|
|
87
|
-
[tool.black]
|
|
88
|
-
exclude = '''
|
|
89
|
-
/(
|
|
90
|
-
\.git
|
|
91
|
-
| \.tox
|
|
92
|
-
)/
|
|
93
|
-
'''
|
|
94
|
-
|
|
95
|
-
[tool.isort]
|
|
96
|
-
profile = 'black'
|
|
97
|
-
skip_gitignore = true
|
|
98
|
-
|
|
99
84
|
[tool.coverage.run]
|
|
100
85
|
source = ["src"]
|
|
101
86
|
|
|
@@ -137,11 +122,9 @@ lint.select = [
|
|
|
137
122
|
lint.extend-ignore = [
|
|
138
123
|
"PLR", # Design related pylint codes
|
|
139
124
|
"E501", # Line too long
|
|
140
|
-
"PT004", # Use underscore for non-returning fixture (use usefixture instead)
|
|
141
125
|
"B028", # No explicit stacklevel
|
|
142
126
|
"EM101", # Exception must not use a string literal
|
|
143
127
|
"EM102", # Exception must not use an f-string literal
|
|
144
|
-
"PD901", # Avoid using the generic variable name `df` for DataFrames
|
|
145
128
|
]
|
|
146
129
|
lint.typing-modules = ["mypackage._compat.typing"]
|
|
147
130
|
src = ["src"]
|
|
@@ -151,20 +134,19 @@ lint.unfixable = [
|
|
|
151
134
|
]
|
|
152
135
|
exclude = []
|
|
153
136
|
lint.flake8-unused-arguments.ignore-variadic-names = true
|
|
154
|
-
extend-exclude = ["tests"]
|
|
137
|
+
extend-exclude = ["tests", "examples", "*.ipynb"]
|
|
155
138
|
lint.pydocstyle.convention = "google"
|
|
156
139
|
lint.isort.known-first-party = ["atomscale"]
|
|
157
140
|
|
|
158
141
|
[tool.docformatter]
|
|
159
142
|
pre-summary-newline = true
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
[
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
disable_error_code = "annotation-unchecked"
|
|
143
|
+
|
|
144
|
+
[tool.ty.environment]
|
|
145
|
+
root = ["./src"]
|
|
146
|
+
|
|
147
|
+
[tool.ty.src]
|
|
148
|
+
include = ["src/atomicds"]
|
|
149
|
+
exclude = ["tests", "examples", "docs"]
|
|
168
150
|
|
|
169
151
|
[tool.codespell]
|
|
170
152
|
ignore-words-list = "fpr"
|
|
@@ -245,9 +245,9 @@ class BaseClient:
|
|
|
245
245
|
atomscale_info = "atomscale/" + __version__
|
|
246
246
|
python_info = f"Python/{sys.version.split()[0]}"
|
|
247
247
|
platform_info = f"{platform.system()}/{platform.release()}"
|
|
248
|
-
session.headers[
|
|
249
|
-
"
|
|
250
|
-
|
|
248
|
+
session.headers["user-agent"] = (
|
|
249
|
+
f"{atomscale_info} ({python_info} {platform_info})"
|
|
250
|
+
)
|
|
251
251
|
|
|
252
252
|
# TODO: Add retry setting to configuration somewhere
|
|
253
253
|
max_retry_num = 3
|
|
@@ -5,6 +5,7 @@ from .photoluminescence import PhotoluminescenceResult
|
|
|
5
5
|
from .raman import RamanResult
|
|
6
6
|
from .rheed_image import RHEEDImageCollection, RHEEDImageResult, _get_rheed_image_result
|
|
7
7
|
from .rheed_video import RHEEDVideoResult
|
|
8
|
+
from .similarity_trajectory import SimilarityTrajectoryResult
|
|
8
9
|
from .unknown import UnknownResult
|
|
9
10
|
from .xps import XPSResult
|
|
10
11
|
|
|
@@ -18,7 +19,8 @@ __all__ = [
|
|
|
18
19
|
"RHEEDImageResult",
|
|
19
20
|
"RHEEDVideoResult",
|
|
20
21
|
"RamanResult",
|
|
21
|
-
"
|
|
22
|
+
"SimilarityTrajectoryResult",
|
|
22
23
|
"UnknownResult",
|
|
24
|
+
"XPSResult",
|
|
23
25
|
"_get_rheed_image_result",
|
|
24
26
|
]
|
|
@@ -371,9 +371,7 @@ class RHEEDImageResult(MSONable):
|
|
|
371
371
|
x,
|
|
372
372
|
new_df["mask_height"].iloc[0], # type: ignore # noqa: PGH003
|
|
373
373
|
new_df["mask_width"].iloc[0], # type: ignore # noqa: PGH003
|
|
374
|
-
)[
|
|
375
|
-
"counts"
|
|
376
|
-
]
|
|
374
|
+
)["counts"]
|
|
377
375
|
|
|
378
376
|
new_df = new_df.groupby("node_id").agg(agg_dict).reset_index(drop=True)
|
|
379
377
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
from monty.json import MSONable
|
|
7
|
+
from pandas import DataFrame
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SimilarityTrajectoryResult(MSONable):
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
source_id: UUID | str,
|
|
14
|
+
workflow: str,
|
|
15
|
+
window_span: float,
|
|
16
|
+
timeseries_data: DataFrame,
|
|
17
|
+
source_data_ids: Sequence[UUID | str] | None = None,
|
|
18
|
+
):
|
|
19
|
+
"""Similarity trajectory result
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
source_id (UUID | str): Source ID for the similarity trajectory query.
|
|
23
|
+
workflow (str): Workflow name used for the similarity analysis.
|
|
24
|
+
window_span (float): Window span parameter used for the trajectory.
|
|
25
|
+
timeseries_data (DataFrame): Pandas DataFrame with similarity trajectory data.
|
|
26
|
+
source_data_ids (Sequence[UUID | str] | None): Sequence of source data IDs included in the trajectory.
|
|
27
|
+
"""
|
|
28
|
+
self.source_id = source_id
|
|
29
|
+
self.workflow = workflow
|
|
30
|
+
self.window_span = window_span
|
|
31
|
+
self.timeseries_data = timeseries_data
|
|
32
|
+
self.source_data_ids: list[UUID | str] = (
|
|
33
|
+
list(source_data_ids) if source_data_ids else []
|
|
34
|
+
)
|
|
@@ -4,11 +4,13 @@ from .optical import OpticalProvider
|
|
|
4
4
|
from .provider import TimeseriesProvider
|
|
5
5
|
from .registry import get_provider
|
|
6
6
|
from .rheed import RHEEDProvider
|
|
7
|
+
from .similarity import SimilarityTrajectoryProvider
|
|
7
8
|
|
|
8
9
|
__all__ = [
|
|
9
10
|
"MetrologyProvider",
|
|
10
11
|
"OpticalProvider",
|
|
11
12
|
"RHEEDProvider",
|
|
13
|
+
"SimilarityTrajectoryProvider",
|
|
12
14
|
"TimeseriesProvider",
|
|
13
15
|
"align_timeseries",
|
|
14
16
|
"get_provider",
|
|
@@ -71,26 +71,26 @@ def _extract_timeseries(result):
|
|
|
71
71
|
"""Return (data_id, domain, df_with_timeindex) or None for non-timeseries."""
|
|
72
72
|
if isinstance(result, RHEEDVideoResult):
|
|
73
73
|
domain = "rheed"
|
|
74
|
-
|
|
74
|
+
timeseries = result.timeseries_data
|
|
75
75
|
elif isinstance(result, OpticalResult):
|
|
76
76
|
domain = "optical"
|
|
77
|
-
|
|
77
|
+
timeseries = result.timeseries_data
|
|
78
78
|
elif isinstance(result, MetrologyResult):
|
|
79
79
|
domain = "metrology"
|
|
80
|
-
|
|
80
|
+
timeseries = result.timeseries_data
|
|
81
81
|
else:
|
|
82
82
|
return None
|
|
83
83
|
|
|
84
|
-
if
|
|
84
|
+
if timeseries is None or timeseries.empty:
|
|
85
85
|
return None
|
|
86
86
|
|
|
87
87
|
# Build time index: prefer absolute epochs; fall back to upload_datetime + relative offsets.
|
|
88
88
|
upload_dt = getattr(result, "upload_datetime", None)
|
|
89
89
|
|
|
90
|
-
time_index = _infer_absolute_time(
|
|
90
|
+
time_index = _infer_absolute_time(timeseries)
|
|
91
91
|
if time_index is None and upload_dt is not None:
|
|
92
92
|
base = pd.to_datetime(upload_dt, utc=True, errors="coerce")
|
|
93
|
-
rel = _infer_relative_time(
|
|
93
|
+
rel = _infer_relative_time(timeseries)
|
|
94
94
|
if base is not pd.NaT and rel is not None:
|
|
95
95
|
time_index = base + rel
|
|
96
96
|
|
|
@@ -101,7 +101,7 @@ def _extract_timeseries(result):
|
|
|
101
101
|
if not valid_mask.any():
|
|
102
102
|
return None
|
|
103
103
|
|
|
104
|
-
indexed =
|
|
104
|
+
indexed = timeseries.loc[valid_mask].copy(deep=False)
|
|
105
105
|
indexed.index = pd.Index(time_index[valid_mask], name="time")
|
|
106
106
|
indexed = indexed.sort_index()
|
|
107
107
|
|
|
@@ -173,11 +173,11 @@ def align_timeseries(
|
|
|
173
173
|
if not extracted:
|
|
174
174
|
continue
|
|
175
175
|
|
|
176
|
-
data_id, domain,
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
frames.append(
|
|
180
|
-
indices.append(
|
|
176
|
+
data_id, domain, frame = extracted
|
|
177
|
+
frame = frame.copy(deep=False)
|
|
178
|
+
frame.columns = pd.MultiIndex.from_product([[data_id], [domain], frame.columns])
|
|
179
|
+
frames.append(frame)
|
|
180
|
+
indices.append(frame.index)
|
|
181
181
|
|
|
182
182
|
if not frames:
|
|
183
183
|
return pd.DataFrame()
|
|
@@ -211,11 +211,11 @@ def align_timeseries(
|
|
|
211
211
|
|
|
212
212
|
# Merge compatible metrics across items: if multiple columns share (domain, metric)
|
|
213
213
|
# and never conflict where they overlap, collapse into (shared, domain, metric).
|
|
214
|
-
def _merge_compatible_metrics(
|
|
215
|
-
if not isinstance(
|
|
216
|
-
return
|
|
217
|
-
domains =
|
|
218
|
-
metrics =
|
|
214
|
+
def _merge_compatible_metrics(data: pd.DataFrame) -> pd.DataFrame:
|
|
215
|
+
if not isinstance(data.columns, pd.MultiIndex):
|
|
216
|
+
return data
|
|
217
|
+
domains = data.columns.get_level_values(1)
|
|
218
|
+
metrics = data.columns.get_level_values(2)
|
|
219
219
|
new_cols: dict = {}
|
|
220
220
|
drop_cols: list = []
|
|
221
221
|
|
|
@@ -223,16 +223,16 @@ def align_timeseries(
|
|
|
223
223
|
for metric in metrics.unique():
|
|
224
224
|
cols = [
|
|
225
225
|
c
|
|
226
|
-
for c in
|
|
226
|
+
for c in data.columns
|
|
227
227
|
if c[1] == domain and c[2] == metric and c[0] != "shared"
|
|
228
228
|
]
|
|
229
229
|
if len(cols) <= 1:
|
|
230
230
|
continue
|
|
231
231
|
|
|
232
|
-
merged =
|
|
232
|
+
merged = data[cols[0]]
|
|
233
233
|
conflict = False
|
|
234
234
|
for c in cols[1:]:
|
|
235
|
-
other =
|
|
235
|
+
other = data[c]
|
|
236
236
|
overlap_mask = merged.notna() & other.notna()
|
|
237
237
|
if (merged[overlap_mask] != other[overlap_mask]).any():
|
|
238
238
|
conflict = True
|
|
@@ -247,10 +247,10 @@ def align_timeseries(
|
|
|
247
247
|
drop_cols.extend(cols)
|
|
248
248
|
|
|
249
249
|
if new_cols:
|
|
250
|
-
|
|
250
|
+
data = data.drop(columns=drop_cols)
|
|
251
251
|
for col, series in new_cols.items():
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return
|
|
252
|
+
data[col] = series
|
|
253
|
+
data = data.sort_index(axis=1)
|
|
254
|
+
return data
|
|
255
255
|
|
|
256
256
|
return _merge_compatible_metrics(aligned)
|
|
@@ -4,11 +4,13 @@ from .metrology import MetrologyProvider
|
|
|
4
4
|
from .optical import OpticalProvider
|
|
5
5
|
from .provider import TimeseriesProvider
|
|
6
6
|
from .rheed import RHEEDProvider
|
|
7
|
+
from .similarity import SimilarityTrajectoryProvider
|
|
7
8
|
|
|
8
9
|
_PROVIDER_CLASSES: dict[str, type[TimeseriesProvider]] = {
|
|
9
10
|
RHEEDProvider.TYPE: RHEEDProvider,
|
|
10
11
|
OpticalProvider.TYPE: OpticalProvider,
|
|
11
12
|
MetrologyProvider.TYPE: MetrologyProvider,
|
|
13
|
+
SimilarityTrajectoryProvider.TYPE: SimilarityTrajectoryProvider,
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
|
|
@@ -41,8 +41,13 @@ class RHEEDProvider(TimeseriesProvider[RHEEDVideoResult]):
|
|
|
41
41
|
"first_order_fwhm_1": "First Order FWHM",
|
|
42
42
|
"lattice_spacing": "Lattice Spacing",
|
|
43
43
|
"tar_metric": "TAR Metric",
|
|
44
|
+
"composition_metric": "Composition Metric",
|
|
44
45
|
}
|
|
45
|
-
DROP_IF_ALL_NA: Sequence[str] = [
|
|
46
|
+
DROP_IF_ALL_NA: Sequence[str] = [
|
|
47
|
+
"reconstruction_intensity",
|
|
48
|
+
"tar_metric",
|
|
49
|
+
"composition_metric",
|
|
50
|
+
]
|
|
46
51
|
INDEX_COLS: Sequence[str] = ["Angle", "Frame Number"]
|
|
47
52
|
|
|
48
53
|
def fetch_raw(self, client: BaseClient, data_id: str, **kwargs) -> Any:
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping, Sequence
|
|
4
|
+
from typing import Any
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from pandas import DataFrame, concat
|
|
8
|
+
|
|
9
|
+
from atomscale.core import BaseClient
|
|
10
|
+
from atomscale.results.similarity_trajectory import SimilarityTrajectoryResult
|
|
11
|
+
from atomscale.timeseries.provider import TimeseriesProvider
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SimilarityTrajectoryProvider(TimeseriesProvider[SimilarityTrajectoryResult]):
|
|
15
|
+
TYPE = "similarity_trajectory"
|
|
16
|
+
|
|
17
|
+
RENAME_MAP: Mapping[str, str] = {
|
|
18
|
+
"reference_id": "Reference ID",
|
|
19
|
+
"reference_item_name": "Reference Name",
|
|
20
|
+
"real_time_seconds": "Time",
|
|
21
|
+
"similarity_values": "Similarity",
|
|
22
|
+
"unix_times": "UNIX Timestamp",
|
|
23
|
+
"is_active": "Active",
|
|
24
|
+
"averaged_count": "Averaged Count",
|
|
25
|
+
}
|
|
26
|
+
INDEX_COLS: Sequence[str] = ["Reference ID", "Time"]
|
|
27
|
+
|
|
28
|
+
def fetch_raw(self, client: BaseClient, data_id: str, **kwargs: Any) -> Any:
|
|
29
|
+
"""Fetch similarity trajectory data from the API.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
client: The API client.
|
|
33
|
+
data_id: The source ID for the similarity query.
|
|
34
|
+
**kwargs: Must include 'workflow' (required). Optional parameters:
|
|
35
|
+
window_span, reference_ids, softmax_mode, reference_n_values.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Raw API response payload.
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
KeyError: If 'workflow' is not provided in kwargs.
|
|
42
|
+
"""
|
|
43
|
+
workflow = kwargs.pop("workflow")
|
|
44
|
+
return client._get(
|
|
45
|
+
sub_url=f"similarity/{workflow}/{data_id}/trajectory/",
|
|
46
|
+
params=kwargs,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def to_dataframe(self, raw: Any) -> DataFrame:
|
|
50
|
+
if not raw:
|
|
51
|
+
return DataFrame(None)
|
|
52
|
+
|
|
53
|
+
trajectories = raw.get("trajectories", [])
|
|
54
|
+
if not trajectories:
|
|
55
|
+
return DataFrame(None)
|
|
56
|
+
|
|
57
|
+
frames: list[DataFrame] = []
|
|
58
|
+
for traj in trajectories:
|
|
59
|
+
ref_id = traj.get("reference_id")
|
|
60
|
+
ref_name = traj.get("reference_item_name")
|
|
61
|
+
similarity_values = traj.get("similarity_values", [])
|
|
62
|
+
real_time_seconds = traj.get("real_time_seconds", [])
|
|
63
|
+
unix_times = traj.get("unix_times", [])
|
|
64
|
+
is_active = traj.get("is_active")
|
|
65
|
+
averaged_count = traj.get("averaged_count")
|
|
66
|
+
|
|
67
|
+
if not similarity_values:
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
# Build dataframe from columnar data
|
|
71
|
+
traj_df = DataFrame(
|
|
72
|
+
{
|
|
73
|
+
"reference_id": ref_id,
|
|
74
|
+
"reference_item_name": ref_name,
|
|
75
|
+
"similarity_values": similarity_values,
|
|
76
|
+
"real_time_seconds": real_time_seconds,
|
|
77
|
+
"unix_times": unix_times,
|
|
78
|
+
"is_active": is_active,
|
|
79
|
+
"averaged_count": averaged_count,
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
frames.append(traj_df)
|
|
83
|
+
|
|
84
|
+
if not frames:
|
|
85
|
+
return DataFrame(None)
|
|
86
|
+
|
|
87
|
+
df_all = concat(frames, axis=0, ignore_index=True)
|
|
88
|
+
df_all = df_all.rename(columns=self.RENAME_MAP)
|
|
89
|
+
|
|
90
|
+
idx_cols = [c for c in self.INDEX_COLS if c in df_all.columns]
|
|
91
|
+
if idx_cols:
|
|
92
|
+
df_all = df_all.set_index(idx_cols)
|
|
93
|
+
|
|
94
|
+
return df_all
|
|
95
|
+
|
|
96
|
+
def build_result(
|
|
97
|
+
self,
|
|
98
|
+
client: BaseClient, # noqa: ARG002
|
|
99
|
+
data_id: str,
|
|
100
|
+
data_type: str, # noqa: ARG002
|
|
101
|
+
ts_df: DataFrame,
|
|
102
|
+
*,
|
|
103
|
+
workflow: str = "",
|
|
104
|
+
window_span: float = 0.0,
|
|
105
|
+
source_data_ids: Sequence[UUID | str] | None = None,
|
|
106
|
+
) -> SimilarityTrajectoryResult:
|
|
107
|
+
return SimilarityTrajectoryResult(
|
|
108
|
+
source_id=data_id,
|
|
109
|
+
workflow=workflow,
|
|
110
|
+
window_span=window_span,
|
|
111
|
+
timeseries_data=ts_df,
|
|
112
|
+
source_data_ids=source_data_ids,
|
|
113
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atomscale
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: Python SDK for Atomscale.
|
|
5
5
|
Author-email: Atomscale <info@atomscale.ai>
|
|
6
6
|
License: GPL-3.0-only
|
|
@@ -36,10 +36,11 @@ Requires-Dist: pytest-cov; extra == "dev"
|
|
|
36
36
|
Requires-Dist: pytest-order; extra == "dev"
|
|
37
37
|
Requires-Dist: pytest-dependency; extra == "dev"
|
|
38
38
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
39
|
-
Requires-Dist: ruff; extra == "dev"
|
|
40
|
-
Requires-Dist:
|
|
39
|
+
Requires-Dist: ruff>=0.9.0; extra == "dev"
|
|
40
|
+
Requires-Dist: ty; extra == "dev"
|
|
41
41
|
Requires-Dist: types-requests; extra == "dev"
|
|
42
42
|
Requires-Dist: pandas-stubs; extra == "dev"
|
|
43
|
+
Requires-Dist: pre-commit>=4.0.0; extra == "dev"
|
|
43
44
|
Provides-Extra: docs
|
|
44
45
|
Requires-Dist: sphinx>=6.2; extra == "docs"
|
|
45
46
|
Requires-Dist: sphinx-autodoc-typehints>=1.24; extra == "docs"
|
|
@@ -73,6 +73,7 @@ src/atomscale/results/photoluminescence.py
|
|
|
73
73
|
src/atomscale/results/raman.py
|
|
74
74
|
src/atomscale/results/rheed_image.py
|
|
75
75
|
src/atomscale/results/rheed_video.py
|
|
76
|
+
src/atomscale/results/similarity_trajectory.py
|
|
76
77
|
src/atomscale/results/unknown.py
|
|
77
78
|
src/atomscale/results/xps.py
|
|
78
79
|
src/atomscale/streaming/Cargo.lock
|
|
@@ -92,6 +93,7 @@ src/atomscale/timeseries/provider.py
|
|
|
92
93
|
src/atomscale/timeseries/registry.py
|
|
93
94
|
src/atomscale/timeseries/rheed.py
|
|
94
95
|
src/atomscale/timeseries/sample.py
|
|
96
|
+
src/atomscale/timeseries/similarity.py
|
|
95
97
|
tests/__init__.py
|
|
96
98
|
tests/conftest.py
|
|
97
99
|
tests/test_atomicds_alias.py
|
|
@@ -104,5 +106,6 @@ tests/test_polling.py
|
|
|
104
106
|
tests/test_raman.py
|
|
105
107
|
tests/test_rheed_image.py
|
|
106
108
|
tests/test_rheed_video.py
|
|
109
|
+
tests/test_similarity_trajectory.py
|
|
107
110
|
tests/test_xps.py
|
|
108
111
|
tests/data/test_rheed.mp4
|
|
@@ -22,6 +22,7 @@ def result(client: Client):
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def test_get_dataframe(result: RHEEDVideoResult):
|
|
25
|
+
# Core columns that should always be present
|
|
25
26
|
column_names = set(
|
|
26
27
|
[
|
|
27
28
|
"Strain",
|
|
@@ -38,9 +39,12 @@ def test_get_dataframe(result: RHEEDVideoResult):
|
|
|
38
39
|
"Half Order Intensity R",
|
|
39
40
|
"Specular FWHM",
|
|
40
41
|
"First Order FWHM",
|
|
41
|
-
"Time",
|
|
42
42
|
"UNIX Timestamp",
|
|
43
43
|
"Relative Time",
|
|
44
|
+
# Optional columns (included if data exists)
|
|
45
|
+
"Time",
|
|
46
|
+
"TAR Metric",
|
|
47
|
+
"Composition Metric",
|
|
44
48
|
]
|
|
45
49
|
)
|
|
46
50
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from pandas import DataFrame
|
|
3
|
+
|
|
4
|
+
from atomscale import Client
|
|
5
|
+
from atomscale.results import SimilarityTrajectoryResult
|
|
6
|
+
from atomscale.timeseries.similarity import SimilarityTrajectoryProvider
|
|
7
|
+
|
|
8
|
+
from .conftest import ResultIDs
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def client():
|
|
13
|
+
return Client()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.fixture
|
|
17
|
+
def provider():
|
|
18
|
+
return SimilarityTrajectoryProvider()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.fixture
|
|
22
|
+
def raw_data(client: Client, provider: SimilarityTrajectoryProvider):
|
|
23
|
+
if not ResultIDs.similarity_workflow or not ResultIDs.similarity_source_id:
|
|
24
|
+
pytest.skip("No similarity trajectory data available")
|
|
25
|
+
|
|
26
|
+
data = provider.fetch_raw(
|
|
27
|
+
client,
|
|
28
|
+
ResultIDs.similarity_source_id,
|
|
29
|
+
workflow=ResultIDs.similarity_workflow,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if not data or not data.get("trajectories"):
|
|
33
|
+
pytest.skip("No trajectory data returned from API")
|
|
34
|
+
|
|
35
|
+
return data
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.fixture
|
|
39
|
+
def result(
|
|
40
|
+
client: Client, provider: SimilarityTrajectoryProvider, raw_data: dict
|
|
41
|
+
) -> SimilarityTrajectoryResult:
|
|
42
|
+
df = provider.to_dataframe(raw_data)
|
|
43
|
+
return provider.build_result(
|
|
44
|
+
client=client,
|
|
45
|
+
data_id=ResultIDs.similarity_source_id,
|
|
46
|
+
data_type="similarity_trajectory",
|
|
47
|
+
ts_df=df,
|
|
48
|
+
workflow=ResultIDs.similarity_workflow,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_type_constant():
|
|
53
|
+
"""Verify TYPE constant is set correctly."""
|
|
54
|
+
assert SimilarityTrajectoryProvider.TYPE == "similarity_trajectory"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_fetch_raw(raw_data: dict):
|
|
58
|
+
"""Verify raw data is fetched from API."""
|
|
59
|
+
assert raw_data is not None
|
|
60
|
+
assert "trajectories" in raw_data
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_to_dataframe(provider: SimilarityTrajectoryProvider, raw_data: dict):
|
|
64
|
+
"""Verify dataframe conversion."""
|
|
65
|
+
df = provider.to_dataframe(raw_data)
|
|
66
|
+
|
|
67
|
+
assert isinstance(df, DataFrame)
|
|
68
|
+
assert not df.empty
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_to_dataframe_columns(provider: SimilarityTrajectoryProvider, raw_data: dict):
|
|
72
|
+
"""Verify column names and index."""
|
|
73
|
+
df = provider.to_dataframe(raw_data)
|
|
74
|
+
|
|
75
|
+
# Check index names
|
|
76
|
+
assert df.index.names == ["Reference ID", "Time"]
|
|
77
|
+
|
|
78
|
+
# Check expected columns exist
|
|
79
|
+
expected_columns = {"Similarity", "Reference Name", "UNIX Timestamp", "Active", "Averaged Count"}
|
|
80
|
+
assert expected_columns == set(df.columns)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_build_result(result: SimilarityTrajectoryResult):
|
|
84
|
+
"""Verify result object construction."""
|
|
85
|
+
assert isinstance(result, SimilarityTrajectoryResult)
|
|
86
|
+
assert result.source_id == ResultIDs.similarity_source_id
|
|
87
|
+
assert result.workflow == ResultIDs.similarity_workflow
|
|
88
|
+
assert isinstance(result.timeseries_data, DataFrame)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_result_dataframe(result: SimilarityTrajectoryResult):
|
|
92
|
+
"""Verify result contains valid timeseries data."""
|
|
93
|
+
df = result.timeseries_data
|
|
94
|
+
|
|
95
|
+
assert isinstance(df, DataFrame)
|
|
96
|
+
if df.index.names != [None]:
|
|
97
|
+
assert df.index.names == ["Reference ID", "Time"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.10_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.11_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-macos-latest_py3.12_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.10_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.11_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.12_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-ubuntu-latest_py3.9_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.10_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.11_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.12_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
{atomscale-0.8.0 → atomscale-0.8.2}/requirements/requirements-windows-latest_py3.9_extras.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|