sfapi-client 0.3.1__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/PKG-INFO +2 -2
  2. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_async/client.py +9 -3
  3. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_async/jobs.py +3 -1
  4. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_models/__init__.py +34 -19
  5. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_sync/client.py +10 -7
  6. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_sync/jobs.py +3 -1
  7. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_groups.py +2 -9
  8. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_jobs.py +4 -24
  9. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_jobs_async.py +2 -15
  10. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/.github/dependabot.yml +0 -0
  11. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/.github/workflows/black.yml +0 -0
  12. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/.github/workflows/mkdocs.yml +0 -0
  13. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/.github/workflows/pypi.yml +0 -0
  14. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/.github/workflows/pytest.yml +0 -0
  15. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/.github/workflows/ruff.yml +0 -0
  16. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/.gitignore +0 -0
  17. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/.pre-commit-config.yaml +0 -0
  18. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/LEGAL +0 -0
  19. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/LICENSE +0 -0
  20. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/README.md +0 -0
  21. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/community/contributing.md +0 -0
  22. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/examples/check_current_and_past_jobs.ipynb +0 -0
  23. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/examples/getting_bearer_token.ipynb +0 -0
  24. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/examples/run_job_and_check_status.ipynb +0 -0
  25. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/gen_examples.py +0 -0
  26. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/gen_sync.py +0 -0
  27. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/index.md +0 -0
  28. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/javascript/apiselector.js +0 -0
  29. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/quickstart/index.md +0 -0
  30. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/SUMMARY.txt +0 -0
  31. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/client/index.md +0 -0
  32. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/compute/index.md +0 -0
  33. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/exceptions/index.md +0 -0
  34. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/groups/index.md +0 -0
  35. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/jobs/index.md +0 -0
  36. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/paths/index.md +0 -0
  37. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/projects/index.md +0 -0
  38. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/resources/index.md +0 -0
  39. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/docs/reference/async/users/index.md +0 -0
  40. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/mkdocs.yml +0 -0
  41. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/pyproject.toml +0 -0
  42. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/pytest.ini +0 -0
  43. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/requirements-dev.txt +0 -0
  44. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/scripts/run.py +0 -0
  45. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/__init__.py +0 -0
  46. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_async/__init__.py +0 -0
  47. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_async/compute.py +0 -0
  48. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_async/groups.py +0 -0
  49. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_async/paths.py +0 -0
  50. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_async/projects.py +0 -0
  51. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_async/users.py +0 -0
  52. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_compute.py +0 -0
  53. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_jobs.py +0 -0
  54. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_models/job_status_response_sacct.py +0 -0
  55. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_models/job_status_response_squeue.py +0 -0
  56. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_models/resources.py +0 -0
  57. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_monitor.py +0 -0
  58. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_sync/__init__.py +0 -0
  59. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_sync/compute.py +0 -0
  60. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_sync/groups.py +0 -0
  61. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_sync/paths.py +0 -0
  62. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_sync/projects.py +0 -0
  63. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_sync/users.py +0 -0
  64. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/_utils.py +0 -0
  65. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/client.py +0 -0
  66. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/compute.py +0 -0
  67. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/exceptions.py +0 -0
  68. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/groups.py +0 -0
  69. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/jobs.py +0 -0
  70. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/paths.py +0 -0
  71. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/projects.py +0 -0
  72. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/resources.py +0 -0
  73. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/src/sfapi_client/users.py +0 -0
  74. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/conftest.py +0 -0
  75. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_api.py +0 -0
  76. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_api_async.py +0 -0
  77. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_client.py +0 -0
  78. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_client_async.py +0 -0
  79. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_compute.py +0 -0
  80. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_compute_async.py +0 -0
  81. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_groups_async.py +0 -0
  82. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_key.py +0 -0
  83. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_paths.py +0 -0
  84. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_paths_async.py +0 -0
  85. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_projects.py +0 -0
  86. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_projects_async.py +0 -0
  87. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_resources.py +0 -0
  88. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_resources_async.py +0 -0
  89. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_users.py +0 -0
  90. {sfapi_client-0.3.1 → sfapi_client-0.4.0}/tests/test_users_async.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: sfapi_client
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Python client for NERSC SF API
5
5
  Author-email: Chris Harris <cjh@lbl.gov>, Nicholas Tyler <tylern@lbl.gov>
6
6
  License-File: LICENSE
@@ -276,9 +276,15 @@ class AsyncClient:
276
276
 
277
277
  await self.__http_client.fetch_token()
278
278
  else:
279
- # We have a session
280
- # Make sure it's still active
281
- await self.__http_client.ensure_active_token(self.__http_client.token)
279
+ if self.__http_client.token is None:
280
+ # We don't have a token, fetch one
281
+ await self.__http_client.fetch_token()
282
+ else:
283
+ # We have a session
284
+ # Make sure it's still active
285
+ await self.__http_client.ensure_active_token(
286
+ self.__http_client.token
287
+ )
282
288
  # Use regular client, but add the access token if we have one
283
289
  elif self.__http_client is None:
284
290
  # We already have an access token
@@ -24,7 +24,9 @@ async def _fetch_raw_state(
24
24
  partition: Optional[str] = None,
25
25
  sacct: Optional[bool] = False,
26
26
  ):
27
- params = {"sacct": sacct}
27
+ # For now we are pass cached=False to ensure we don't
28
+ # break compatibility
29
+ params = {"sacct": sacct, "cached": False}
28
30
 
29
31
  job_url = f"compute/jobs/{compute.name}"
30
32
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
- # filename: https://api-dev.nersc.gov/api/v1.2/openapi.json
3
- # timestamp: 2024-07-18T15:58:27+00:00
2
+ # filename: https://api.nersc.gov/api/v1.2/openapi.json
3
+ # timestamp: 2025-01-23T19:49:01+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -85,15 +85,12 @@ class Note(BaseModel):
85
85
  timestamp: Optional[datetime] = Field(None, title="Timestamp")
86
86
 
87
87
 
88
- class Outage(BaseModel):
89
- name: str = Field(..., title="Name")
90
- start_at: Optional[datetime] = Field(None, title="Start At")
91
- end_at: Optional[datetime] = Field(None, title="End At")
92
- description: Optional[str] = Field(None, title="Description")
93
- notes: Optional[str] = Field(None, title="Notes")
94
- status: Optional[str] = Field(None, title="Status")
95
- swo: Optional[str] = Field(None, title="Swo")
96
- update_at: Optional[datetime] = Field(None, title="Update At")
88
+ class OutageStatusValue(str, Enum):
89
+ Active = "Active"
90
+ Cancelled = "Cancelled"
91
+ Completed = "Completed"
92
+ Extended = "Extended"
93
+ Planned = "Planned"
97
94
 
98
95
 
99
96
  class PublicHost(str, Enum):
@@ -126,14 +123,11 @@ class StorageStats(BaseModel):
126
123
  files_used: Optional[float] = Field(None, title="Files Used")
127
124
 
128
125
 
129
- class Task(BaseModel):
130
- id: str = Field(..., title="Id")
131
- status: Optional[str] = Field(..., title="Status")
132
- result: Optional[str] = Field(..., title="Result")
133
-
134
-
135
- class Tasks(BaseModel):
136
- tasks: Optional[List[Task]] = Field(None, title="Tasks")
126
+ class TaskStatus(str, Enum):
127
+ new = "new"
128
+ completed = "completed"
129
+ cancelled = "cancelled"
130
+ failed = "failed"
137
131
 
138
132
 
139
133
  class UserInfo(BaseModel):
@@ -214,6 +208,17 @@ class JobOutput(BaseModel):
214
208
  error: Optional[str] = Field(None, title="Error")
215
209
 
216
210
 
211
+ class Outage(BaseModel):
212
+ name: str = Field(..., title="Name")
213
+ start_at: Optional[datetime] = Field(None, title="Start At")
214
+ end_at: Optional[datetime] = Field(None, title="End At")
215
+ description: Optional[str] = Field(None, title="Description")
216
+ notes: Optional[str] = Field(None, title="Notes")
217
+ status: Optional[OutageStatusValue] = None
218
+ swo: Optional[str] = Field(None, title="Swo")
219
+ update_at: Optional[datetime] = Field(None, title="Update At")
220
+
221
+
217
222
  class ProjectStats(BaseModel):
218
223
  id: int = Field(..., title="Id")
219
224
  description: str = Field(..., title="Description")
@@ -250,6 +255,16 @@ class QueueOutput(BaseModel):
250
255
  error: Optional[str] = Field(None, title="Error")
251
256
 
252
257
 
258
+ class Task(BaseModel):
259
+ id: str = Field(..., title="Id")
260
+ status: Optional[TaskStatus]
261
+ result: Optional[str] = Field(..., title="Result")
262
+
263
+
264
+ class Tasks(BaseModel):
265
+ tasks: Optional[List[Task]] = Field(..., title="Tasks")
266
+
267
+
253
268
  class TransferResult(BaseModel):
254
269
  task_id: str = Field(..., title="Task Id")
255
270
  status: AppRoutersStorageModelsStatus
@@ -276,9 +276,15 @@ class Client:
276
276
 
277
277
  self.__http_client.fetch_token()
278
278
  else:
279
- # We have a session
280
- # Make sure it's still active
281
- self.__http_client.ensure_active_token(self.__http_client.token)
279
+ if self.__http_client.token is None:
280
+ # We don't have a token, fetch one
281
+ self.__http_client.fetch_token()
282
+ else:
283
+ # We have a session
284
+ # Make sure it's still active
285
+ self.__http_client.ensure_active_token(
286
+ self.__http_client.token
287
+ )
282
288
  # Use regular client, but add the access token if we have one
283
289
  elif self.__http_client is None:
284
290
  # We already have an access token
@@ -383,10 +389,7 @@ class Client:
383
389
  stop=tenacity.stop_after_attempt(MAX_RETRY),
384
390
  )
385
391
  def post(
386
- self,
387
- url: str,
388
- data: Dict[str, Any] = None,
389
- json: Dict[str, Any] = None
392
+ self, url: str, data: Dict[str, Any] = None, json: Dict[str, Any] = None
390
393
  ) -> httpx.Response:
391
394
  client = self._http_client()
392
395
 
@@ -24,7 +24,9 @@ def _fetch_raw_state(
24
24
  partition: Optional[str] = None,
25
25
  sacct: Optional[bool] = False,
26
26
  ):
27
- params = {"sacct": sacct}
27
+ # For now we are pass cached=False to ensure we don't
28
+ # break compatibility
29
+ params = {"sacct": sacct, "cached": False}
28
30
 
29
31
  job_url = f"compute/jobs/{compute.name}"
30
32
 
@@ -3,15 +3,8 @@ from sfapi_client import Client
3
3
 
4
4
 
5
5
  @pytest.mark.api_dev
6
- def test_group(
7
- dev_client_id, dev_client_secret, test_group, dev_api_url, dev_token_url
8
- ):
9
- with Client(
10
- client_id=dev_client_id,
11
- secret=dev_client_secret,
12
- api_base_url=dev_api_url,
13
- token_url=dev_token_url,
14
- ) as client:
6
+ def test_group(authenticated_client, test_group):
7
+ with authenticated_client as client:
15
8
  group = client.group(test_group)
16
9
  assert group is not None
17
10
  assert group.name == test_group
@@ -2,7 +2,6 @@ import pytest
2
2
  from concurrent.futures import ThreadPoolExecutor
3
3
  import time
4
4
 
5
- from sfapi_client import Client
6
5
  from sfapi_client.jobs import JobState
7
6
  from sfapi_client.compute import Compute
8
7
  from sfapi_client.jobs import JobSqueue
@@ -52,22 +51,13 @@ def test_complete_timeout(authenticated_client, test_job_path, test_machine):
52
51
  job.complete(timeout=10)
53
52
 
54
53
 
55
- @pytest.mark.api_dev
56
54
  def test_job_monitor_check_request(
57
55
  mocker,
58
- dev_client_id,
59
- dev_client_secret,
56
+ authenticated_client,
60
57
  test_job_path,
61
58
  test_machine,
62
- dev_api_url,
63
- dev_token_url,
64
59
  ):
65
- with Client(
66
- client_id=dev_client_id,
67
- secret=dev_client_secret,
68
- api_base_url=dev_api_url,
69
- token_url=dev_token_url,
70
- ) as client:
60
+ with authenticated_client as client:
71
61
  num_jobs = 10
72
62
  _fetch_jobs = mocker.patch("sfapi_client._monitor._fetch_jobs")
73
63
 
@@ -122,24 +112,14 @@ def test_job_monitor_check_request(
122
112
  assert len(ids) == num_jobs
123
113
 
124
114
 
125
- # We currently run this in api-dev as its a new feature deployed there
126
- @pytest.mark.api_dev
127
115
  def test_job_monitor_multiple_threads(
128
- dev_client_id,
129
- dev_client_secret,
116
+ authenticated_client,
130
117
  test_job_path,
131
118
  test_machine,
132
- dev_api_url,
133
- dev_token_url,
134
119
  ):
135
120
  num_jobs = 5
136
121
 
137
- with Client(
138
- client_id=dev_client_id,
139
- secret=dev_client_secret,
140
- api_base_url=dev_api_url,
141
- token_url=dev_token_url,
142
- ) as client:
122
+ with authenticated_client as client:
143
123
  machine = client.compute(test_machine)
144
124
 
145
125
  jobs = []
@@ -1,7 +1,6 @@
1
1
  import pytest
2
2
  import asyncio
3
3
 
4
- from sfapi_client import AsyncClient
5
4
  from sfapi_client.compute import AsyncCompute
6
5
  from sfapi_client.jobs import AsyncJobSqueue, AsyncJobSacct, JobState
7
6
 
@@ -162,23 +161,11 @@ async def test_job_monitor_job_types(async_authenticated_client, mocker, test_ma
162
161
  assert kwargs["job_type"] == AsyncJobSacct
163
162
 
164
163
 
165
- # We currently run this in api-dev as its a new feature deployed there
166
- @pytest.mark.api_dev
167
164
  @pytest.mark.asyncio
168
165
  async def test_job_monitor_gather(
169
- dev_client_id,
170
- dev_client_secret,
171
- test_job_path,
172
- test_machine,
173
- dev_api_url,
174
- dev_token_url,
166
+ async_authenticated_client, test_job_path, test_machine
175
167
  ):
176
- async with AsyncClient(
177
- client_id=dev_client_id,
178
- secret=dev_client_secret,
179
- api_base_url=dev_api_url,
180
- token_url=dev_token_url,
181
- ) as client:
168
+ async with async_authenticated_client as client:
182
169
  machine = await client.compute(test_machine)
183
170
 
184
171
  submit_tasks = []
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes