From 7aa55309928fad366c9c7e481bc887048ab57e7e Mon Sep 17 00:00:00 2001 From: Johnny Sequeira Date: Tue, 17 Feb 2026 09:23:13 -0600 Subject: [PATCH 1/3] Fixing delete files flag and other improvements --- .gitignore | 1 + docs/docs/examples.md | 32 +++++++++++++++++++++++++++++++- qfieldcloud_sdk/cli.py | 18 +++++++++++++++--- qfieldcloud_sdk/sdk.py | 10 +++++----- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index b80e3a7..fdbbf0d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ build **/qfieldcloud_sdk_python.egg-info .env Pipfile* +docs/site/* diff --git a/docs/docs/examples.md b/docs/docs/examples.md index 071e83b..2349e2f 100644 --- a/docs/docs/examples.md +++ b/docs/docs/examples.md @@ -227,7 +227,21 @@ To free up storage on QFieldCloud, you can delete unnecessary files, such as `.j qfieldcloud-cli delete-files "123e4567-e89b-12d3-a456-426614174000" --filter "*.jpg" ``` -You can also delete specific files by specifying their exact path: +Or if multiple type of files: + +=== ":material-bash: Bash" + + ```bash + qfieldcloud-cli delete-files '123e4567-e89b-12d3-a456-426614174000' --filter '*.jpg' '*.csv' + ``` + +=== ":material-powershell: PowerShell" + + ```powershell + qfieldcloud-cli delete-files "123e4567-e89b-12d3-a456-426614174000" --filter "*.jpg" '*.csv' + ``` + +You can also delete specific files by specifying their exact paths: === ":material-bash: Bash" @@ -241,6 +255,22 @@ You can also delete specific files by specifying their exact path: qfieldcloud-cli delete-files "123e4567-e89b-12d3-a456-426614174000" "DCIM\tree-202411202334943.jpg" ``` +Or for multiples files: + +You can also delete specific files by specifying their exact paths: + +=== ":material-bash: Bash" + + ```bash + qfieldcloud-cli delete-files '123e4567-e89b-12d3-a456-426614174000' 'DCIM/tree-202411202334943.jpg' 'DCIM/tree-202411202331234.jpg' + ``` + +=== ":material-powershell: PowerShell" + + ```powershell + qfieldcloud-cli delete-files "123e4567-e89b-12d3-a456-426614174000" "DCIM\tree-202411202334943.jpg" "DCIM/tree-202411202331234.jpg" + ``` + ### Manage Members and Collaborators The collaborative nature of QFieldCloud naturally involves other people in the fieldwork. diff --git a/qfieldcloud_sdk/cli.py b/qfieldcloud_sdk/cli.py index 56a611a..35be269 100755 --- a/qfieldcloud_sdk/cli.py +++ b/qfieldcloud_sdk/cli.py @@ -459,16 +459,28 @@ def patch_project( @cli.command() @click.argument("project_id") -@click.argument("paths", nargs=-1, required=True) +@click.argument("paths", nargs=-1) +@click.option( + "--filter", + multiple=True, + help="Glob pattern to filter files for deletion (e.g., '*.jpg'). Can be provided multiple times.", +) @click.option( "--throw-on-error/--no-throw-on-error", help="If any project file delete operations fails stop, stop deleting the rest. Default: False", ) @click.pass_context -def delete_files(ctx: Context, project_id, paths, throw_on_error): +def delete_files(ctx: Context, project_id, paths, filter, throw_on_error): """Delete QFieldCloud project files.""" - paths_result = ctx.obj["client"].delete_files(project_id, paths, throw_on_error) + all_patterns = list(paths) + list(filter) + + if not all_patterns: + log("You must provide at least one file path or use the --filter option.") + + paths_result = ctx.obj["client"].delete_files( + project_id, all_patterns, throw_on_error + ) if ctx.obj["format_json"]: print_json(paths_result) diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 27d8f35..f49c88f 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -946,20 +946,18 @@ def delete_files( file["status"] = FileTransferStatus.SUCCESS except QfcRequestException as err: resp = err.response - logger.info( f"{resp.request.method} {resp.url} got HTTP {resp.status_code}" ) file["status"] = FileTransferStatus.FAILED file["error"] = err - log(f'File "{file["name"]}" failed to delete:\n{file["error"]}') if throw_on_error: - continue - else: raise err + else: + continue finally: if callable(finished_cb): finished_cb(file) @@ -972,13 +970,15 @@ def delete_files( if file["status"] == FileTransferStatus.SUCCESS: files_deleted += 1 - elif file["status"] == FileTransferStatus.SUCCESS: + elif file["status"] == FileTransferStatus.FAILED: files_failed += 1 log(f"{files_deleted} file(s) deleted, {files_failed} file(s) failed to delete") return glob_results + return glob_results + def delete_file( self, project_id: str, From dab1515b1fa3864310efae3dabad2333ed4e0dcb Mon Sep 17 00:00:00 2001 From: Johnny Sequeira Date: Tue, 17 Feb 2026 11:21:37 -0600 Subject: [PATCH 2/3] Addressing review --- docs/docs/examples.md | 2 +- qfieldcloud_sdk/cli.py | 3 ++- qfieldcloud_sdk/sdk.py | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/docs/examples.md b/docs/docs/examples.md index 2349e2f..6de6e75 100644 --- a/docs/docs/examples.md +++ b/docs/docs/examples.md @@ -238,7 +238,7 @@ Or if multiple type of files: === ":material-powershell: PowerShell" ```powershell - qfieldcloud-cli delete-files "123e4567-e89b-12d3-a456-426614174000" --filter "*.jpg" '*.csv' + qfieldcloud-cli delete-files "123e4567-e89b-12d3-a456-426614174000" --filter "*.jpg" "*.csv" ``` You can also delete specific files by specifying their exact paths: diff --git a/qfieldcloud_sdk/cli.py b/qfieldcloud_sdk/cli.py index 78acf76..e476f10 100755 --- a/qfieldcloud_sdk/cli.py +++ b/qfieldcloud_sdk/cli.py @@ -518,7 +518,7 @@ def patch_project( ) @click.option( "--throw-on-error/--no-throw-on-error", - help="If any project file delete operations fails stop, stop deleting the rest. Default: False", + help="If any project file delete operations fails, stop deleting the rest. Default: False", ) @click.pass_context def delete_files(ctx: Context, project_id, paths, filter, throw_on_error): @@ -528,6 +528,7 @@ def delete_files(ctx: Context, project_id, paths, filter, throw_on_error): if not all_patterns: log("You must provide at least one file path or use the --filter option.") + return paths_result = ctx.obj["client"].delete_files( project_id, all_patterns, throw_on_error diff --git a/qfieldcloud_sdk/sdk.py b/qfieldcloud_sdk/sdk.py index 94066d0..23f7c52 100644 --- a/qfieldcloud_sdk/sdk.py +++ b/qfieldcloud_sdk/sdk.py @@ -1049,8 +1049,6 @@ def delete_files( return glob_results - return glob_results - def delete_file( self, project_id: str, From a8cf52ef8265327ba7c3eb14fec2c217c7ccc31e Mon Sep 17 00:00:00 2001 From: Johnny Sequeira Date: Thu, 19 Feb 2026 09:17:32 -0600 Subject: [PATCH 3/3] changing from filter to filter_glob --- qfieldcloud_sdk/cli.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qfieldcloud_sdk/cli.py b/qfieldcloud_sdk/cli.py index e476f10..55958ec 100755 --- a/qfieldcloud_sdk/cli.py +++ b/qfieldcloud_sdk/cli.py @@ -513,6 +513,7 @@ def patch_project( @click.argument("paths", nargs=-1) @click.option( "--filter", + "filter_glob", multiple=True, help="Glob pattern to filter files for deletion (e.g., '*.jpg'). Can be provided multiple times.", ) @@ -521,10 +522,10 @@ def patch_project( help="If any project file delete operations fails, stop deleting the rest. Default: False", ) @click.pass_context -def delete_files(ctx: Context, project_id, paths, filter, throw_on_error): +def delete_files(ctx: Context, project_id, paths, filter_glob, throw_on_error): """Delete QFieldCloud project files.""" - all_patterns = list(paths) + list(filter) + all_patterns = list(paths) + list(filter_glob) if not all_patterns: log("You must provide at least one file path or use the --filter option.")