sfapi-client 0.0.7__tar.gz → 0.0.9__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.
- sfapi_client-0.0.9/.github/dependabot.yml +6 -0
- sfapi_client-0.0.9/.github/workflows/black.yml +17 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/.github/workflows/mkdocs.yml +3 -3
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/.github/workflows/pypi.yml +4 -4
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/.github/workflows/pytest.yml +2 -2
- sfapi_client-0.0.9/.github/workflows/ruff.yml +14 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/PKG-INFO +2 -2
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/gen_examples.py +0 -1
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/pyproject.toml +8 -1
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/requirements-dev.txt +2 -1
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/scripts/run.py +5 -8
- sfapi_client-0.0.9/src/sfapi_client/__init__.py +5 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_async/client.py +8 -3
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_async/compute.py +5 -10
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_async/groups.py +6 -5
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_async/jobs.py +14 -13
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_async/paths.py +16 -12
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_async/projects.py +3 -3
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_async/users.py +10 -7
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_models/__init__.py +7 -9
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_monitor.py +3 -3
- sfapi_client-0.0.9/src/sfapi_client/_sync/__init__.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_sync/client.py +7 -3
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_sync/compute.py +5 -10
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_sync/groups.py +6 -5
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_sync/jobs.py +14 -13
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_sync/paths.py +13 -12
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_sync/projects.py +3 -3
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_sync/users.py +9 -7
- sfapi_client-0.0.9/src/sfapi_client/client.py +2 -0
- sfapi_client-0.0.9/src/sfapi_client/compute.py +3 -0
- sfapi_client-0.0.9/src/sfapi_client/groups.py +2 -0
- sfapi_client-0.0.9/src/sfapi_client/jobs.py +7 -0
- sfapi_client-0.0.9/src/sfapi_client/paths.py +2 -0
- sfapi_client-0.0.9/src/sfapi_client/projects.py +2 -0
- sfapi_client-0.0.9/src/sfapi_client/resources.py +1 -0
- sfapi_client-0.0.9/src/sfapi_client/users.py +2 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/conftest.py +0 -1
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_compute.py +0 -1
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_jobs_async.py +1 -2
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_paths.py +4 -4
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_paths_async.py +4 -6
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_projects.py +0 -2
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_projects_async.py +0 -1
- sfapi_client-0.0.7/src/sfapi_client/__init__.py +0 -5
- sfapi_client-0.0.7/src/sfapi_client/client.py +0 -2
- sfapi_client-0.0.7/src/sfapi_client/compute.py +0 -3
- sfapi_client-0.0.7/src/sfapi_client/groups.py +0 -2
- sfapi_client-0.0.7/src/sfapi_client/jobs.py +0 -7
- sfapi_client-0.0.7/src/sfapi_client/paths.py +0 -2
- sfapi_client-0.0.7/src/sfapi_client/projects.py +0 -2
- sfapi_client-0.0.7/src/sfapi_client/resources.py +0 -1
- sfapi_client-0.0.7/src/sfapi_client/users.py +0 -2
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/.gitignore +0 -0
- /sfapi_client-0.0.7/src/sfapi_client/_async/__init__.py → /sfapi_client-0.0.9/.pre-commit-config.yaml +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/LEGAL +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/LICENSE +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/README.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/community/contributing.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/examples/check_current_and_past_jobs.ipynb +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/examples/getting_bearer_token.ipynb +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/examples/run_job_and_check_status.ipynb +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/gen_sync.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/javascript/apiselector.js +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/quickstart/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/SUMMARY.txt +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/client/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/compute/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/exceptions/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/groups/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/jobs/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/paths/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/projects/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/resources/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/docs/reference/async/users/index.md +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/mkdocs.yml +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/pytest.ini +0 -0
- {sfapi_client-0.0.7/src/sfapi_client/_sync → sfapi_client-0.0.9/src/sfapi_client/_async}/__init__.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_compute.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_jobs.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_models/job_status_response_sacct.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_models/job_status_response_squeue.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_models/resources.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/_utils.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/src/sfapi_client/exceptions.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_api.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_api_async.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_client.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_client_async.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_compute_async.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_groups.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_groups_async.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_jobs.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_resources.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_resources_async.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_users.py +0 -0
- {sfapi_client-0.0.7 → sfapi_client-0.0.9}/tests/test_users_async.py +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: black
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ["main"]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
black:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: psf/black@23.9.1
|
|
15
|
+
with:
|
|
16
|
+
options: "--check --verbose"
|
|
17
|
+
jupyter: false
|
|
@@ -12,11 +12,11 @@ jobs:
|
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/')
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
16
|
-
- uses: actions/setup-python@
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
17
|
with:
|
|
18
18
|
python-version: 3.x
|
|
19
|
-
- uses: actions/cache@
|
|
19
|
+
- uses: actions/cache@v4
|
|
20
20
|
with:
|
|
21
21
|
key: mkdocs-${{ github.ref }}
|
|
22
22
|
path: .cache
|
|
@@ -13,9 +13,9 @@ jobs:
|
|
|
13
13
|
name: Build wheel
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
17
|
- name: Set up Python
|
|
18
|
-
uses: actions/setup-python@
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
19
|
with:
|
|
20
20
|
python-version: "3.x"
|
|
21
21
|
- name: Install pypa/build
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
--wheel
|
|
34
34
|
--outdir dist/
|
|
35
35
|
|
|
36
|
-
- uses: actions/upload-artifact@
|
|
36
|
+
- uses: actions/upload-artifact@v4
|
|
37
37
|
with:
|
|
38
38
|
name: wheel
|
|
39
39
|
path: ./dist/
|
|
@@ -49,7 +49,7 @@ jobs:
|
|
|
49
49
|
id-token: write
|
|
50
50
|
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/')
|
|
51
51
|
steps:
|
|
52
|
-
- uses: actions/download-artifact@
|
|
52
|
+
- uses: actions/download-artifact@v4
|
|
53
53
|
with:
|
|
54
54
|
name: wheel
|
|
55
55
|
path: dist
|
|
@@ -16,9 +16,9 @@ jobs:
|
|
|
16
16
|
python-version: ["3.8", "3.9", "3.10", "3.11"]
|
|
17
17
|
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
20
|
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
-
uses: actions/setup-python@
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
22
|
with:
|
|
23
23
|
python-version: ${{ matrix.python-version }}
|
|
24
24
|
- name: Install dependencies
|
|
@@ -32,10 +32,17 @@ classifiers = [
|
|
|
32
32
|
exclude = '''
|
|
33
33
|
(
|
|
34
34
|
src/sfapi_client/_sync |
|
|
35
|
-
src/sfapi_client/_async/_models.py
|
|
35
|
+
src/sfapi_client/_async/_models.py |
|
|
36
|
+
sfapi_client/examples/
|
|
36
37
|
)
|
|
37
38
|
'''
|
|
38
39
|
|
|
40
|
+
[tool.ruff]
|
|
41
|
+
exclude = [
|
|
42
|
+
"src/sfapi_client/_sync",
|
|
43
|
+
"src/sfapi_client/_async/_models.py"
|
|
44
|
+
]
|
|
45
|
+
|
|
39
46
|
[project.optional-dependencies]
|
|
40
47
|
docs = [
|
|
41
48
|
"mkdocs-material",
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import re
|
|
3
2
|
from pathlib import Path
|
|
4
3
|
import json
|
|
5
4
|
|
|
6
5
|
import typer
|
|
7
6
|
import unasync
|
|
8
|
-
from pathlib import Path
|
|
9
7
|
from tempfile import TemporaryDirectory
|
|
10
8
|
from urllib.parse import urlparse
|
|
11
9
|
from typing import List, Optional
|
|
12
10
|
|
|
13
11
|
from datamodel_code_generator import InputFileType, generate
|
|
14
|
-
import typer
|
|
15
12
|
|
|
16
13
|
|
|
17
14
|
cli = typer.Typer()
|
|
@@ -91,10 +88,10 @@ def run_unasync():
|
|
|
91
88
|
# can't determine the type, so we have to patch things up, for now they are all
|
|
92
89
|
# string based enums.
|
|
93
90
|
def _to_str_enum(code: str) -> str:
|
|
94
|
-
pattern = re.compile(
|
|
91
|
+
pattern = re.compile(r"(.*)\(Enum\)(.*)", re.DOTALL)
|
|
95
92
|
|
|
96
93
|
while pattern.match(code):
|
|
97
|
-
code = re.sub(pattern,
|
|
94
|
+
code = re.sub(pattern, r"\1(str, Enum)\2", code)
|
|
98
95
|
|
|
99
96
|
return code
|
|
100
97
|
|
|
@@ -151,9 +148,9 @@ def _from_json(json: Path, class_name: str) -> str:
|
|
|
151
148
|
|
|
152
149
|
|
|
153
150
|
#
|
|
154
|
-
# Generate models using datamodel-codegen using OpenAPI spec and a sample JSON job
|
|
155
|
-
# Eventually is would be nice to move the job status model into SF
|
|
156
|
-
# only on the OpenAPI spec.
|
|
151
|
+
# Generate models using datamodel-codegen using OpenAPI spec and a sample JSON job
|
|
152
|
+
# status output. Eventually is would be nice to move the job status model into SF
|
|
153
|
+
# API, so cold then just rely only on the OpenAPI spec.
|
|
157
154
|
#
|
|
158
155
|
@cli.command(name="codegen")
|
|
159
156
|
def openapimodel_codegen(
|
|
@@ -12,8 +12,6 @@ from authlib.jose import JsonWebKey
|
|
|
12
12
|
from .compute import Machine, AsyncCompute
|
|
13
13
|
from ..exceptions import SfApiError
|
|
14
14
|
from .._models import (
|
|
15
|
-
JobOutput as JobStatusResponse,
|
|
16
|
-
AppRoutersComputeModelsStatus as JobStatus,
|
|
17
15
|
Changelog as ChangelogItem,
|
|
18
16
|
Config as ConfItem,
|
|
19
17
|
Outage,
|
|
@@ -256,7 +254,7 @@ class AsyncClient:
|
|
|
256
254
|
|
|
257
255
|
async def _oauth2_session(self):
|
|
258
256
|
if self._client_id is None:
|
|
259
|
-
raise SfApiError(
|
|
257
|
+
raise SfApiError("No credentials have been provides")
|
|
260
258
|
|
|
261
259
|
if self.__oauth2_session is None:
|
|
262
260
|
# Create a new session if we haven't already
|
|
@@ -514,3 +512,10 @@ AsyncProject.model_rebuild()
|
|
|
514
512
|
AsyncRemotePath.model_rebuild()
|
|
515
513
|
AsyncRole.model_rebuild()
|
|
516
514
|
AsyncGroupMember.model_rebuild()
|
|
515
|
+
|
|
516
|
+
# Ensure that the job models are built, we need to import here to
|
|
517
|
+
# avoid circular imports
|
|
518
|
+
from .jobs import AsyncJobSacct, AsyncJobSqueue # noqa: E402
|
|
519
|
+
|
|
520
|
+
AsyncJobSqueue.model_rebuild()
|
|
521
|
+
AsyncJobSacct.model_rebuild()
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import asyncio
|
|
2
1
|
from typing import Dict, List, Optional, Union, Callable
|
|
3
2
|
import json
|
|
4
|
-
from
|
|
5
|
-
from pydantic import BaseModel, PrivateAttr, ConfigDict
|
|
6
|
-
from functools import wraps
|
|
7
|
-
|
|
3
|
+
from pydantic import PrivateAttr, ConfigDict
|
|
8
4
|
from ..exceptions import SfApiError
|
|
9
5
|
from .._utils import _ASYNC_SLEEP
|
|
10
|
-
from .jobs import AsyncJobSacct, AsyncJobSqueue,
|
|
6
|
+
from .jobs import AsyncJobSacct, AsyncJobSqueue, JobCommand
|
|
11
7
|
from .._models import (
|
|
12
8
|
AppRoutersStatusModelsStatus as ComputeBase,
|
|
13
9
|
Task,
|
|
@@ -26,11 +22,10 @@ Machine.__str__ = lambda self: self.value
|
|
|
26
22
|
|
|
27
23
|
|
|
28
24
|
def check_auth(method: Callable):
|
|
29
|
-
@wraps(method)
|
|
30
25
|
def wrapper(self, *args, **kwargs):
|
|
31
26
|
if self.client._client_id is None:
|
|
32
27
|
raise SfApiError(
|
|
33
|
-
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client."
|
|
28
|
+
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client." # noqa: E501
|
|
34
29
|
)
|
|
35
30
|
elif self.status in [StatusValue.unavailable]:
|
|
36
31
|
raise SfApiError(
|
|
@@ -42,7 +37,7 @@ def check_auth(method: Callable):
|
|
|
42
37
|
|
|
43
38
|
|
|
44
39
|
class AsyncCompute(ComputeBase):
|
|
45
|
-
client: Optional["AsyncClient"]
|
|
40
|
+
client: Optional["AsyncClient"] # noqa: F821
|
|
46
41
|
_monitor: AsyncJobMonitor = PrivateAttr()
|
|
47
42
|
|
|
48
43
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
@@ -131,7 +126,7 @@ class AsyncCompute(ComputeBase):
|
|
|
131
126
|
Job = AsyncJobSacct if (command == JobCommand.sacct) else AsyncJobSqueue
|
|
132
127
|
jobs = await self._monitor.fetch_jobs(job_type=Job, jobids=[jobid])
|
|
133
128
|
if len(jobs) == 0:
|
|
134
|
-
raise SfApiError(f"Job not found:
|
|
129
|
+
raise SfApiError(f"Job not found: {jobid}")
|
|
135
130
|
|
|
136
131
|
return jobs[0]
|
|
137
132
|
|
|
@@ -11,7 +11,7 @@ def check_auth(method: Callable):
|
|
|
11
11
|
def wrapper(self, *args, **kwargs):
|
|
12
12
|
if self._client_id is None:
|
|
13
13
|
raise SfApiError(
|
|
14
|
-
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client."
|
|
14
|
+
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client." # noqa: E501
|
|
15
15
|
)
|
|
16
16
|
return method(self, *args, **kwargs)
|
|
17
17
|
|
|
@@ -19,7 +19,7 @@ def check_auth(method: Callable):
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class AsyncGroupMember(GroupMemberBase):
|
|
22
|
-
client: Optional["AsyncClient"]
|
|
22
|
+
client: Optional["AsyncClient"] # noqa: F821
|
|
23
23
|
|
|
24
24
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
25
25
|
|
|
@@ -30,13 +30,14 @@ class AsyncGroupMember(GroupMemberBase):
|
|
|
30
30
|
return await AsyncUser._fetch_user(self.client, self.name)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
# Note: We can't use our generated model as we want user => members ( to avoid
|
|
33
|
+
# Note: We can't use our generated model as we want user => members ( to avoid
|
|
34
|
+
# confusion with User model )
|
|
34
35
|
class AsyncGroup(BaseModel):
|
|
35
36
|
"""
|
|
36
37
|
A user group.
|
|
37
38
|
"""
|
|
38
39
|
|
|
39
|
-
client: Optional["AsyncClient"]
|
|
40
|
+
client: Optional["AsyncClient"] # noqa: F821
|
|
40
41
|
gid: Optional[int]
|
|
41
42
|
name: Optional[str]
|
|
42
43
|
users_: Optional[List[GroupMemberBase]] = Field(..., alias="users")
|
|
@@ -114,7 +115,7 @@ class AsyncGroup(BaseModel):
|
|
|
114
115
|
|
|
115
116
|
@staticmethod
|
|
116
117
|
@check_auth
|
|
117
|
-
async def _fetch_group(client: "AsyncClient", name):
|
|
118
|
+
async def _fetch_group(client: "AsyncClient", name): # noqa: F821
|
|
118
119
|
response = await client.get(f"account/groups/{name}")
|
|
119
120
|
|
|
120
121
|
json_response = response.json()
|
|
@@ -2,14 +2,14 @@ from __future__ import annotations
|
|
|
2
2
|
import sys
|
|
3
3
|
import math
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
|
-
from typing import Any, Optional, Dict, List, ClassVar
|
|
5
|
+
from typing import Any, Optional, Dict, List, ClassVar, Union
|
|
6
6
|
from .._utils import _ASYNC_SLEEP
|
|
7
7
|
from ..exceptions import SfApiError
|
|
8
8
|
from .._models.job_status_response_sacct import OutputItem as JobSacctBase
|
|
9
9
|
from .._models.job_status_response_squeue import OutputItem as JobSqueueBase
|
|
10
10
|
from .._models import AppRoutersComputeModelsStatus as JobResponseStatus
|
|
11
11
|
|
|
12
|
-
from pydantic import BaseModel,
|
|
12
|
+
from pydantic import BaseModel, field_validator
|
|
13
13
|
|
|
14
14
|
from .._jobs import JobCommand
|
|
15
15
|
from .._jobs import JobStateResponse
|
|
@@ -18,7 +18,7 @@ from .._jobs import TERMINAL_STATES
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
async def _fetch_raw_state(
|
|
21
|
-
compute: "AsyncCompute",
|
|
21
|
+
compute: "AsyncCompute", # noqa: F821
|
|
22
22
|
jobids: Optional[List[int]] = None,
|
|
23
23
|
user: Optional[str] = None,
|
|
24
24
|
partition: Optional[str] = None,
|
|
@@ -55,7 +55,7 @@ async def _fetch_raw_state(
|
|
|
55
55
|
|
|
56
56
|
async def _fetch_jobs(
|
|
57
57
|
job_type: Union["AsyncJobSacct", "AsyncJobSqueue"],
|
|
58
|
-
compute: "AsyncCompute",
|
|
58
|
+
compute: "AsyncCompute", # noqa: F821
|
|
59
59
|
jobids: Optional[List[int]] = None,
|
|
60
60
|
user: Optional[str] = None,
|
|
61
61
|
partition: Optional[str] = None,
|
|
@@ -76,7 +76,7 @@ class AsyncJob(BaseModel, ABC):
|
|
|
76
76
|
Models a job submitted to run on a compute resource.
|
|
77
77
|
"""
|
|
78
78
|
|
|
79
|
-
compute: Optional["AsyncCompute"] = None
|
|
79
|
+
compute: Optional["AsyncCompute"] = None # noqa: F821
|
|
80
80
|
state: Optional[JobState] = None
|
|
81
81
|
jobid: Optional[str] = None
|
|
82
82
|
|
|
@@ -97,7 +97,7 @@ class AsyncJob(BaseModel, ABC):
|
|
|
97
97
|
job_state = await self._fetch_state()
|
|
98
98
|
self._update(job_state)
|
|
99
99
|
|
|
100
|
-
def _update(self, new_job_state: Any) -> Job:
|
|
100
|
+
def _update(self, new_job_state: Any) -> Job: # noqa: F821
|
|
101
101
|
for k in new_job_state.model_fields_set:
|
|
102
102
|
v = getattr(new_job_state, k)
|
|
103
103
|
setattr(self, k, v)
|
|
@@ -129,8 +129,8 @@ class AsyncJob(BaseModel, ABC):
|
|
|
129
129
|
"""
|
|
130
130
|
Wait for a job to move into a terminal state.
|
|
131
131
|
|
|
132
|
-
:param timeout: The maximum time to wait in seconds, the actually
|
|
133
|
-
10 second increments.
|
|
132
|
+
:param timeout: The maximum time to wait in seconds, the actually
|
|
133
|
+
wait time will be in 10 second increments.
|
|
134
134
|
:raises TimeoutError: if timeout is reached
|
|
135
135
|
"""
|
|
136
136
|
return await self._wait_until_complete(timeout)
|
|
@@ -139,8 +139,8 @@ class AsyncJob(BaseModel, ABC):
|
|
|
139
139
|
"""
|
|
140
140
|
Wait for a job to move into running state.
|
|
141
141
|
|
|
142
|
-
:param timeout: The maximum time to wait in seconds, the actually wait
|
|
143
|
-
10 second increments.
|
|
142
|
+
:param timeout: The maximum time to wait in seconds, the actually wait
|
|
143
|
+
time will be in 10 second increments.
|
|
144
144
|
:raises TimeoutError: if timeout if reached
|
|
145
145
|
"""
|
|
146
146
|
state = await self._wait_until([JobState.RUNNING] + TERMINAL_STATES, timeout)
|
|
@@ -155,7 +155,8 @@ class AsyncJob(BaseModel, ABC):
|
|
|
155
155
|
"""
|
|
156
156
|
Cancel a running job
|
|
157
157
|
|
|
158
|
-
:param wait: True, to wait for job be to cancel, otherwise returns when
|
|
158
|
+
:param wait: True, to wait for job be to cancel, otherwise returns when
|
|
159
|
+
cancellation
|
|
159
160
|
has been submitted.
|
|
160
161
|
:type wait: bool
|
|
161
162
|
|
|
@@ -199,7 +200,7 @@ class AsyncJobSacct(AsyncJob, JobSacctBase):
|
|
|
199
200
|
@classmethod
|
|
200
201
|
async def _fetch_jobs(
|
|
201
202
|
cls,
|
|
202
|
-
compute: "AsyncCompute",
|
|
203
|
+
compute: "AsyncCompute", # noqa: F821
|
|
203
204
|
jobids: Optional[List[int]] = None,
|
|
204
205
|
user: Optional[str] = None,
|
|
205
206
|
partition: Optional[str] = None,
|
|
@@ -241,7 +242,7 @@ class AsyncJobSqueue(AsyncJob, JobSqueueBase):
|
|
|
241
242
|
@classmethod
|
|
242
243
|
async def _fetch_jobs(
|
|
243
244
|
cls,
|
|
244
|
-
compute: "AsyncCompute",
|
|
245
|
+
compute: "AsyncCompute", # noqa: F821
|
|
245
246
|
jobids: Optional[List[int]] = None,
|
|
246
247
|
user: Optional[str] = None,
|
|
247
248
|
partition: Optional[str] = None,
|
|
@@ -28,7 +28,7 @@ class AsyncRemotePath(PathBase):
|
|
|
28
28
|
pathlib and shares some of its interface.
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
|
-
compute: Optional["AsyncCompute"]
|
|
31
|
+
compute: Optional["AsyncCompute"] # noqa: F821
|
|
32
32
|
# It would be nice to be able subclass PurePosixPath, however, this
|
|
33
33
|
# require using private interfaces. So we derive by composition.
|
|
34
34
|
_path: PurePosixPath = PrivateAttr()
|
|
@@ -54,7 +54,7 @@ class AsyncRemotePath(PathBase):
|
|
|
54
54
|
return str(self._path)
|
|
55
55
|
|
|
56
56
|
@property
|
|
57
|
-
def parent(self) -> "RemotePath":
|
|
57
|
+
def parent(self) -> "RemotePath": # noqa: F821
|
|
58
58
|
"""
|
|
59
59
|
The parent of the path.
|
|
60
60
|
|
|
@@ -66,7 +66,7 @@ class AsyncRemotePath(PathBase):
|
|
|
66
66
|
return parent_path
|
|
67
67
|
|
|
68
68
|
@property
|
|
69
|
-
def parents(self) -> List["RemotePath"]:
|
|
69
|
+
def parents(self) -> List["RemotePath"]: # noqa: F821
|
|
70
70
|
"""
|
|
71
71
|
The parents of the path.
|
|
72
72
|
|
|
@@ -139,7 +139,8 @@ class AsyncRemotePath(PathBase):
|
|
|
139
139
|
"""
|
|
140
140
|
Download the file contents.
|
|
141
141
|
|
|
142
|
-
:param binary: indicate if the file should be treated as binary, defaults
|
|
142
|
+
:param binary: indicate if the file should be treated as binary, defaults
|
|
143
|
+
to False
|
|
143
144
|
:raises IsADirectoryError: if path points to a directory.
|
|
144
145
|
:raises SfApiError:
|
|
145
146
|
"""
|
|
@@ -164,8 +165,11 @@ class AsyncRemotePath(PathBase):
|
|
|
164
165
|
|
|
165
166
|
@staticmethod
|
|
166
167
|
async def _ls(
|
|
167
|
-
compute: "
|
|
168
|
-
|
|
168
|
+
compute: "AsyncCompute", # noqa: F821
|
|
169
|
+
path,
|
|
170
|
+
directory=False,
|
|
171
|
+
filter_dots=True, # noqa: F821
|
|
172
|
+
) -> List["RemotePath"]: # noqa: F821
|
|
169
173
|
r = await compute.client.get(f"utilities/ls/{compute.name}/{path}")
|
|
170
174
|
|
|
171
175
|
json_response = r.json()
|
|
@@ -250,9 +254,9 @@ class AsyncRemotePath(PathBase):
|
|
|
250
254
|
upload_path = str(self._path)
|
|
251
255
|
except SfApiError as ex:
|
|
252
256
|
# Its a valid use case to add a upload a new file to an exiting directory.
|
|
253
|
-
# In this case the is_dir() will raise a SfApiError with
|
|
254
|
-
# So we check for that and then see if the
|
|
255
|
-
# it does we can just continue.
|
|
257
|
+
# In this case the is_dir() will raise a SfApiError with
|
|
258
|
+
# "No such file or directory" So we check for that and then see if the
|
|
259
|
+
# parent directory exists, if it does we can just continue.
|
|
256
260
|
if not _is_no_such(ex):
|
|
257
261
|
raise
|
|
258
262
|
|
|
@@ -291,9 +295,9 @@ class AsyncRemotePath(PathBase):
|
|
|
291
295
|
raise IsADirectoryError()
|
|
292
296
|
except SfApiError as ex:
|
|
293
297
|
# Its a valid use case to add a open a new file to an exiting directory.
|
|
294
|
-
# In this case the is_dir() will raise a SfApiError with
|
|
295
|
-
# So we check for that and then see if the
|
|
296
|
-
# it does we can just continue.
|
|
298
|
+
# In this case the is_dir() will raise a SfApiError with
|
|
299
|
+
# "No such file or directory" So we check for that and then see if the
|
|
300
|
+
# parent directory exists, if it does we can just continue.
|
|
297
301
|
if not _is_no_such(ex):
|
|
298
302
|
raise
|
|
299
303
|
|
|
@@ -6,18 +6,18 @@ from ..exceptions import SfApiError
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class AsyncRole(RoleBase):
|
|
9
|
-
client: Optional["AsyncClient"]
|
|
9
|
+
client: Optional["AsyncClient"] # noqa: F821
|
|
10
10
|
|
|
11
11
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class AsyncProject(ProjectBase):
|
|
15
|
-
client: Optional["AsyncClient"]
|
|
15
|
+
client: Optional["AsyncClient"] # noqa: F821
|
|
16
16
|
name: str = Field(alias="repo_name")
|
|
17
17
|
|
|
18
18
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
19
19
|
|
|
20
|
-
async def create_group(self, name: str) -> "AsyncGroup":
|
|
20
|
+
async def create_group(self, name: str) -> "AsyncGroup": # noqa: F821
|
|
21
21
|
"""
|
|
22
22
|
Create a new project.
|
|
23
23
|
:param name: The project name
|
|
@@ -16,7 +16,7 @@ def check_auth(method: Callable):
|
|
|
16
16
|
def wrapper(self, *args, **kwargs):
|
|
17
17
|
if self._client_id is None:
|
|
18
18
|
raise SfApiError(
|
|
19
|
-
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client."
|
|
19
|
+
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client." # noqa: E501
|
|
20
20
|
)
|
|
21
21
|
return method(self, *args, **kwargs)
|
|
22
22
|
|
|
@@ -24,13 +24,16 @@ def check_auth(method: Callable):
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class AsyncUser(UserBase):
|
|
27
|
-
client: Optional["AsyncClient"]
|
|
27
|
+
client: Optional["AsyncClient"] # noqa: F821
|
|
28
28
|
|
|
29
29
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
30
30
|
|
|
31
31
|
@staticmethod
|
|
32
32
|
@check_auth
|
|
33
|
-
async def _fetch_user(
|
|
33
|
+
async def _fetch_user(
|
|
34
|
+
client: "AsyncClient", # noqa: F821
|
|
35
|
+
username: Optional[str] = None, # noqa: F821
|
|
36
|
+
): # noqa: F821
|
|
34
37
|
url = "account/"
|
|
35
38
|
if username is not None:
|
|
36
39
|
url = f"{url}?username={username}"
|
|
@@ -42,7 +45,7 @@ class AsyncUser(UserBase):
|
|
|
42
45
|
|
|
43
46
|
return user
|
|
44
47
|
|
|
45
|
-
async def groups(self) -> List["AsyncGroup"]:
|
|
48
|
+
async def groups(self) -> List["AsyncGroup"]: # noqa: F821
|
|
46
49
|
"""
|
|
47
50
|
The groups that the user is a member of.
|
|
48
51
|
|
|
@@ -52,7 +55,7 @@ class AsyncUser(UserBase):
|
|
|
52
55
|
from .groups import AsyncGroup
|
|
53
56
|
|
|
54
57
|
if self.name != (await self.client._user()).name:
|
|
55
|
-
raise SfApiError(
|
|
58
|
+
raise SfApiError("Can only fetch groups for authenticated user.")
|
|
56
59
|
|
|
57
60
|
r = await self.client.get("account/groups")
|
|
58
61
|
|
|
@@ -73,7 +76,7 @@ class AsyncUser(UserBase):
|
|
|
73
76
|
:return: the projects
|
|
74
77
|
"""
|
|
75
78
|
if self.name != (await self.client._user()).name:
|
|
76
|
-
raise SfApiError(
|
|
79
|
+
raise SfApiError("Can only fetch projects for authenticated user.")
|
|
77
80
|
|
|
78
81
|
r = await self.client.get("account/projects")
|
|
79
82
|
|
|
@@ -93,7 +96,7 @@ class AsyncUser(UserBase):
|
|
|
93
96
|
:return: the roles
|
|
94
97
|
"""
|
|
95
98
|
if self.name != (await self.client._user()).name:
|
|
96
|
-
raise SfApiError(
|
|
99
|
+
raise SfApiError("Can only fetch roles for authenticated user.")
|
|
97
100
|
|
|
98
101
|
r = await self.client.get("account/roles")
|
|
99
102
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: https://api.nersc.gov/api/v1.2/openapi.json
|
|
3
|
-
# timestamp: 2023-
|
|
3
|
+
# timestamp: 2023-10-20T20:57:45+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
@@ -87,7 +87,6 @@ class Outage(BaseModel):
|
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
class PublicHost(str, Enum):
|
|
90
|
-
cori = "cori"
|
|
91
90
|
dtn01 = "dtn01"
|
|
92
91
|
perlmutter = "perlmutter"
|
|
93
92
|
|
|
@@ -118,7 +117,6 @@ class StorageStats(BaseModel):
|
|
|
118
117
|
|
|
119
118
|
class Task(BaseModel):
|
|
120
119
|
id: str = Field(..., title="Id")
|
|
121
|
-
uuid: Optional[str] = Field(None, title="Uuid")
|
|
122
120
|
status: Optional[str] = Field(None, title="Status")
|
|
123
121
|
result: Optional[str] = Field(None, title="Result")
|
|
124
122
|
|
|
@@ -130,12 +128,12 @@ class Tasks(BaseModel):
|
|
|
130
128
|
class UserInfo(BaseModel):
|
|
131
129
|
uid: int = Field(..., title="Uid")
|
|
132
130
|
name: str = Field(..., title="Name")
|
|
133
|
-
firstname: str = Field(
|
|
134
|
-
lastname: str = Field(
|
|
135
|
-
middlename: str = Field(
|
|
136
|
-
workphone: str = Field(
|
|
137
|
-
otherPhones: str = Field(
|
|
138
|
-
email: str = Field(
|
|
131
|
+
firstname: Optional[str] = Field(None, title="Firstname")
|
|
132
|
+
lastname: Optional[str] = Field(None, title="Lastname")
|
|
133
|
+
middlename: Optional[str] = Field(None, title="Middlename")
|
|
134
|
+
workphone: Optional[str] = Field(None, title="Workphone")
|
|
135
|
+
otherPhones: Optional[str] = Field(None, title="Otherphones")
|
|
136
|
+
email: Optional[str] = Field(None, title="Email")
|
|
139
137
|
|
|
140
138
|
|
|
141
139
|
class UserStats(BaseModel):
|
|
@@ -15,9 +15,9 @@ from ._sync.jobs import _fetch_jobs, JobSacct, JobSqueue
|
|
|
15
15
|
# Async monitor that batches request for job state into fewer request by
|
|
16
16
|
# requesting that state of multiple jobs in a single request to the server.
|
|
17
17
|
class AsyncJobMonitor:
|
|
18
|
-
def __init__(self, compute: "AsyncCompute"):
|
|
18
|
+
def __init__(self, compute: "AsyncCompute"): # noqa: F821
|
|
19
19
|
self._jobids: Dict[Type, Set[int]] = {}
|
|
20
|
-
self._compute: "AsyncCompute" = compute
|
|
20
|
+
self._compute: "AsyncCompute" = compute # noqa: F821
|
|
21
21
|
self._monitor_task: asyncio.Task = None
|
|
22
22
|
self._futures: Dict[Type, Future] = {}
|
|
23
23
|
self._last_job_type_fetched: Type = None
|
|
@@ -126,7 +126,7 @@ class JobRequest:
|
|
|
126
126
|
# a time and aggregates the waiting requests.
|
|
127
127
|
#
|
|
128
128
|
class SyncJobMonitor:
|
|
129
|
-
def __init__(self, compute: "Compute"):
|
|
129
|
+
def __init__(self, compute: "Compute"): # noqa: F821
|
|
130
130
|
self._compute = compute
|
|
131
131
|
self._requests: Dict[Type, Set[JobRequest]] = {}
|
|
132
132
|
# Lock to protect access to self._requests
|
|
File without changes
|