Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2220abc
Initial dirty version of v2 pull integration + porject info v2
MarcelGeo Dec 8, 2025
001c83d
Separate diff files from merge files + comments @wonder-sk
MarcelGeo Dec 9, 2025
68b84c1
Introduce:
MarcelGeo Dec 16, 2025
ae3e55c
Added return types fo new functions
MarcelGeo Dec 18, 2025
55d9e5a
Fix test test_mergin_project
MarcelGeo Dec 18, 2025
db7be6c
add optional download_path for pattern with diff files
MarcelGeo Dec 18, 2025
8e3f2ec
solve base file missing
MarcelGeo Dec 18, 2025
9552372
Handle unfinished pull
MarcelGeo Dec 18, 2025
fc90173
comments @varmar05
MarcelGeo Jan 16, 2026
411d3e1
fix files to merge renamig
MarcelGeo Jan 16, 2026
5e2eccc
fix download base files + import
MarcelGeo Jan 16, 2026
5891088
fix for is_gpgkg_open results
MarcelGeo Jan 19, 2026
9a18374
update tests for cases where geopackage is modified
MarcelGeo Jan 19, 2026
9c82771
Black 26.1.0 upgrades
MarcelGeo Jan 19, 2026
7a144b1
Merge remote-tracking branch 'origin/v2-pull-integration' into pull-i…
MarcelGeo Jan 19, 2026
ec500a5
fixed imports after merge
MarcelGeo Jan 19, 2026
7fb335f
pull actions tests
MarcelGeo Jan 19, 2026
93995ec
First comments resolving from a reviews
MarcelGeo Feb 12, 2026
3a1f47f
Update mergin/test/test_client_pull.py
MarcelGeo Feb 27, 2026
be1ffed
Update mergin/common.py
MarcelGeo Feb 27, 2026
337757f
Update mergin/merginproject.py
MarcelGeo Feb 27, 2026
d1585fb
Apply suggestions from code review
MarcelGeo Feb 27, 2026
c3dd5ec
Address comments @wonder-sk
MarcelGeo Feb 27, 2026
f6aea66
Fix arguments of pull changes
MarcelGeo Feb 27, 2026
e4afd04
Fix rest of tests
MarcelGeo Feb 27, 2026
a41258a
Fix renamed missing key
MarcelGeo Feb 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 105 additions & 5 deletions mergin/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
from enum import Enum
from typing import Optional, Type, Union

from .models import (
ProjectDelta,
ProjectDeltaItemDiff,
ProjectDeltaChange,
ProjectInfo,
ProjectFile,
ProjectWorkspace,
)

from .common import (
SYNC_ATTEMPT_WAIT,
SYNC_ATTEMPTS,
Expand Down Expand Up @@ -732,6 +741,89 @@ 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_info_v2(self, project_id: str, files_at_version=None) -> ProjectInfo:
"""
Fetch info about project.

:param project_id: Project's id
:type project_id: String
:param files_at_version: Version to track files at given version
:type files_at_version: String
"""
self.check_v2_project_info_support()

params = {}
if files_at_version:
params = {"files_at_version": files_at_version}
resp = self.get(f"/v2/projects/{project_id}", params)
resp_json = json.load(resp)
project_workspace = resp_json.get("workspace")
return ProjectInfo(
id=resp_json.get("id"),
name=resp_json.get("name"),
created_at=resp_json.get("created_at"),
updated_at=resp_json.get("updated_at"),
version=resp_json.get("version"),
public=resp_json.get("public"),
role=resp_json.get("role"),
size=resp_json.get("size"),
workspace=ProjectWorkspace(
id=project_workspace.get("id"),
name=project_workspace.get("name"),
),
files=[
ProjectFile(
checksum=f.get("checksum"),
mtime=f.get("mtime"),
path=f.get("path"),
size=f.get("size"),
)
for f in resp_json.get("files", [])
],
)

def get_project_delta(self, project_id: str, since: str, to: typing.Optional[str] = None) -> ProjectDelta:
"""
Fetch info about project delta since given version.

:param project_id: Project's id
:type project_id: String
:param since: Version to track history of files from
:type since: String (e.g. v1)
:param to: Optional version to track history of files to, if not given latest version is used
:type to: String (e.g. v2)
"""
# If it is not enabled on the server, raise error
if not self.server_features().get("v2_pull_enabled", False):
raise ClientError("Project delta is not supported by the server")

params = {"since": since}
if to:
params["to"] = to
resp = self.get(f"/v2/projects/{project_id}/delta", params)
resp_parsed = json.load(resp)
return ProjectDelta(
to_version=resp_parsed.get("to_version"),
changes=[
ProjectDeltaChange(
path=item["path"],
size=item.get("size"),
checksum=item.get("checksum"),
version=item.get("version"),
type=item.get("change"),
diffs=(
[
ProjectDeltaItemDiff(
id=diff.get("id"),
)
for diff in item.get("diffs", [])
]
),
)
for item in resp_parsed.get("items", [])
],
)

def paginated_project_versions(self, project_path, page, per_page=100, descending=False):
"""
Get records of project's versions (history) using calculated pagination.
Expand Down Expand Up @@ -822,11 +914,11 @@ def download_project(self, project_path, directory, version=None):
:param project_path: Project's full name (<namespace>/<name>)
:type project_path: String

:param version: Project version to download, e.g. v42
:type version: String

:param directory: Target directory
:type directory: String

:param version: Project version to download, e.g. v42
:type version: String
"""
job = download_project_async(self, project_path, directory, version)
download_project_wait(job)
Expand Down Expand Up @@ -1070,7 +1162,7 @@ def project_status(self, directory):
mp = MerginProject(directory)
server_info = self.project_info(mp.project_full_name(), since=mp.version())

pull_changes = mp.get_pull_changes(server_info["files"])
pull_changes = mp.get_pull_changes(server_info.get("files", []), server_info.get("version"))

push_changes = mp.get_push_changes()
push_changes_summary = mp.get_list_of_push_changes(push_changes)
Expand Down Expand Up @@ -1341,13 +1433,21 @@ def check_collaborators_members_support(self):
if not is_version_acceptable(self.server_version(), f"{min_version}"):
raise NotImplementedError(f"This needs server at version {min_version} or later")

def check_v2_project_info_support(self):
"""
Check if the server is compatible with v2 endpoint for project info
"""
min_version = "2025.8.2"
if not is_version_acceptable(self.server_version(), f"{min_version}"):
raise NotImplementedError(f"This needs server at version {min_version} or later")

def create_user(
self,
email: str,
password: str,
workspace_id: int,
workspace_role: Union[str, WorkspaceRole],
username: str = None,
username: Optional[str] = None,
notify_user: bool = False,
) -> dict:
"""
Expand Down
Loading
Loading