Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make datasets optional in Project data model #339

Merged
merged 10 commits into from
Mar 6, 2024
4 changes: 3 additions & 1 deletion geti_sdk/data_models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ class Project:

name: str
pipeline: Pipeline
datasets: List[Dataset]
datasets: Optional[List[Dataset]] = (
None # `datasets` was removed from project listing in Geti v1.15
)
score: Optional[float] = None # 'score' is removed in v1.1
performance: Optional[Performance] = None
creation_time: Optional[str] = attr.field(default=None, converter=str_to_datetime)
Expand Down
13 changes: 10 additions & 3 deletions geti_sdk/http_session/geti_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,9 +515,16 @@ def _handle_error_response(
logging.info("Authentication complete.")

else:
access_token = self._acquire_access_token()
logging.info("New bearer token obtained.")
self.headers.update({"Authorization": f"Bearer {access_token}"})
if self.authentication_service == AUTHENTICATION_DEX_OLD:
access_token = self._acquire_access_token()
logging.info("New bearer token obtained.")
self.headers.update({"Authorization": f"Bearer {access_token}"})
else:
raise ValueError(
"Authentication via your personal access token has failed, "
"most likely the token has expired. Please verify that you "
"have provided a valid token."
)

retry_request = True

Expand Down
49 changes: 39 additions & 10 deletions geti_sdk/rest_clients/project_client/project_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,18 @@ def __init__(self, session: GetiSession, workspace_id: str):
self.workspace_id = workspace_id
self.base_url = f"workspaces/{workspace_id}/"

def get_all_projects(self, request_page_size: int = 50) -> List[Project]:
def get_all_projects(
self, request_page_size: int = 50, get_project_details: bool = True
) -> List[Project]:
"""
Return a list of projects found on the Intel® Geti™ server

:param request_page_size: Max number of projects to fetch in a single HTTP
request. Higher values may reduce the response time of this method when
there are many projects, but increase the chance of timeout.
:param get_project_details: True to get all details of the projects on the
Intel® Geti™, False to fetch only a summary of each project. Set this to
False if minimizing latency is a concern. Defaults to True
:return: List of Project objects, containing the project information for each
project on the Intel® Geti™ server
"""
Expand All @@ -81,19 +86,23 @@ def get_all_projects(self, request_page_size: int = 50) -> List[Project]:

# The 'projects' endpoint uses pagination: multiple HTTP may be necessary to
# fetch the full list of projects
project_list: List[Dict] = []
project_rest_list: List[Dict] = []
while response := self.session.get_rest_response(
url=f"{self.base_url}projects?limit={request_page_size}&skip={len(project_list)}",
url=f"{self.base_url}projects?limit={request_page_size}&skip={len(project_rest_list)}",
method="GET",
):
project_list.extend(response[project_key])
if len(project_list) >= response[num_total_projects_key]:
project_rest_list.extend(response[project_key])
if len(project_rest_list) >= response[num_total_projects_key]:
break

return [
project_list = [
ProjectRESTConverter.from_dict(project_input=project)
for project in project_list
for project in project_rest_list
]
if get_project_details:
return [self._get_project_detail(project) for project in project_list]
else:
return project_list

def get_project_by_name(self, project_name: str) -> Optional[Project]:
"""
Expand All @@ -103,11 +112,14 @@ def get_project_by_name(self, project_name: str) -> Optional[Project]:
:return: Project object containing the data of the project, if the project is
found on the server. Returns None if the project doesn't exist
"""
project_list = self.get_all_projects()
project = next(
project_list = self.get_all_projects(get_project_details=False)
project_entry = next(
(project for project in project_list if project.name == project_name), None
)
return project
if project_entry is not None:
return self._get_project_detail(project_entry)
else:
return None

def get_or_create_project(
self,
Expand Down Expand Up @@ -619,3 +631,20 @@ def _await_project_ready(
f"Project has not become ready within the specified timeout ({timeout} "
f"seconds)."
) from error

def _get_project_detail(self, project: Union[Project, str]) -> Project:
"""
Fetch the most recent project details from the Intel® Geti™ server

:param project: Name of the project or Project object representing the project
to get detailed information for.
:return: Updated Project object
"""
if isinstance(project, str):
project = self.get_project_by_name(project_name=project)
return project
else:
response = self.session.get_rest_response(
url=f"{self.base_url}projects/{project.id}", method="GET"
)
return ProjectRESTConverter.from_dict(response)
Loading