From 182514a9fe8923c9af68674e80dea9a0c32b3169 Mon Sep 17 00:00:00 2001 From: Johnny Sequeira Date: Sat, 31 Aug 2024 09:32:39 -0600 Subject: [PATCH 01/25] Adding modifications and fixing --- qfieldcloud_sdk/sdk.py | 168 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 155 insertions(+), 13 deletions(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 6759b74..cce9e6a 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -30,26 +30,64 @@ DEFAULT_PAGINATION_LIMIT = 20 +"""int: Defines the default limit for pagination, set to `20`.""" class FileTransferStatus(str, Enum): + """Represents the status of a file transfer. + + Attributes: + PENDING (str): The transfer is pending. + SUCCESS (str): The transfer was successful. + FAILED (str): The transfer failed. + """ + PENDING = "PENDING" SUCCESS = "SUCCESS" FAILED = "FAILED" class FileTransferType(Enum): + """Represents the type of file transfer. + + The PACKAGE transfer type is used only internally in QFieldCloud workers, so it should never be used by other API clients. + + Attributes: + PROJECT (str): Refers to a project file. + PACKAGE (str): Refers to a package Type. + """ + PROJECT = "project" PACKAGE = "package" class JobTypes(str, Enum): + """Represents the types of jobs that can be processed on QFieldCloud. + + Attributes: + PACKAGE (str): Refers to a packaging job. + APPLY_DELTAS (str): Refers to applying deltas (differences). + PROCESS_PROJECTFILE (str): Refers to processing a project file. + """ + PACKAGE = "package" APPLY_DELTAS = "delta_apply" PROCESS_PROJECTFILE = "process_projectfile" class ProjectCollaboratorRole(str, Enum): + """Defines roles for project collaborators. + + See project collaborator roles documentation: https://docs.qfield.org/reference/qfieldcloud/permissions/#roles_1 + + Attributes: + ADMIN (str): Administrator role. + MANAGER (str): Manager role. + EDITOR (str): Editor role. + REPORTER (str): Reporter role. + READER (str): Reader role. + """ + ADMIN = "admin" MANAGER = "manager" EDITOR = "editor" @@ -58,11 +96,32 @@ class ProjectCollaboratorRole(str, Enum): class OrganizationMemberRole(str, Enum): + """Defines roles for organization members. + + See organization member roles documentation: https://docs.qfield.org/reference/qfieldcloud/permissions/#roles_2 + + Attributes: + ADMIN (str): Administrator role. + MEMBER (str): Member role. + """ + ADMIN = "admin" MEMBER = "member" class CollaboratorModel(TypedDict): + """Represents the structure of a project collaborator in the QFieldCloud system. + + Attributes: + collaborator (str): The collaborator's identifier. + role (ProjectCollaboratorRole): The role of the collaborator. + project_id (str): The associated project identifier. + created_by (str): The user who created the collaborator entry. + updated_by (str): The user who last updated the collaborator entry. + created_at (datetime.datetime): The timestamp when the collaborator entry was created. + updated_at (datetime.datetime): The timestamp when the collaborator entry was last updated. + """ + collaborator: str role: ProjectCollaboratorRole project_id: str @@ -73,6 +132,15 @@ class CollaboratorModel(TypedDict): class OrganizationMemberModel(TypedDict): + """Represents the structure of an organization member in the QFieldCloud system. + + Attributes: + member (str): The member's identifier. + role (OrganizationMemberRole): The role of the member. + organization (str): The associated organization identifier. + is_public (bool): A boolean indicating if the membership is public. + """ + member: str role: OrganizationMemberRole organization: str @@ -85,29 +153,64 @@ class OrganizationMemberModel(TypedDict): class Pagination: + """The Pagination class allows for controlling and managing pagination of results within the QFieldCloud SDK. + + Attributes: + limit (Optional[int]): The maximum number of items to return. + offset (Optional[int]): The starting point from which to return items. + """ + limit = None offset = None def __init__( self, limit: Optional[int] = None, offset: Optional[int] = None ) -> None: + """Initializes the pagination settings. + + Args: + limit (Optional[int]): The maximum number of items to return. Defaults to None. + offset (Optional[int]): The starting point from which to return items. Defaults to None. + """ self.limit = limit self.offset = offset @property def is_empty(self): + """Checks if both limit and offset are None, indicating no pagination settings. + + Returns: + bool: True if both limit and offset are None, False otherwise. + """ return self.limit is None and self.offset is None class Client: + """The core component of the QFieldCloud SDK, providing methods for interacting with the QFieldCloud platform. + + This class handles authentication, project management, file management, and more. + + Attributes: + session (requests.Session): The session object to maintain connections. + url (str): The base URL for the QFieldCloud API. + token (str): The authentication token for API access. + verify_ssl (bool): Whether to verify SSL certificates. + """ + def __init__( self, url: str = None, verify_ssl: bool = None, token: str = None ) -> None: - """Prepares a new client. + """Initializes a new Client instance. - If the `url` is not provided, uses `QFIELDCLOUD_URL` from the environment. - If the `token` is not provided, uses `QFIELDCLOUD_TOKEN` from the environment. - `session` will be reused between requests if the SDK is run as a library. + The session is configured with retries for GET requests on specific 5xx HTTP status codes. + + Args: + url (Optional[str]): The base URL for the QFieldCloud API. Defaults to `QFIELDCLOUD_URL` environment variable if not provided. + verify_ssl (Optional[bool]): Whether to verify SSL certificates. Defaults to True if not specified. + token (Optional[str]): The authentication token for API access. Defaults to `QFIELDCLOUD_TOKEN` environment variable if not provided. + + Raises: + QfcException: If the `url` is not provided either directly or through the environment variable. """ self.session = requests.Session() # retries should be only on GET and only if error 5xx @@ -132,12 +235,19 @@ def __init__( "Cannot create a new QFieldCloud client without a url passed in the constructor or as environment variable QFIELDCLOUD_URL" ) - def login(self, username: str, password: str) -> Dict: - """Logins with the provided credentials. + def login(self, username: str, password: str) -> Dict[str, Any]: + """Logs in with the provided username and password. Args: - username: the username or the email used to register - password: the password associated with that username + username (str): The username or email used to register. + password (str): The password associated with the username. + + Returns: + Dict[str, Any]: Authentication token and additional metadata. + + Example: + client = sdk.Client(url="https://app.qfield.cloud/api/v1/") + client.login("ninjamaster", "secret_password123") """ resp = self._request( "POST", @@ -156,7 +266,11 @@ def login(self, username: str, password: str) -> Dict: return payload def logout(self) -> None: - """Logout from the current session.""" + """Logs out from the current session, invalidating the authentication token. + + Example: + client.logout() + """ resp = self._request("POST", "auth/logout") return resp.json() @@ -167,9 +281,14 @@ def list_projects( pagination: Pagination = Pagination(), **kwargs, ) -> List[Dict[str, Any]]: - """ - Returns a list of projects accessible to the current user, - their own and optionally the public ones. + """Returns a list of projects accessible to the current user, their own and optionally the public ones. + + Args: + include_public (Optional[bool]): Whether to include public projects in the list. Defaults to False. + pagination (Pagination): Pagination settings for the request. Defaults to an empty Pagination instance. + + Returns: + List[Dict[str, Any]]: A list of dictionaries containing project details. """ params = { "include-public": str(int(include_public)), # type: ignore @@ -183,6 +302,18 @@ def list_projects( def list_remote_files( self, project_id: str, skip_metadata: bool = True ) -> List[Dict[str, Any]]: + """Lists the files available in the specified project. + + Args: + project_id (str): The ID of the project to list files for. + skip_metadata (bool): Whether to skip fetching metadata for the files. Defaults to True. + + Returns: + List[Dict[str, Any]]: A list of file details. + + Example: + client.list_remote_files("project_id", True) + """ params = {} if skip_metadata: @@ -201,7 +332,18 @@ def create_project( owner: str = None, description: str = "", is_public: bool = False, - ) -> Dict: + ) -> Dict[str, Any]: + """Creates a new project in QFieldCloud. + + Args: + name (str): The name of the new project. + owner (Optional[str]): The owner of the project. Defaults to None. + description (Optional[str]): A description of the project. Defaults to an empty string. + is_public (Optional[bool]): Whether the project should be public. Defaults to False. + + Returns: + Dict[str, Any]: A dictionary containing the details of the created project. + """ resp = self._request( "POST", "projects", From f315962865797b2b5d0f64f3cfd311403ce30ae5 Mon Sep 17 00:00:00 2001 From: Ivan Ivanov Date: Tue, 3 Sep 2024 12:54:26 +0300 Subject: [PATCH 02/25] Apply suggestions from code review Co-authored-by: Mathieu Pellerin --- qfieldcloud_sdk/sdk.py | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index cce9e6a..be9fe08 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -47,7 +47,7 @@ class FileTransferStatus(str, Enum): FAILED = "FAILED" -class FileTransferType(Enum): +class FileTransferType(str, Enum): """Represents the type of file transfer. The PACKAGE transfer type is used only internally in QFieldCloud workers, so it should never be used by other API clients. @@ -197,17 +197,28 @@ class Client: verify_ssl (bool): Whether to verify SSL certificates. """ + session: requests.Session + + url: str + + token:str + + veryfy_ssl: bool + def __init__( - self, url: str = None, verify_ssl: bool = None, token: str = None + self, + url: str = "", + verify_ssl: bool = True, + token: str = "", ) -> None: """Initializes a new Client instance. The session is configured with retries for GET requests on specific 5xx HTTP status codes. Args: - url (Optional[str]): The base URL for the QFieldCloud API. Defaults to `QFIELDCLOUD_URL` environment variable if not provided. - verify_ssl (Optional[bool]): Whether to verify SSL certificates. Defaults to True if not specified. - token (Optional[str]): The authentication token for API access. Defaults to `QFIELDCLOUD_TOKEN` environment variable if not provided. + url (str, optional): The base URL for the QFieldCloud API. Defaults to `QFIELDCLOUD_URL` environment variable if empty. + verify_ssl (bool, optional): Whether to verify SSL certificates. Defaults to True. + token (str, optional): The authentication token for API access. Defaults to `QFIELDCLOUD_TOKEN` environment variable if empty. Raises: QfcException: If the `url` is not provided either directly or through the environment variable. @@ -243,7 +254,7 @@ def login(self, username: str, password: str) -> Dict[str, Any]: password (str): The password associated with the username. Returns: - Dict[str, Any]: Authentication token and additional metadata. + dict[str, Any]: Authentication token and additional metadata. Example: client = sdk.Client(url="https://app.qfield.cloud/api/v1/") @@ -284,11 +295,11 @@ def list_projects( """Returns a list of projects accessible to the current user, their own and optionally the public ones. Args: - include_public (Optional[bool]): Whether to include public projects in the list. Defaults to False. - pagination (Pagination): Pagination settings for the request. Defaults to an empty Pagination instance. + include_public (bool, optional): Whether to include public projects in the list. Defaults to False. + pagination (Pagination, optional): Pagination settings for the request. Defaults to an empty Pagination instance. Returns: - List[Dict[str, Any]]: A list of dictionaries containing project details. + list[Dict[str, Any]]: A list of dictionaries containing project details. """ params = { "include-public": str(int(include_public)), # type: ignore @@ -337,12 +348,12 @@ def create_project( Args: name (str): The name of the new project. - owner (Optional[str]): The owner of the project. Defaults to None. - description (Optional[str]): A description of the project. Defaults to an empty string. - is_public (Optional[bool]): Whether the project should be public. Defaults to False. + owner (str, optional): The owner of the project. Defaults to None. + description (str, optional): A description of the project. Defaults to an empty string. + is_public (bool, optional): Whether the project should be public. Defaults to False. Returns: - Dict[str, Any]: A dictionary containing the details of the created project. + dict[str, Any]: A dictionary containing the details of the created project. """ resp = self._request( "POST", From d2c204c52e6379dcdbd09e69428a805915211a2c Mon Sep 17 00:00:00 2001 From: Ivan Ivanov Date: Tue, 3 Sep 2024 12:57:29 +0300 Subject: [PATCH 03/25] Apply suggestions from code review --- qfieldcloud_sdk/sdk.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index be9fe08..9217c77 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -156,8 +156,8 @@ class Pagination: """The Pagination class allows for controlling and managing pagination of results within the QFieldCloud SDK. Attributes: - limit (Optional[int]): The maximum number of items to return. - offset (Optional[int]): The starting point from which to return items. + limit (int | None): The maximum number of items to return. + offset (int | None): The starting point from which to return items. """ limit = None @@ -169,8 +169,8 @@ def __init__( """Initializes the pagination settings. Args: - limit (Optional[int]): The maximum number of items to return. Defaults to None. - offset (Optional[int]): The starting point from which to return items. Defaults to None. + limit (int | None, optional): The maximum number of items to return. Defaults to None. + offset (int | None, optional): The starting point from which to return items. Defaults to None. """ self.limit = limit self.offset = offset @@ -348,7 +348,7 @@ def create_project( Args: name (str): The name of the new project. - owner (str, optional): The owner of the project. Defaults to None. + owner (str | None, optional): The owner of the project. When None, the project will be owned by the currently logged-in user. Defaults to None. description (str, optional): A description of the project. Defaults to an empty string. is_public (bool, optional): Whether the project should be public. Defaults to False. From 42126f23fa551e29891f5392713e015ac3be30dc Mon Sep 17 00:00:00 2001 From: Johnny Sequeira Date: Tue, 3 Sep 2024 10:21:17 -0600 Subject: [PATCH 04/25] Fixing and adding more docstrings --- qfieldcloud_sdk/sdk.py | 88 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 11 deletions(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 9217c77..1da7000 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -201,7 +201,7 @@ class Client: url: str - token:str + token: str veryfy_ssl: bool @@ -288,15 +288,15 @@ def logout(self) -> None: def list_projects( self, - include_public: Optional[bool] = False, + include_public: bool = False, pagination: Pagination = Pagination(), **kwargs, ) -> List[Dict[str, Any]]: """Returns a list of projects accessible to the current user, their own and optionally the public ones. Args: - include_public (bool, optional): Whether to include public projects in the list. Defaults to False. - pagination (Pagination, optional): Pagination settings for the request. Defaults to an empty Pagination instance. + include_public (bool): Whether to include public projects in the list. Defaults to False. + pagination (Pagination): Pagination settings for the request. Defaults to an empty Pagination instance. Returns: list[Dict[str, Any]]: A list of dictionaries containing project details. @@ -369,6 +369,14 @@ def create_project( return resp.json() def delete_project(self, project_id: str): + """Delete a QFieldCloud project. + + Args: + project_id (str): The ID of the project to delete. + + Returns: + requests.Response: The response object from the delete request. + """ resp = self._request("DELETE", f"projects/{project_id}") return resp @@ -384,7 +392,21 @@ def upload_files( force: bool = False, job_id: str = "", ) -> List[Dict]: - """Upload files to a QFieldCloud project""" + """Upload files to a QFieldCloud project. + + Args: + project_id (str): The ID of the project to upload files to. + upload_type (FileTransferType): The type of file transfer (PROJECT or PACKAGE). + project_path (str): The local directory containing the files to upload. + filter_glob (str): A glob pattern to filter which files to upload. + throw_on_error (bool, optional): Whether to raise an error if a file fails to upload. Defaults to False. + show_progress (bool, optional): Whether to display a progress bar during upload. Defaults to False. + force (bool, optional): Whether to force upload all files, even if they exist remotely. Defaults to False. + job_id (str, optional): The job ID, required if `upload_type` is PACKAGE. Defaults to an empty string. + + Returns: + List[Dict]: A list of dictionaries with information about the uploaded files. + """ if not filter_glob: filter_glob = "*" @@ -451,6 +473,19 @@ def upload_file( show_progress: bool, job_id: str = "", ) -> requests.Response: + """Upload a single file to a QFieldCloud project. + + Args: + project_id (str): The ID of the project to upload the file to. + upload_type (FileTransferType): The type of file transfer (PROJECT or PACKAGE). + local_filename (Path): The path to the local file to upload. + remote_filename (Path): The path where the file should be stored remotely. + show_progress (bool): Whether to display a progress bar during upload. + job_id (str, optional): The job ID, required if `upload_type` is PACKAGE. Defaults to an empty string. + + Returns: + requests.Response: The response object from the upload request. + """ with open(local_filename, "rb") as local_file: upload_file = local_file if show_progress: @@ -502,8 +537,9 @@ def download_project( local_dir: destination directory where the files will be downloaded filter_glob: if specified, download only the files which match the glob, otherwise download all force_download (bool, optional): Download file even if it already exists locally. Defaults to False. + Returns: + List[Dict]: A list of dictionaries with information about the downloaded files. """ - files = self.list_remote_files(project_id) return self.download_files( @@ -523,8 +559,15 @@ def list_jobs( job_type: JobTypes = None, pagination: Pagination = Pagination(), ) -> List[Dict[str, Any]]: - """ - Returns a paginated lists of jobs accessible to the user. + """Return a paginated list of jobs accessible to the user. + + Args: + project_id (str): The ID of the project. + job_type (JobTypes, optional): The type of job to filter by. Defaults to None. + pagination (Pagination, optional): Pagination settings. Defaults to a new Pagination object. + + Returns: + List[Dict[str, Any]]: A list of dictionaries representing the jobs. """ payload = self._request_json( "GET", @@ -540,8 +583,16 @@ def list_jobs( def job_trigger( self, project_id: str, job_type: JobTypes, force: bool = False ) -> Dict[str, Any]: - """Initiate a new project job.""" + """Initiate a new project job. + Args: + project_id (str): The ID of the project. + job_type (JobTypes): The type of job to trigger. + force (bool, optional): Whether to force the job execution. Defaults to False. + + Returns: + Dict[str, Any]: A dictionary containing the job information. + """ resp = self._request( "POST", "jobs/", @@ -555,8 +606,14 @@ def job_trigger( return resp.json() def job_status(self, job_id: str) -> Dict[str, Any]: - """Get job status.""" + """Get the status of a job. + + Args: + job_id (str): The ID of the job. + Returns: + Dict[str, Any]: A dictionary containing the job status. + """ resp = self._request("GET", f"jobs/{job_id}") return resp.json() @@ -649,7 +706,14 @@ def delete_files( return glob_results def package_latest(self, project_id: str) -> Dict[str, Any]: - """Check project packaging status.""" + """Check the latest packaging status of a project. + + Args: + project_id (str): The ID of the project. + + Returns: + Dict[str, Any]: A dictionary containing the latest packaging status. + """ resp = self._request("GET", f"packages/{project_id}/latest/") return resp.json() @@ -670,6 +734,8 @@ def package_download( local_dir: destination directory where the files will be downloaded filter_glob: if specified, download only packaged files which match the glob, otherwise download all force_download (bool, optional): Download file even if it already exists locally. Defaults to False. + Returns: + List[Dict]: A list of dictionaries with information about the downloaded files. """ project_status = self.package_latest(project_id) From aeef2cada08dd1fb40e91ad1d7a123c4868b6328 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:39:17 -0600 Subject: [PATCH 05/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 1da7000..bb9a9e8 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -295,11 +295,11 @@ def list_projects( """Returns a list of projects accessible to the current user, their own and optionally the public ones. Args: - include_public (bool): Whether to include public projects in the list. Defaults to False. - pagination (Pagination): Pagination settings for the request. Defaults to an empty Pagination instance. + include_public (bool, optional): Whether to include public projects in the list. Defaults to False. + pagination (Pagination, optional): Pagination settings for the request. Defaults to an empty Pagination instance. Returns: - list[Dict[str, Any]]: A list of dictionaries containing project details. + list[dict[str, Any]]: A list of dictionaries containing project details. """ params = { "include-public": str(int(include_public)), # type: ignore From a18a377aa0ce6b45308a9a8fbe16b42d27826064 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:39:58 -0600 Subject: [PATCH 06/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index bb9a9e8..e4770b5 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -313,14 +313,14 @@ def list_projects( def list_remote_files( self, project_id: str, skip_metadata: bool = True ) -> List[Dict[str, Any]]: - """Lists the files available in the specified project. + """List project files. Args: - project_id (str): The ID of the project to list files for. - skip_metadata (bool): Whether to skip fetching metadata for the files. Defaults to True. + project_id (str): Project ID. + skip_metadata (bool, optional): Whether to skip fetching metadata for the files. Defaults to True. Returns: - List[Dict[str, Any]]: A list of file details. + list[dict[str, Any]]: A list of file details. Example: client.list_remote_files("project_id", True) From 9a270f8920cecb8a22d4606c97814154966559c2 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:40:24 -0600 Subject: [PATCH 07/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index e4770b5..6362906 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -344,7 +344,7 @@ def create_project( description: str = "", is_public: bool = False, ) -> Dict[str, Any]: - """Creates a new project in QFieldCloud. + """Create a new project. Args: name (str): The name of the new project. From 61110258749e021c5a5a843100460b707339e8c6 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:40:46 -0600 Subject: [PATCH 08/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 6362906..9182a69 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -369,7 +369,7 @@ def create_project( return resp.json() def delete_project(self, project_id: str): - """Delete a QFieldCloud project. + """Delete a project. Args: project_id (str): The ID of the project to delete. From 379068720f076ee263947401148b82b96482f387 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:41:13 -0600 Subject: [PATCH 09/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 9182a69..8d6bab3 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -372,7 +372,7 @@ def delete_project(self, project_id: str): """Delete a project. Args: - project_id (str): The ID of the project to delete. + project_id (str): Project ID. Returns: requests.Response: The response object from the delete request. From 2caeba56f53bd873b40ddc0d81448437c850bfa4 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:41:59 -0600 Subject: [PATCH 10/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 8d6bab3..49725e7 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -395,7 +395,7 @@ def upload_files( """Upload files to a QFieldCloud project. Args: - project_id (str): The ID of the project to upload files to. + project_id (str): Project ID. upload_type (FileTransferType): The type of file transfer (PROJECT or PACKAGE). project_path (str): The local directory containing the files to upload. filter_glob (str): A glob pattern to filter which files to upload. From cdba47800962abd83b0799c570757dc93f882c18 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:42:22 -0600 Subject: [PATCH 11/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 49725e7..168e94e 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -405,7 +405,7 @@ def upload_files( job_id (str, optional): The job ID, required if `upload_type` is PACKAGE. Defaults to an empty string. Returns: - List[Dict]: A list of dictionaries with information about the uploaded files. + list[dict]: A list of dictionaries with information about the uploaded files. """ if not filter_glob: filter_glob = "*" From 4d2dbf92134a3f71882209aefdc1af79ad2dcf84 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:44:17 -0600 Subject: [PATCH 12/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 168e94e..5cd1815 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -473,7 +473,7 @@ def upload_file( show_progress: bool, job_id: str = "", ) -> requests.Response: - """Upload a single file to a QFieldCloud project. + """Upload a single file to a project. Args: project_id (str): The ID of the project to upload the file to. From bf1bd2498903c04320d9a4cca4a4106441f7dfb6 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:44:35 -0600 Subject: [PATCH 13/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 5cd1815..172efa9 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -477,7 +477,7 @@ def upload_file( Args: project_id (str): The ID of the project to upload the file to. - upload_type (FileTransferType): The type of file transfer (PROJECT or PACKAGE). + upload_type (FileTransferType): The type of file transfer. local_filename (Path): The path to the local file to upload. remote_filename (Path): The path where the file should be stored remotely. show_progress (bool): Whether to display a progress bar during upload. From 13fdb04c783beb2a25d1766000acf342defd095b Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:44:59 -0600 Subject: [PATCH 14/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 172efa9..519a1ca 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -538,7 +538,7 @@ def download_project( filter_glob: if specified, download only the files which match the glob, otherwise download all force_download (bool, optional): Download file even if it already exists locally. Defaults to False. Returns: - List[Dict]: A list of dictionaries with information about the downloaded files. + list[dict]: A list of dictionaries with information about the downloaded files. """ files = self.list_remote_files(project_id) From f534b1f499111725590cc1c864640d33567577d8 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:45:20 -0600 Subject: [PATCH 15/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 519a1ca..8dca942 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -567,7 +567,7 @@ def list_jobs( pagination (Pagination, optional): Pagination settings. Defaults to a new Pagination object. Returns: - List[Dict[str, Any]]: A list of dictionaries representing the jobs. + list[dict[str, Any]]: A list of dictionaries representing the jobs. """ payload = self._request_json( "GET", From cde554fc7ab6ff4efd6113df81a94ee696d0a6bd Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:45:41 -0600 Subject: [PATCH 16/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 8dca942..ec3520e 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -559,7 +559,7 @@ def list_jobs( job_type: JobTypes = None, pagination: Pagination = Pagination(), ) -> List[Dict[str, Any]]: - """Return a paginated list of jobs accessible to the user. + """List project jobs. Args: project_id (str): The ID of the project. From bdb90960e934b35a04e90ec053fed23ecfa9789b Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:45:58 -0600 Subject: [PATCH 17/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index ec3520e..4b02843 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -583,7 +583,7 @@ def list_jobs( def job_trigger( self, project_id: str, job_type: JobTypes, force: bool = False ) -> Dict[str, Any]: - """Initiate a new project job. + """Trigger a new job for given project. Args: project_id (str): The ID of the project. From be7994d57e4f5f8b41984f92f5b55110ff77dc42 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:46:10 -0600 Subject: [PATCH 18/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 4b02843..8d3d405 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -591,7 +591,7 @@ def job_trigger( force (bool, optional): Whether to force the job execution. Defaults to False. Returns: - Dict[str, Any]: A dictionary containing the job information. + dict[str, Any]: A dictionary containing the job information. """ resp = self._request( "POST", From 72ee76743659f9f6f6626c698c1639d078b064ca Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:46:31 -0600 Subject: [PATCH 19/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 8d3d405..0502589 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -612,7 +612,7 @@ def job_status(self, job_id: str) -> Dict[str, Any]: job_id (str): The ID of the job. Returns: - Dict[str, Any]: A dictionary containing the job status. + dict[str, Any]: A dictionary containing the job status. """ resp = self._request("GET", f"jobs/{job_id}") From a03928c215fea4c089aa83c072badce2af99d686 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:46:40 -0600 Subject: [PATCH 20/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 0502589..efddde3 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -735,7 +735,7 @@ def package_download( filter_glob: if specified, download only packaged files which match the glob, otherwise download all force_download (bool, optional): Download file even if it already exists locally. Defaults to False. Returns: - List[Dict]: A list of dictionaries with information about the downloaded files. + list[dict[str, Any]]: A list of dictionaries with information about the downloaded files. """ project_status = self.package_latest(project_id) From 7199e3d833b52af8b56288bb24f5ff4a7f24e7a5 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:46:50 -0600 Subject: [PATCH 21/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index efddde3..4cccbed 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -712,7 +712,7 @@ def package_latest(self, project_id: str) -> Dict[str, Any]: project_id (str): The ID of the project. Returns: - Dict[str, Any]: A dictionary containing the latest packaging status. + dict[str, Any]: A dictionary containing the latest packaging status. """ resp = self._request("GET", f"packages/{project_id}/latest/") From e450a20214559e7fff0b4dbefc53dabdd19b80e1 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:47:03 -0600 Subject: [PATCH 22/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 4cccbed..15ae43a 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -292,7 +292,7 @@ def list_projects( pagination: Pagination = Pagination(), **kwargs, ) -> List[Dict[str, Any]]: - """Returns a list of projects accessible to the current user, their own and optionally the public ones. + """List projects accessible by the current user. Optionally include all public projects. Args: include_public (bool, optional): Whether to include public projects in the list. Defaults to False. From 99bdbee4ef0da98013bcb84592391786fc3c115f Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:47:25 -0600 Subject: [PATCH 23/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 15ae43a..b0be252 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -211,7 +211,7 @@ def __init__( verify_ssl: bool = True, token: str = "", ) -> None: - """Initializes a new Client instance. + """Initialize a new SDK Client instance. The session is configured with retries for GET requests on specific 5xx HTTP status codes. From 66338f31747bd09a7ffbfa9f1ad4bf0b94c00435 Mon Sep 17 00:00:00 2001 From: Johnny <77129293+SeqLaz@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:47:56 -0600 Subject: [PATCH 24/25] Update qfieldcloud_sdk/sdk.py Co-authored-by: Ivan Ivanov --- qfieldcloud_sdk/sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index b0be252..591d751 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -177,7 +177,7 @@ def __init__( @property def is_empty(self): - """Checks if both limit and offset are None, indicating no pagination settings. + """Whether both limit and offset are None, indicating no pagination settings. Returns: bool: True if both limit and offset are None, False otherwise. From db5b090d6b4691636d51cbedabe9d044d8201e12 Mon Sep 17 00:00:00 2001 From: Johnny Sequeira Date: Tue, 3 Sep 2024 16:35:50 -0600 Subject: [PATCH 25/25] Updating list and dic --- qfieldcloud_sdk/sdk.py | 43 ++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 591d751..52f34d0 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -476,7 +476,7 @@ def upload_file( """Upload a single file to a project. Args: - project_id (str): The ID of the project to upload the file to. + project_id (str): Project ID. upload_type (FileTransferType): The type of file transfer. local_filename (Path): The path to the local file to upload. remote_filename (Path): The path where the file should be stored remotely. @@ -533,10 +533,11 @@ def download_project( """Download the specified project files into the destination dir. Args: - project_id: id of the project to be downloaded + project_id: Project ID. local_dir: destination directory where the files will be downloaded filter_glob: if specified, download only the files which match the glob, otherwise download all force_download (bool, optional): Download file even if it already exists locally. Defaults to False. + Returns: list[dict]: A list of dictionaries with information about the downloaded files. """ @@ -562,7 +563,7 @@ def list_jobs( """List project jobs. Args: - project_id (str): The ID of the project. + project_id (str): Project ID. job_type (JobTypes, optional): The type of job to filter by. Defaults to None. pagination (Pagination, optional): Pagination settings. Defaults to a new Pagination object. @@ -586,7 +587,7 @@ def job_trigger( """Trigger a new job for given project. Args: - project_id (str): The ID of the project. + project_id (str): Project ID. job_type (JobTypes): The type of job to trigger. force (bool, optional): Whether to force the job execution. Defaults to False. @@ -628,8 +629,8 @@ def delete_files( """Delete project files. Args: - project_id (str): Project id - glob_patterns (List[str]): Delete only files matching one the glob patterns. + project_id (str): Project ID. + glob_patterns (list[str]): Delete only files matching one the glob patterns. throw_on_error (bool, optional): Throw if delete error occurres. Defaults to False. finished_cb (Callable, optional): Deprecated. Defaults to None. @@ -637,7 +638,7 @@ def delete_files( QFieldCloudException: if throw_on_error is True, throw an error if a download request fails. Returns: - Dict[str, Dict[str, Any]]: Deleted files by glob pattern. + dict[str, dict[str, Any]]: Deleted files by glob pattern. """ project_files = self.list_remote_files(project_id) glob_results = {} @@ -709,7 +710,7 @@ def package_latest(self, project_id: str) -> Dict[str, Any]: """Check the latest packaging status of a project. Args: - project_id (str): The ID of the project. + project_id (str): Project ID. Returns: dict[str, Any]: A dictionary containing the latest packaging status. @@ -730,10 +731,11 @@ def package_download( """Download the specified project packaged files into the destination dir. Args: - project_id: id of the project to be downloaded + project_id: Project ID. local_dir: destination directory where the files will be downloaded filter_glob: if specified, download only packaged files which match the glob, otherwise download all force_download (bool, optional): Download file even if it already exists locally. Defaults to False. + Returns: list[dict[str, Any]]: A list of dictionaries with information about the downloaded files. """ @@ -772,18 +774,19 @@ def download_files( Args: files (List[Dict]): A list of file dicts, specifying which files to download. - project_id (str): Project id + project_id (str): Project ID. download_type (FileTransferType): File transfer type which specifies what should be the download url. local_dir (str): Local destination directory filter_glob (str, optional): Download only files matching the glob pattern. If None download all. Defaults to None. throw_on_error (bool, optional): Throw if download error occurres. Defaults to False. show_progress (bool, optional): Show progress bar in the console. Defaults to False. force_download (bool, optional): Download file even if it already exists locally. Defaults to False. + Raises: QFieldCloudException: if throw_on_error is True, throw an error if a download request fails. Returns: - List[Dict]: A list of file dicts. + list[dict]: A list of file dicts. """ if not filter_glob: filter_glob = "*" @@ -840,7 +843,7 @@ def download_file( """Download a single project file. Args: - project_id (str): Project id + project_id (str): Project ID. download_type (FileTransferType): File transfer type which specifies what should be the download URL local_filename (Path): Local filename remote_filename (Path): Remote filename @@ -939,10 +942,10 @@ def get_project_collaborators(self, project_id: str) -> List[CollaboratorModel]: """Gets a list of project collaborators. Args: - project_id (str): project UUID + project_id (str): Project ID. Returns: - List[CollaboratorModel]: the list of collaborators for that project + list[CollaboratorModel]: the list of collaborators for that project """ collaborators = cast( List[CollaboratorModel], @@ -957,7 +960,7 @@ def add_project_collaborator( """Adds a project collaborator. Args: - project_id (str): project UUID + project_id (str): Project ID. username (str): username of the collaborator to be added role (ProjectCollaboratorRole): the role of the collaborator. One of: `reader`, `reporter`, `editor`, `manager` or `admin` @@ -982,7 +985,7 @@ def remove_project_collaborators(self, project_id: str, username: str) -> None: """Removes a collaborator from a project. Args: - project_id (str): project UUID + project_id (str): Project ID. username (str): the username of the collaborator to be removed """ self._request("DELETE", f"/collaborators/{project_id}/{username}") @@ -993,7 +996,7 @@ def patch_project_collaborators( """Change an already existing collaborator Args: - project_id (str): project UUID + project_id (str): Project ID. username (str): the username of the collaborator to be patched role (ProjectCollaboratorRole): the new role of the collaborator @@ -1022,7 +1025,7 @@ def get_organization_members( organization (str): organization username Returns: - List[OrganizationMemberModel]: the list of members for that organization + list[OrganizationMemberModel]: the list of members for that organization """ members = cast( List[OrganizationMemberModel], @@ -1067,7 +1070,7 @@ def remove_organization_members(self, project_id: str, username: str) -> None: """Removes a member from a project. Args: - project_id (str): project UUID + project_id (str): Project ID. username (str): the username of the member to be removed """ self._request("DELETE", f"/members/{project_id}/{username}") @@ -1078,7 +1081,7 @@ def patch_organization_members( """Change an already existing member Args: - project_id (str): project UUID + project_id (str): Project ID. username (str): the username of the member to be patched role (OrganizationMemberRole): the new role of the member