diff --git a/mergin/client.py b/mergin/client.py index 4cd7ef3..8c1750c 100644 --- a/mergin/client.py +++ b/mergin/client.py @@ -372,6 +372,17 @@ def workspace_service(self, workspace_id): return response + def workspace_usage(self, workspace_id): + """ + This Requests information about a workspace usage from /workspace/{id}/usage endpoint, + if such exists in self.url server. + + Returns response from server as JSON dict or None if endpoint is not found + """ + + resp = self.get(f"/v1/workspace/{workspace_id}/usage") + return json.load(resp) + def server_type(self): """ Returns the deployment type of the server @@ -700,7 +711,43 @@ def project_info(self, project_path_or_id, since=None, version=None): resp = self.get("/v1/project/{}".format(project_path_or_id), params) return json.load(resp) - def project_versions(self, project_path, since=None, to=None): + def paginated_project_versions(self, project_path, page, per_page=100, descending=False): + """ + Get records of project's versions (history) using calculated pagination. + wrapper around the /v1/project/versions/paginated/{} API end point + + :param project_path: Project's full name (/) + :type project_path: String | Int + :param page: page number + :type page: Int + :param per_page: number of results per page default 100 + :type per_page: Int + :param descending: order of sorting + :type descending: Bool + + :rtype: List[Dict], Int + """ + params = {"page": page, "per_page": per_page, "descending": descending} + resp = self.get("/v1/project/versions/paginated/{}".format(project_path), params) + resp_json = json.load(resp) + return resp_json["versions"], resp_json["count"] + + def project_versions_count(self, project_path): + """ + return the total count of versions + To note we fetch only one page and one item as we only need the "count" response + + :param project_path_or_id: Project's full name (/) or id + :type project_path_or_id: String + + :rtype: Int + """ + params = {"page": 1, "per_page": 1, "descending": False} + resp = self.get("/v1/project/versions/paginated/{}".format(project_path), params) + resp_json = json.load(resp) + return resp_json["count"] + + def project_versions(self, project_path, since=1, to=None): """ Get records of project's versions (history) in ascending order. If neither 'since' nor 'to' is specified it will return all versions. @@ -708,33 +755,40 @@ def project_versions(self, project_path, since=None, to=None): :param project_path: Project's full name (/) :type project_path: String :param since: Version to track project history from - :type since: String + :type since: String | Int :param to: Version to track project history to - :type to: String + :type to: String | Int :rtype: List[Dict] """ versions = [] per_page = 100 # server limit - num_since = int_version(since) if since else 1 - num_to = int_version(to) if to else None # we may not know yet + + if type(since) == str: + num_since = int_version(since) + else: + # keep the since parameter as is + num_since = since + + if type(to) == str: + num_to = int_version(to) + else: + # keep the to parameter as is + num_to = to + start_page = math.ceil(num_since / per_page) if not num_to: # let's get first page and count - params = {"page": start_page, "per_page": per_page, "descending": False} - resp = self.get("/v1/project/versions/paginated/{}".format(project_path), params) - resp_json = json.load(resp) - versions = resp_json["versions"] - num_to = resp_json["count"] + versions, num_to = self.paginated_project_versions(project_path, start_page, per_page) + latest_version = int_version(versions[-1]["name"]) if latest_version < num_to: versions += self.project_versions(project_path, f"v{latest_version+1}", f"v{num_to}") else: end_page = math.ceil(num_to / per_page) for page in range(start_page, end_page + 1): - params = {"page": page, "per_page": per_page, "descending": False} - resp = self.get("/v1/project/versions/paginated/{}".format(project_path), params) - versions += json.load(resp)["versions"] + page_versions, _ = self.paginated_project_versions(project_path, page, per_page) + versions += page_versions # filter out versions not within range filtered_versions = list(filter(lambda v: (num_since <= int_version(v["name"]) <= num_to), versions)) diff --git a/mergin/client_pull.py b/mergin/client_pull.py index 795cf2e..a46e6f9 100644 --- a/mergin/client_pull.py +++ b/mergin/client_pull.py @@ -687,6 +687,8 @@ def download_diffs_async(mc, project_directory, file_path, versions): fetch_files = [] for version in versions: + if version not in file_history["history"]: + continue # skip if this file was not modified at this version version_data = file_history["history"][version] if "diff" not in version_data: continue # skip if there is no diff in history diff --git a/mergin/test/test_client.py b/mergin/test/test_client.py index 6e35c6e..5ae3f3b 100644 --- a/mergin/test/test_client.py +++ b/mergin/test/test_client.py @@ -2013,6 +2013,14 @@ def test_project_versions_list(mc): assert versions[0]["name"] == "v2" assert versions[-1]["name"] == "v4" + versions_count = mc.project_versions_count(project) + assert versions_count == 5 + + versions, _ = mc.paginated_project_versions(project, page=1, descending=True) + assert len(versions) == 5 + assert versions[0]["name"] == "v5" + assert versions[-1]["name"] == "v1" + def test_report(mc): test_project = "test_report"