Skip to content

Commit

Permalink
Merge pull request #69 from tylern4/update_wrapper_and_models
Browse files Browse the repository at this point in the history
Update wrapper and models
  • Loading branch information
tylern4 authored Oct 23, 2023
2 parents 55af1e2 + cf40eab commit 284acda
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/black.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: psf/black@stable
- uses: psf/black@23.9.1
with:
options: "--check --verbose"
jupyter: false
Empty file added .pre-commit-config.yaml
Empty file.
3 changes: 2 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ unasync
typer
pytest
pytest-asyncio
mkdocs-jupyter
mkdocs-jupyter
datamodel-code-generator[http]
11 changes: 3 additions & 8 deletions src/sfapi_client/_async/compute.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from typing import Dict, List, Optional, Union, Callable
import json
from pydantic import PrivateAttr, ConfigDict
from functools import wraps

from ..exceptions import SfApiError
from .._utils import _ASYNC_SLEEP
from .jobs import AsyncJobSacct, AsyncJobSqueue, JobCommand
Expand All @@ -24,7 +22,6 @@


def check_auth(method: Callable):
@wraps(method)
def wrapper(self, *args, **kwargs):
if self.client._client_id is None:
raise SfApiError(
Expand Down Expand Up @@ -74,10 +71,8 @@ async def _wait_for_task(self, task_id) -> str:
async def submit_job(self, script: Union[str, AsyncRemotePath]) -> AsyncJobSqueue:
"""Submit a job to the compute resource
:param script: Path to file on the compute system, or script to run beginning
with `#!`.
:return: Object containing information about the job, its job id, and status
on the system.
:param script: Path to file on the compute system, or script to run beginning with `#!`.
:return: Object containing information about the job, its job id, and status on the system.
"""

is_path: bool = True
Expand Down Expand Up @@ -131,7 +126,7 @@ async def job(
Job = AsyncJobSacct if (command == JobCommand.sacct) else AsyncJobSqueue
jobs = await self._monitor.fetch_jobs(job_type=Job, jobids=[jobid])
if len(jobs) == 0:
raise SfApiError(f"Job not found: ${jobid}")
raise SfApiError(f"Job not found: {jobid}")

return jobs[0]

Expand Down
16 changes: 7 additions & 9 deletions src/sfapi_client/_models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# generated by datamodel-codegen:
# filename: https://api.nersc.gov/api/v1.2/openapi.json
# timestamp: 2023-07-05T20:00:24+00:00
# timestamp: 2023-10-20T20:57:45+00:00

from __future__ import annotations

Expand Down Expand Up @@ -87,7 +87,6 @@ class Outage(BaseModel):


class PublicHost(str, Enum):
cori = "cori"
dtn01 = "dtn01"
perlmutter = "perlmutter"

Expand Down Expand Up @@ -118,7 +117,6 @@ class StorageStats(BaseModel):

class Task(BaseModel):
id: str = Field(..., title="Id")
uuid: Optional[str] = Field(None, title="Uuid")
status: Optional[str] = Field(None, title="Status")
result: Optional[str] = Field(None, title="Result")

Expand All @@ -130,12 +128,12 @@ class Tasks(BaseModel):
class UserInfo(BaseModel):
uid: int = Field(..., title="Uid")
name: str = Field(..., title="Name")
firstname: str = Field(..., title="Firstname")
lastname: str = Field(..., title="Lastname")
middlename: str = Field(..., title="Middlename")
workphone: str = Field(..., title="Workphone")
otherPhones: str = Field(..., title="Otherphones")
email: str = Field(..., title="Email")
firstname: Optional[str] = Field(None, title="Firstname")
lastname: Optional[str] = Field(None, title="Lastname")
middlename: Optional[str] = Field(None, title="Middlename")
workphone: Optional[str] = Field(None, title="Workphone")
otherPhones: Optional[str] = Field(None, title="Otherphones")
email: Optional[str] = Field(None, title="Email")


class UserStats(BaseModel):
Expand Down
4 changes: 1 addition & 3 deletions src/sfapi_client/_sync/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
from .compute import Machine, Compute
from ..exceptions import SfApiError
from .._models import (
JobOutput as JobStatusResponse,
AppRoutersComputeModelsStatus as JobStatus,
Changelog as ChangelogItem,
Config as ConfItem,
Outage,
Expand Down Expand Up @@ -256,7 +254,7 @@ def __enter__(self):

def _oauth2_session(self):
if self._client_id is None:
raise SfApiError(f"No credentials have been provides")
raise SfApiError("No credentials have been provides")

if self.__oauth2_session is None:
# Create a new session if we haven't already
Expand Down
15 changes: 5 additions & 10 deletions src/sfapi_client/_sync/compute.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import asyncio
from typing import Dict, List, Optional, Union, Callable
import json
from enum import Enum
from pydantic import BaseModel, PrivateAttr, ConfigDict
from functools import wraps

from pydantic import PrivateAttr, ConfigDict
from ..exceptions import SfApiError
from .._utils import _SLEEP
from .jobs import JobSacct, JobSqueue, JobSqueue, JobCommand
from .jobs import JobSacct, JobSqueue, JobCommand
from .._models import (
AppRoutersStatusModelsStatus as ComputeBase,
Task,
Expand All @@ -26,11 +22,10 @@


def check_auth(method: Callable):
@wraps(method)
def wrapper(self, *args, **kwargs):
if self.client._client_id is None:
raise SfApiError(
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client."
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client." # noqa: E501
)
elif self.status in [StatusValue.unavailable]:
raise SfApiError(
Expand All @@ -42,7 +37,7 @@ def wrapper(self, *args, **kwargs):


class Compute(ComputeBase):
client: Optional["Client"]
client: Optional["Client"] # noqa: F821
_monitor: SyncJobMonitor = PrivateAttr()

model_config = ConfigDict(arbitrary_types_allowed=True)
Expand Down Expand Up @@ -131,7 +126,7 @@ def job(
Job = JobSacct if (command == JobCommand.sacct) else JobSqueue
jobs = self._monitor.fetch_jobs(job_type=Job, jobids=[jobid])
if len(jobs) == 0:
raise SfApiError(f"Job not found: ${jobid}")
raise SfApiError(f"Job not found: {jobid}")

return jobs[0]

Expand Down
11 changes: 6 additions & 5 deletions src/sfapi_client/_sync/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ def check_auth(method: Callable):
def wrapper(self, *args, **kwargs):
if self._client_id is None:
raise SfApiError(
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client."
f"Cannot call {self.__class__.__name__}.{method.__name__}() with an unauthenticated client." # noqa: E501
)
return method(self, *args, **kwargs)

return wrapper


class GroupMember(GroupMemberBase):
client: Optional["Client"]
client: Optional["Client"] # noqa: F821

model_config = ConfigDict(arbitrary_types_allowed=True)

Expand All @@ -30,13 +30,14 @@ def user(self) -> "User":
return User._fetch_user(self.client, self.name)


# Note: We can't use our generated model as we want user => members ( to avoid confusion with User model )
# Note: We can't use our generated model as we want user => members ( to avoid
# confusion with User model )
class Group(BaseModel):
"""
A user group.
"""

client: Optional["Client"]
client: Optional["Client"] # noqa: F821
gid: Optional[int]
name: Optional[str]
users_: Optional[List[GroupMemberBase]] = Field(..., alias="users")
Expand Down Expand Up @@ -114,7 +115,7 @@ def _set_client(m):

@staticmethod
@check_auth
def _fetch_group(client: "Client", name):
def _fetch_group(client: "Client", name): # noqa: F821
response = client.get(f"account/groups/{name}")

json_response = response.json()
Expand Down
27 changes: 14 additions & 13 deletions src/sfapi_client/_sync/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import sys
import math
from abc import ABC, abstractmethod
from typing import Any, Optional, Dict, List, ClassVar
from typing import Any, Optional, Dict, List, ClassVar, Union
from .._utils import _SLEEP
from ..exceptions import SfApiError
from .._models.job_status_response_sacct import OutputItem as JobSacctBase
from .._models.job_status_response_squeue import OutputItem as JobSqueueBase
from .._models import AppRoutersComputeModelsStatus as JobResponseStatus

from pydantic import BaseModel, Field, field_validator
from pydantic import BaseModel, field_validator

from .._jobs import JobCommand
from .._jobs import JobStateResponse
Expand All @@ -18,7 +18,7 @@


def _fetch_raw_state(
compute: "Compute",
compute: "Compute", # noqa: F821
jobids: Optional[List[int]] = None,
user: Optional[str] = None,
partition: Optional[str] = None,
Expand Down Expand Up @@ -55,7 +55,7 @@ def _fetch_raw_state(

def _fetch_jobs(
job_type: Union["JobSacct", "JobSqueue"],
compute: "Compute",
compute: "Compute", # noqa: F821
jobids: Optional[List[int]] = None,
user: Optional[str] = None,
partition: Optional[str] = None,
Expand All @@ -76,7 +76,7 @@ class Job(BaseModel, ABC):
Models a job submitted to run on a compute resource.
"""

compute: Optional["Compute"] = None
compute: Optional["Compute"] = None # noqa: F821
state: Optional[JobState] = None
jobid: Optional[str] = None

Expand All @@ -97,7 +97,7 @@ def update(self):
job_state = self._fetch_state()
self._update(job_state)

def _update(self, new_job_state: Any) -> Job:
def _update(self, new_job_state: Any) -> Job: # noqa: F821
for k in new_job_state.model_fields_set:
v = getattr(new_job_state, k)
setattr(self, k, v)
Expand Down Expand Up @@ -129,8 +129,8 @@ def complete(self, timeout: int = sys.maxsize):
"""
Wait for a job to move into a terminal state.
:param timeout: The maximum time to wait in seconds, the actually wait time will be in
10 second increments.
:param timeout: The maximum time to wait in seconds, the actually
wait time will be in 10 second increments.
:raises TimeoutError: if timeout is reached
"""
return self._wait_until_complete(timeout)
Expand All @@ -139,8 +139,8 @@ def running(self, timeout: int = sys.maxsize):
"""
Wait for a job to move into running state.
:param timeout: The maximum time to wait in seconds, the actually wait time will be in
10 second increments.
:param timeout: The maximum time to wait in seconds, the actually wait
time will be in 10 second increments.
:raises TimeoutError: if timeout if reached
"""
state = self._wait_until([JobState.RUNNING] + TERMINAL_STATES, timeout)
Expand All @@ -155,7 +155,8 @@ def cancel(self, wait=False):
"""
Cancel a running job
:param wait: True, to wait for job be to cancel, otherwise returns when cancellation
:param wait: True, to wait for job be to cancel, otherwise returns when
cancellation
has been submitted.
:type wait: bool
Expand Down Expand Up @@ -199,7 +200,7 @@ def _fetch_state(self):
@classmethod
def _fetch_jobs(
cls,
compute: "Compute",
compute: "Compute", # noqa: F821
jobids: Optional[List[int]] = None,
user: Optional[str] = None,
partition: Optional[str] = None,
Expand Down Expand Up @@ -241,7 +242,7 @@ def _fetch_state(self):
@classmethod
def _fetch_jobs(
cls,
compute: "Compute",
compute: "Compute", # noqa: F821
jobids: Optional[List[int]] = None,
user: Optional[str] = None,
partition: Optional[str] = None,
Expand Down
25 changes: 13 additions & 12 deletions src/sfapi_client/_sync/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class RemotePath(PathBase):
pathlib and shares some of its interface.
"""

compute: Optional["Compute"]
compute: Optional["Compute"] # noqa: F821
# It would be nice to be able subclass PurePosixPath, however, this
# require using private interfaces. So we derive by composition.
_path: PurePosixPath = PrivateAttr()
Expand All @@ -54,7 +54,7 @@ def __str__(self):
return str(self._path)

@property
def parent(self) -> "RemotePath":
def parent(self) -> "RemotePath": # noqa: F821
"""
The parent of the path.
Expand All @@ -66,7 +66,7 @@ def parent(self) -> "RemotePath":
return parent_path

@property
def parents(self) -> List["RemotePath"]:
def parents(self) -> List["RemotePath"]: # noqa: F821
"""
The parents of the path.
Expand Down Expand Up @@ -139,7 +139,8 @@ def download(self, binary=False) -> IO[AnyStr]:
"""
Download the file contents.
:param binary: indicate if the file should be treated as binary, defaults to False
:param binary: indicate if the file should be treated as binary, defaults
to False
:raises IsADirectoryError: if path points to a directory.
:raises SfApiError:
"""
Expand All @@ -164,8 +165,8 @@ def download(self, binary=False) -> IO[AnyStr]:

@staticmethod
def _ls(
compute: "Compute", path, directory=False, filter_dots=True
) -> List["RemotePath"]:
compute: "Compute", path, directory=False, filter_dots=True # noqa: F821
) -> List["RemotePath"]: # noqa: F821
r = compute.client.get(f"utilities/ls/{compute.name}/{path}")

json_response = r.json()
Expand Down Expand Up @@ -250,9 +251,9 @@ def upload(self, file: BytesIO) -> "RemotePath":
upload_path = str(self._path)
except SfApiError as ex:
# Its a valid use case to add a upload a new file to an exiting directory.
# In this case the is_dir() will raise a SfApiError with "No such file or directory"
# So we check for that and then see if the parent directory exists, if
# it does we can just continue.
# In this case the is_dir() will raise a SfApiError with
# "No such file or directory" So we check for that and then see if the
# parent directory exists, if it does we can just continue.
if not _is_no_such(ex):
raise

Expand Down Expand Up @@ -291,9 +292,9 @@ def open(self, mode: str) -> IO[AnyStr]:
raise IsADirectoryError()
except SfApiError as ex:
# Its a valid use case to add a open a new file to an exiting directory.
# In this case the is_dir() will raise a SfApiError with "No such file or directory"
# So we check for that and then see if the parent directory exists, if
# it does we can just continue.
# In this case the is_dir() will raise a SfApiError with
# "No such file or directory" So we check for that and then see if the
# parent directory exists, if it does we can just continue.
if not _is_no_such(ex):
raise

Expand Down
Loading

0 comments on commit 284acda

Please sign in to comment.