Skip to content

Commit ed47d58

Browse files
committed
Make ChnagesHandler cleaner
1 parent 87f072e commit ed47d58

3 files changed

Lines changed: 52 additions & 45 deletions

File tree

mergin/client_push.py

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from .common import UPLOAD_CHUNK_SIZE, ClientError
2121
from .merginproject import MerginProject
22-
from .editor import filter_changes
22+
from .editor import is_editor_enabled, _apply_editor_filters
2323
from .utils import is_qgis_file, is_versioned_file
2424

2525

@@ -84,7 +84,7 @@ def upload_blocking(self, mc, mp):
8484
raise ClientError("Mismatch between uploaded file chunk {} and local one".format(self.chunk_id))
8585

8686

87-
class UploadChangesHandler:
87+
class ChangesHandler:
8888
"""
8989
Handles preparation of file changes to be uploaded to the server.
9090
@@ -95,49 +95,71 @@ class UploadChangesHandler:
9595
- Generating upload-ready change groups for asynchronous job creation.
9696
"""
9797

98-
def __init__(self, mp, client, project_info):
99-
self.mp = mp
98+
def __init__(self, client, project_info, changes):
10099
self.client = client
101100
self.project_info = project_info
102-
self._raw_changes = mp.get_push_changes()
103-
self._filtered_changes = filter_changes(client, project_info, self._raw_changes)
101+
self._raw_changes = changes
104102

105103
@staticmethod
106104
def is_blocking_file(file):
107105
return is_qgis_file(file["path"]) or is_versioned_file(file["path"])
108106

109-
def split_by_type(self) -> List[Dict[str, List[dict]]]:
107+
def _filter_changes(self, changes: Dict[str, List[dict]]) -> Dict[str, List[dict]]:
108+
"""
109+
Filters the given changes dictionary based on the editor's enabled state.
110+
111+
If the editor is not enabled, the changes dictionary is returned as-is. Otherwise, the changes are passed through the `_apply_editor_filters` method to apply any configured filters.
112+
113+
Args:
114+
changes (dict[str, list[dict]]): A dictionary mapping file paths to lists of change dictionaries.
115+
116+
Returns:
117+
dict[str, list[dict]]: The filtered changes dictionary.
118+
"""
119+
if not is_editor_enabled(self.client, self.project_info):
120+
return changes
121+
return _apply_editor_filters(changes)
122+
123+
def _split_by_type(self, changes: Dict[str, List[dict]]) -> List[Dict[str, List[dict]]]:
110124
"""
111125
Split raw filtered changes into two batches:
112126
1. Blocking: updated/removed and added files that are blocking
113127
2. Non-blocking: added files that are not blocking
114128
115-
Returns a list of dicts each with keys:
116-
- added, updated, removed, blocking
129+
Adds blocking key with a boolean value for each group
117130
"""
118-
blocking_group = {"added": [], "updated": [], "removed": [], "blocking": True}
119-
non_blocking_group = {"added": [], "updated": [], "removed": [], "blocking": False}
131+
blocking_changes = {"added": [], "updated": [], "removed": [], "blocking": True}
132+
non_blocking_changes = {"added": [], "updated": [], "removed": [], "blocking": False}
120133

121-
for f in self._filtered_changes.get("added", []):
134+
for f in changes.get("added", []):
122135
if self.is_blocking_file(f):
123-
blocking_group["added"].append(f)
136+
blocking_changes["added"].append(f)
124137
else:
125-
non_blocking_group["added"].append(f)
138+
non_blocking_changes["added"].append(f)
126139

127-
for f in self._filtered_changes.get("updated", []):
128-
blocking_group["updated"].append(f)
140+
for f in changes.get("updated", []):
141+
blocking_changes["updated"].append(f)
129142

130-
for f in self._filtered_changes.get("removed", []):
131-
blocking_group["removed"].append(f)
143+
for f in changes.get("removed", []):
144+
blocking_changes["removed"].append(f)
132145

133146
result = []
134-
if any(blocking_group[k] for k in ("added", "updated", "removed")):
135-
result.append(blocking_group)
136-
if any(non_blocking_group["added"]):
137-
result.append(non_blocking_group)
147+
if any(blocking_changes[k] for k in ("added", "updated", "removed")):
148+
result.append(blocking_changes)
149+
if any(non_blocking_changes["added"]):
150+
result.append(non_blocking_changes)
138151

139152
return result
140153

154+
def split(self) -> List[Dict[str, List[dict]]]:
155+
"""
156+
Applies all configured internal filters and returns a list of change ready to be uploaded.
157+
"""
158+
changes = self._filter_changes(self._raw_changes)
159+
changes = self._split_by_type(changes)
160+
# TODO: apply limits; changes = self._limit_by_file_count(changes)
161+
return changes
162+
141163

142164
def push_project_async(mc, directory) -> Optional[List[UploadJob]]:
143165
"""Starts push of a project and returns pending upload jobs"""
@@ -177,13 +199,14 @@ def push_project_async(mc, directory) -> Optional[List[UploadJob]]:
177199
+ f"\n\nLocal version: {local_version}\nServer version: {server_version}"
178200
)
179201

180-
changes_handler = UploadChangesHandler(mp, mc, project_info)
181-
changes_groups = changes_handler.split_by_type()
202+
changes = mp.get_push_changes()
203+
changes_handler = ChangesHandler(mc, project_info, changes)
204+
changes_list = changes_handler.split()
182205

183206
tmp_dir = tempfile.TemporaryDirectory(prefix="python-api-client-")
184207
jobs = []
185208

186-
for changes in changes_groups:
209+
for changes in changes_list:
187210
mp.log.debug("push changes:\n" + pprint.pformat(changes))
188211

189212
# If there are any versioned files (aka .gpkg) that are not updated through a diff,

mergin/editor.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,6 @@ def _apply_editor_filters(changes: Dict[str, List[dict]]) -> Dict[str, List[dict
4040
return changes
4141

4242

43-
def filter_changes(mc, project_info: dict, changes: Dict[str, List[dict]]) -> Dict[str, List[dict]]:
44-
"""
45-
Filters the given changes dictionary based on the editor's enabled state.
46-
47-
If the editor is not enabled, the changes dictionary is returned as-is. Otherwise, the changes are passed through the `_apply_editor_filters` method to apply any configured filters.
48-
49-
Args:
50-
changes (dict[str, list[dict]]): A dictionary mapping file paths to lists of change dictionaries.
51-
52-
Returns:
53-
dict[str, list[dict]]: The filtered changes dictionary.
54-
"""
55-
if not is_editor_enabled(mc, project_info):
56-
return changes
57-
return _apply_editor_filters(changes)
58-
59-
6043
def prevent_conflicted_copy(path: str, mc, project_info: dict) -> bool:
6144
"""
6245
Decides whether a file path should be blocked from creating a conflicted copy.

mergin/test/test_client.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
TokenError,
2222
ServerType,
2323
)
24-
from ..client_push import push_project_async, push_project_cancel
24+
from ..client_push import push_project_async, push_project_cancel, ChangesHandler
2525
from ..client_pull import (
2626
download_project_async,
2727
download_project_wait,
@@ -38,7 +38,7 @@
3838
)
3939
from ..merginproject import pygeodiff
4040
from ..report import create_report
41-
from ..editor import EDITOR_ROLE_NAME, filter_changes, is_editor_enabled
41+
from ..editor import EDITOR_ROLE_NAME, is_editor_enabled
4242
from ..common import ErrorCode, WorkspaceRole, ProjectRole
4343

4444
SERVER_URL = os.environ.get("TEST_MERGIN_URL")
@@ -2593,7 +2593,8 @@ def test_editor(mc: MerginClient):
25932593
"updated": [{"path": "/folder/project.updated.Qgs"}],
25942594
"removed": [{"path": "/folder/project.removed.qgs"}],
25952595
}
2596-
qgs_changeset = filter_changes(mc, project_info, qgs_changeset)
2596+
changes_handler = ChangesHandler(mc, project_info, qgs_changeset)
2597+
qgs_changeset = changes_handler._filter_changes(qgs_changeset)
25972598
assert sum(len(v) for v in qgs_changeset.values()) == 2
25982599

25992600

0 commit comments

Comments
 (0)