dbx-sync 0.2.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/AGENTS.md +3 -4
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/PKG-INFO +36 -5
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/README.md +35 -4
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/src/dbx_sync/__init__.py +1 -1
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/src/dbx_sync/cli.py +29 -6
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/src/dbx_sync/sync.py +243 -52
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/tests/test_cli.py +54 -3
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/tests/test_sync.py +914 -30
- dbx_sync-0.4.0/uv.lock +344 -0
- dbx_sync-0.2.0/uv.lock +0 -343
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/.github/CODEOWNERS +0 -0
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/.github/workflows/release.yml +0 -0
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/.gitignore +0 -0
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/.python-version +0 -0
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/CONTRIBUTING.md +0 -0
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/LICENSE +0 -0
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/pyproject.toml +0 -0
- {dbx_sync-0.2.0 → dbx_sync-0.4.0}/src/dbx_sync/__main__.py +0 -0
|
@@ -6,9 +6,9 @@ This repository uses a single shared instruction file for coding agents.
|
|
|
6
6
|
|
|
7
7
|
1. Sync dependencies with `uv sync --dev`.
|
|
8
8
|
2. Implement code inside `src/dbx_sync/` using typed functions and small modules.
|
|
9
|
-
3.
|
|
10
|
-
4.
|
|
11
|
-
5.
|
|
9
|
+
3. Update README.md to document new or changed functionality.
|
|
10
|
+
4. Add or update tests in `tests/` for each user-visible change.
|
|
11
|
+
5. Run `uv run ruff format .`, `uv run ruff check .`, `uv run ty check`, and `uv run pytest` before handing work back.
|
|
12
12
|
|
|
13
13
|
## Guardrails
|
|
14
14
|
|
|
@@ -39,4 +39,3 @@ This repository uses a single shared instruction file for coding agents.
|
|
|
39
39
|
- Add unit tests for critical paths and behavior changes.
|
|
40
40
|
- Include edge-case coverage for empty inputs, invalid state, and error handling when those paths matter.
|
|
41
41
|
- Keep tests readable and focused on behavior rather than implementation detail.
|
|
42
|
-
- When adapting logic from another codebase, translate the relevant tests into this repo's current API instead of copying obsolete cases unchanged.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dbx-sync
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Synchronize Databricks workspace content with a local directory.
|
|
5
5
|
Project-URL: Repository, https://github.com/gramhagen/dbx-sync
|
|
6
6
|
Author: gramhagen
|
|
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
|
|
|
22
22
|
|
|
23
23
|
Are you tired of bouncing between the Databricks workspace UI and your local editor, copying changes by hand, and pretending that counts as a workflow? Well now there's `dbx-sync`.
|
|
24
24
|
|
|
25
|
-
`dbx-sync` keeps a
|
|
25
|
+
`dbx-sync` keeps a Databricks workspace folder or file and a local directory or file in sync so you can work with your favorite tools and still stay aligned with what is running in Databricks.
|
|
26
26
|
|
|
27
27
|
Build locally, run in Databricks, tweak it there, then jump back to local coding. Skip the usual copy-paste ritual or one-way imports to weird folders.
|
|
28
28
|
|
|
@@ -32,9 +32,10 @@ Worried about losing files? `dbx-sync` does not delete files locally or remotely
|
|
|
32
32
|
|
|
33
33
|
Current scope notes:
|
|
34
34
|
|
|
35
|
-
- Sync is limited to a single local folder
|
|
35
|
+
- Sync is limited to a single local folder/workspace folder pair or one local/workspace file pair.
|
|
36
36
|
- File and folder discovery is not recursive.
|
|
37
37
|
- Local tracking currently covers notebook files with Databricks notebook extensions: `.py`, `.sql`, `.scala`, `.r`, and `.ipynb`.
|
|
38
|
+
- When syncing a single local file, notebook extensions are imported as notebooks and other files are imported as workspace files.
|
|
38
39
|
|
|
39
40
|
## Prerequisites
|
|
40
41
|
|
|
@@ -83,6 +84,24 @@ Sync a single workspace folder with a single local folder (one-time):
|
|
|
83
84
|
dbx-sync ./local-project /Workspace/Users/me/project
|
|
84
85
|
```
|
|
85
86
|
|
|
87
|
+
Sync a single local file to a workspace folder, using the source filename for the target object:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
dbx-sync ./local-project/notebook.py /Workspace/Users/me/project
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Sync a single workspace file or notebook to a local folder, using the source filename locally:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
dbx-sync ./local-project /Workspace/Users/me/project/notebook
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Sync explicit local and workspace file paths:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
dbx-sync ./local-project/notebook.py /Workspace/Users/me/project/notebook
|
|
103
|
+
```
|
|
104
|
+
|
|
86
105
|
Preview actions without applying them:
|
|
87
106
|
|
|
88
107
|
```bash
|
|
@@ -95,6 +114,19 @@ Continuously watch and resync (default polling happens every second):
|
|
|
95
114
|
dbx-sync ./local-project /Workspace/Users/me/project --watch
|
|
96
115
|
```
|
|
97
116
|
|
|
117
|
+
Use `--force` to clear saved sync state before a fresh pass. This can be useful to handle conflicts.
|
|
118
|
+
Pro-tip: Add --dry-run to check force behavior before running it for real.
|
|
119
|
+
|
|
120
|
+
Force options are mutually exclusive and only apply to a single sync pass:
|
|
121
|
+
|
|
122
|
+
- `--force` clears saved sync state before comparing local and remote files.
|
|
123
|
+
- `--force-upload` uploads matching local files even when saved sync state would otherwise skip them.
|
|
124
|
+
- `--force-download` downloads matching remote files even when saved sync state would otherwise skip them.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
dbx-sync ./local-project /Workspace/Users/me/project --force
|
|
128
|
+
```
|
|
129
|
+
|
|
98
130
|
Override optional settings when needed:
|
|
99
131
|
|
|
100
132
|
```bash
|
|
@@ -102,10 +134,9 @@ dbx-sync ./local-project /Workspace/Users/me/project \
|
|
|
102
134
|
--profile WORKSPACE \
|
|
103
135
|
--poll-interval 5 \
|
|
104
136
|
--log-level DEBUG \
|
|
105
|
-
--force
|
|
106
137
|
```
|
|
107
138
|
|
|
108
|
-
Use `--
|
|
139
|
+
Watch mode cannot be combined with force options or dry-run mode. Use `--watch` for continuous syncing, or use `--dry-run`, `--force`, `--force-upload`, and `--force-download` for one-time sync passes.
|
|
109
140
|
|
|
110
141
|
If your local directory does not exist, the tool will attempt to create it for you (when not in dry-run mode).
|
|
111
142
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
Are you tired of bouncing between the Databricks workspace UI and your local editor, copying changes by hand, and pretending that counts as a workflow? Well now there's `dbx-sync`.
|
|
13
13
|
|
|
14
|
-
`dbx-sync` keeps a
|
|
14
|
+
`dbx-sync` keeps a Databricks workspace folder or file and a local directory or file in sync so you can work with your favorite tools and still stay aligned with what is running in Databricks.
|
|
15
15
|
|
|
16
16
|
Build locally, run in Databricks, tweak it there, then jump back to local coding. Skip the usual copy-paste ritual or one-way imports to weird folders.
|
|
17
17
|
|
|
@@ -21,9 +21,10 @@ Worried about losing files? `dbx-sync` does not delete files locally or remotely
|
|
|
21
21
|
|
|
22
22
|
Current scope notes:
|
|
23
23
|
|
|
24
|
-
- Sync is limited to a single local folder
|
|
24
|
+
- Sync is limited to a single local folder/workspace folder pair or one local/workspace file pair.
|
|
25
25
|
- File and folder discovery is not recursive.
|
|
26
26
|
- Local tracking currently covers notebook files with Databricks notebook extensions: `.py`, `.sql`, `.scala`, `.r`, and `.ipynb`.
|
|
27
|
+
- When syncing a single local file, notebook extensions are imported as notebooks and other files are imported as workspace files.
|
|
27
28
|
|
|
28
29
|
## Prerequisites
|
|
29
30
|
|
|
@@ -72,6 +73,24 @@ Sync a single workspace folder with a single local folder (one-time):
|
|
|
72
73
|
dbx-sync ./local-project /Workspace/Users/me/project
|
|
73
74
|
```
|
|
74
75
|
|
|
76
|
+
Sync a single local file to a workspace folder, using the source filename for the target object:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
dbx-sync ./local-project/notebook.py /Workspace/Users/me/project
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Sync a single workspace file or notebook to a local folder, using the source filename locally:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
dbx-sync ./local-project /Workspace/Users/me/project/notebook
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Sync explicit local and workspace file paths:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
dbx-sync ./local-project/notebook.py /Workspace/Users/me/project/notebook
|
|
92
|
+
```
|
|
93
|
+
|
|
75
94
|
Preview actions without applying them:
|
|
76
95
|
|
|
77
96
|
```bash
|
|
@@ -84,6 +103,19 @@ Continuously watch and resync (default polling happens every second):
|
|
|
84
103
|
dbx-sync ./local-project /Workspace/Users/me/project --watch
|
|
85
104
|
```
|
|
86
105
|
|
|
106
|
+
Use `--force` to clear saved sync state before a fresh pass. This can be useful to handle conflicts.
|
|
107
|
+
Pro-tip: Add --dry-run to check force behavior before running it for real.
|
|
108
|
+
|
|
109
|
+
Force options are mutually exclusive and only apply to a single sync pass:
|
|
110
|
+
|
|
111
|
+
- `--force` clears saved sync state before comparing local and remote files.
|
|
112
|
+
- `--force-upload` uploads matching local files even when saved sync state would otherwise skip them.
|
|
113
|
+
- `--force-download` downloads matching remote files even when saved sync state would otherwise skip them.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
dbx-sync ./local-project /Workspace/Users/me/project --force
|
|
117
|
+
```
|
|
118
|
+
|
|
87
119
|
Override optional settings when needed:
|
|
88
120
|
|
|
89
121
|
```bash
|
|
@@ -91,10 +123,9 @@ dbx-sync ./local-project /Workspace/Users/me/project \
|
|
|
91
123
|
--profile WORKSPACE \
|
|
92
124
|
--poll-interval 5 \
|
|
93
125
|
--log-level DEBUG \
|
|
94
|
-
--force
|
|
95
126
|
```
|
|
96
127
|
|
|
97
|
-
Use `--
|
|
128
|
+
Watch mode cannot be combined with force options or dry-run mode. Use `--watch` for continuous syncing, or use `--dry-run`, `--force`, `--force-upload`, and `--force-download` for one-time sync passes.
|
|
98
129
|
|
|
99
130
|
If your local directory does not exist, the tool will attempt to create it for you (when not in dry-run mode).
|
|
100
131
|
|
|
@@ -4,7 +4,8 @@ import argparse
|
|
|
4
4
|
from collections.abc import Sequence
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
-
from dbx_sync
|
|
7
|
+
from dbx_sync import __version__
|
|
8
|
+
from dbx_sync.sync import ForceType, run_sync
|
|
8
9
|
|
|
9
10
|
DEFAULT_POLL_INTERVAL_SECONDS = 1
|
|
10
11
|
LOG_LEVELS = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
|
@@ -29,10 +30,11 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
29
30
|
"""
|
|
30
31
|
parser = argparse.ArgumentParser(
|
|
31
32
|
prog="dbx-sync",
|
|
32
|
-
description="Synchronize Databricks workspace files
|
|
33
|
+
description="Synchronize Databricks workspace files with a local path.",
|
|
33
34
|
)
|
|
34
|
-
parser.add_argument("
|
|
35
|
-
parser.add_argument("
|
|
35
|
+
parser.add_argument("-v", "--version", action="version", version=f"%(prog)s {__version__}")
|
|
36
|
+
parser.add_argument("local_dir", help="Local file or directory to sync")
|
|
37
|
+
parser.add_argument("workspace", help="Databricks workspace file or folder to sync")
|
|
36
38
|
parser.add_argument("--profile", default="DEFAULT", help="Databricks CLI profile name")
|
|
37
39
|
parser.add_argument(
|
|
38
40
|
"-p",
|
|
@@ -60,14 +62,35 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
60
62
|
action="store_true",
|
|
61
63
|
help="Watch for changes and sync continuously",
|
|
62
64
|
)
|
|
63
|
-
parser.
|
|
65
|
+
force_group = parser.add_mutually_exclusive_group()
|
|
66
|
+
force_group.add_argument(
|
|
64
67
|
"-f",
|
|
65
68
|
"--force",
|
|
66
69
|
action="store_true",
|
|
67
70
|
help="Force a refresh by clearing saved sync state before running",
|
|
68
71
|
)
|
|
72
|
+
force_group.add_argument(
|
|
73
|
+
"-fu",
|
|
74
|
+
"--force-upload",
|
|
75
|
+
action="store_true",
|
|
76
|
+
help="Force upload of all local files, ignoring sync state",
|
|
77
|
+
)
|
|
78
|
+
force_group.add_argument(
|
|
79
|
+
"-fd",
|
|
80
|
+
"--force-download",
|
|
81
|
+
action="store_true",
|
|
82
|
+
help="Force download of all remote files, ignoring sync state",
|
|
83
|
+
)
|
|
69
84
|
args = parser.parse_args(argv)
|
|
70
85
|
|
|
86
|
+
force_type = None
|
|
87
|
+
if args.force:
|
|
88
|
+
force_type = ForceType.CLEAR
|
|
89
|
+
elif args.force_upload:
|
|
90
|
+
force_type = ForceType.UPLOAD
|
|
91
|
+
elif args.force_download:
|
|
92
|
+
force_type = ForceType.DOWNLOAD
|
|
93
|
+
|
|
71
94
|
try:
|
|
72
95
|
return run_sync(
|
|
73
96
|
local_dir=Path(args.local_dir).expanduser().resolve(),
|
|
@@ -77,7 +100,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
77
100
|
log_level=args.log_level,
|
|
78
101
|
dry_run=args.dry_run,
|
|
79
102
|
watch=args.watch,
|
|
80
|
-
|
|
103
|
+
force_type=force_type,
|
|
81
104
|
)
|
|
82
105
|
except RuntimeError as exc:
|
|
83
106
|
# print user-friendly instructions if error is reauthentication-related, otherwise re-raise
|