yd-cli 0.10__tar.gz → 0.12__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yd-cli
3
- Version: 0.10
3
+ Version: 0.12
4
4
  Summary: CLI tool to synchronize directories using rsync.
5
5
  Author: Christian Heinze
6
6
  License-Expression: MIT
@@ -14,9 +14,9 @@ Classifier: Programming Language :: Python :: 3.14
14
14
  Classifier: Topic :: System :: Archiving
15
15
  Classifier: Topic :: Utilities
16
16
  Classifier: Typing :: Typed
17
- Requires-Dist: msgspec>=0.20
18
- Requires-Dist: rich>=14.3
19
- Requires-Dist: typer>=0.24
17
+ Requires-Dist: msgspec>=0.21
18
+ Requires-Dist: rich>=15
19
+ Requires-Dist: typer>=0.26
20
20
  Requires-Python: >=3.14
21
21
  Project-URL: Repository, https://codeberg.org/christianheinze/yd-cli
22
22
  Description-Content-Type: text/markdown
@@ -25,6 +25,26 @@ Description-Content-Type: text/markdown
25
25
 
26
26
  Build and execute `rsync` commands from *TOML* configuration files.
27
27
 
28
+ ## (Un)Install
29
+
30
+ To install, run
31
+
32
+ ```bash
33
+ uv tool install yd-cli
34
+ ```
35
+
36
+ Then run
37
+
38
+ ```bash
39
+ yd --install-completion
40
+ ```
41
+
42
+ to install auto-completion in your shell.
43
+
44
+ In `bash`, the completion code is stored in `~/.bash_completions/yd.sh` and that file is sourced from `~/.bashrc`.
45
+ Remove both and call `uv tool uninstall yd-cli` to remove this tool.
46
+ The below mentioned configuration files need to be removed separately.
47
+
28
48
  ## Create a config
29
49
 
30
50
  Create a new configuration called `photos` with:
@@ -36,7 +56,7 @@ yd edit --new photos
36
56
  This command
37
57
 
38
58
  - creates `~/.config/yd/photos.toml` (or under `$XDG_CONFIG_HOME/yd` if set; relative paths are resolved from your home directory), and
39
- - opens it in the editor selected via `EDITOR`.
59
+ - opens it with the executable selected via `EDITOR`, or `nvim` when `EDITOR` is unset.
40
60
 
41
61
  Reopen an existing configuration with:
42
62
 
@@ -72,7 +92,7 @@ Leading comment lines directly at the top of the file are treated as the configu
72
92
  | Key | Meaning |
73
93
  | --- | --- |
74
94
  | `src_home` | Base directory for all `src` paths. Relative paths are resolved from your home directory. |
75
- | `target_home` | Base directory for all target paths. Relative paths are resolved from your home directory. `strftime` placeholders such as `%Y-%m-%d` are supported. |
95
+ | `target_home` | Base directory for all target paths. Relative paths are resolved from your home directory. |
76
96
  | `mtp_target` | Use in-place syncing for MTP targets. |
77
97
  | `backup` | Backup directory for replaced or deleted files. Relative paths are resolved from `target_home`. `strftime` placeholders are supported. |
78
98
  | `exclude` | Exclude patterns applied to every command. |
@@ -84,17 +104,20 @@ Leading comment lines directly at the top of the file are treated as the configu
84
104
  | Key | Meaning |
85
105
  | --- | --- |
86
106
  | `src` | Relative source directory below `src_home`. |
87
- | `target` | Relative target directory below `target_home`; defaults to `src`. `strftime` placeholders are supported. |
107
+ | `target` | Relative target directory below `target_home`; defaults to `src`. `strftime` placeholders (`%Y`, `%m`, and `%d` only!) are supported. A newly created dated target is removed if it contains only directories after synchronization. |
88
108
  | `delete_extra` | Delete files in the target that do not exist in the source. Defaults to `true`. |
89
109
  | `exclude` | Extra exclude patterns for this command only. |
90
110
 
91
111
  ### Notes
92
112
 
93
113
  - `src` and `target` must stay within `src_home` and `target_home` after path resolution.
114
+ - Literal targets are retained when they contain only empty directories. Dated targets serve as snapshots: if a dated target did not exist before synchronization and contains neither files nor symlinks afterward, `yd` removes its empty directory tree.
94
115
  - `src_home` or `target_home` may be omitted from the configuration, but every missing value must then be supplied when running (via CLI parameters).
95
116
  - Exactly one of `--src-home -` and `--target-home -` may read from standard input in a single run.
96
117
  - If `backup` is omitted, `yd` creates a timestamped backup directory automatically unless `--no-backup` is specified.
97
- - If a configured source directory exists but is empty, `yd` reports that no synchronization was performed for that command. E.g., forgetting to mount an external drive does not delete all corresponding copies on harddrive).
118
+ - If a configured source directory exists but is empty, `yd` reports that no synchronization was performed for that command. E.g., forgetting to mount an external drive does not delete all corresponding copies on hard-drive.
119
+ - If `strftime` placeholders are included in the `target`, then the `target_home` is scanned for matching directories (possibly) created by this rule before today.
120
+ The 20 most recent matches are included as additional comparison destinations in the synchronization: if a file in `src` is included in one of those reference directories, then it will not be copied to `target`.
98
121
 
99
122
  ## Run a config
100
123
 
@@ -115,6 +138,14 @@ yd run photos
115
138
  | `--src-home PATH` | Override `src_home` from the config. Use `-` to read the value from standard input. |
116
139
  | `--target-home PATH` | Override `target_home` from the config. Use `-` to read the value from standard input. |
117
140
 
141
+ ## Logging
142
+
143
+ Set `YD_LOGLEVEL` to a numeric [Python logging level](https://docs.python.org/3/library/logging.html#logging-levels), such as `10` for debug, `20` for info, or `40` for errors.
144
+ When set, `yd` appends *JSON* Lines records to `.yd.jsonl` in the current working directory.
145
+ Records contain `time`, `level`, `logger`, and `message` fields, plus exception `type`, `message`, and `traceback` when applicable.
146
+
147
+ Logging is effectively disabled by default. Enable it when diagnosing a failed or interrupted run.
148
+
118
149
  ## List configs
119
150
 
120
151
  List available configurations with:
@@ -128,5 +159,5 @@ This shows the configuration name together with the optional leading-comment des
128
159
  ## Why `yd`?
129
160
 
130
161
  - Has one character from `synchronize` and one from `directory`.
131
- - Easy to type with both *QWERTZ* and *QUERTY* keyboards.
162
+ - Easy to type with both *QWERTZ* and *QWERTY* keyboards.
132
163
  - Name was still available on *PyPI*.
@@ -2,6 +2,26 @@
2
2
 
3
3
  Build and execute `rsync` commands from *TOML* configuration files.
4
4
 
5
+ ## (Un)Install
6
+
7
+ To install, run
8
+
9
+ ```bash
10
+ uv tool install yd-cli
11
+ ```
12
+
13
+ Then run
14
+
15
+ ```bash
16
+ yd --install-completion
17
+ ```
18
+
19
+ to install auto-completion in your shell.
20
+
21
+ In `bash`, the completion code is stored in `~/.bash_completions/yd.sh` and that file is sourced from `~/.bashrc`.
22
+ Remove both and call `uv tool uninstall yd-cli` to remove this tool.
23
+ The below mentioned configuration files need to be removed separately.
24
+
5
25
  ## Create a config
6
26
 
7
27
  Create a new configuration called `photos` with:
@@ -13,7 +33,7 @@ yd edit --new photos
13
33
  This command
14
34
 
15
35
  - creates `~/.config/yd/photos.toml` (or under `$XDG_CONFIG_HOME/yd` if set; relative paths are resolved from your home directory), and
16
- - opens it in the editor selected via `EDITOR`.
36
+ - opens it with the executable selected via `EDITOR`, or `nvim` when `EDITOR` is unset.
17
37
 
18
38
  Reopen an existing configuration with:
19
39
 
@@ -49,7 +69,7 @@ Leading comment lines directly at the top of the file are treated as the configu
49
69
  | Key | Meaning |
50
70
  | --- | --- |
51
71
  | `src_home` | Base directory for all `src` paths. Relative paths are resolved from your home directory. |
52
- | `target_home` | Base directory for all target paths. Relative paths are resolved from your home directory. `strftime` placeholders such as `%Y-%m-%d` are supported. |
72
+ | `target_home` | Base directory for all target paths. Relative paths are resolved from your home directory. |
53
73
  | `mtp_target` | Use in-place syncing for MTP targets. |
54
74
  | `backup` | Backup directory for replaced or deleted files. Relative paths are resolved from `target_home`. `strftime` placeholders are supported. |
55
75
  | `exclude` | Exclude patterns applied to every command. |
@@ -61,17 +81,20 @@ Leading comment lines directly at the top of the file are treated as the configu
61
81
  | Key | Meaning |
62
82
  | --- | --- |
63
83
  | `src` | Relative source directory below `src_home`. |
64
- | `target` | Relative target directory below `target_home`; defaults to `src`. `strftime` placeholders are supported. |
84
+ | `target` | Relative target directory below `target_home`; defaults to `src`. `strftime` placeholders (`%Y`, `%m`, and `%d` only!) are supported. A newly created dated target is removed if it contains only directories after synchronization. |
65
85
  | `delete_extra` | Delete files in the target that do not exist in the source. Defaults to `true`. |
66
86
  | `exclude` | Extra exclude patterns for this command only. |
67
87
 
68
88
  ### Notes
69
89
 
70
90
  - `src` and `target` must stay within `src_home` and `target_home` after path resolution.
91
+ - Literal targets are retained when they contain only empty directories. Dated targets serve as snapshots: if a dated target did not exist before synchronization and contains neither files nor symlinks afterward, `yd` removes its empty directory tree.
71
92
  - `src_home` or `target_home` may be omitted from the configuration, but every missing value must then be supplied when running (via CLI parameters).
72
93
  - Exactly one of `--src-home -` and `--target-home -` may read from standard input in a single run.
73
94
  - If `backup` is omitted, `yd` creates a timestamped backup directory automatically unless `--no-backup` is specified.
74
- - If a configured source directory exists but is empty, `yd` reports that no synchronization was performed for that command. E.g., forgetting to mount an external drive does not delete all corresponding copies on harddrive).
95
+ - If a configured source directory exists but is empty, `yd` reports that no synchronization was performed for that command. E.g., forgetting to mount an external drive does not delete all corresponding copies on hard-drive.
96
+ - If `strftime` placeholders are included in the `target`, then the `target_home` is scanned for matching directories (possibly) created by this rule before today.
97
+ The 20 most recent matches are included as additional comparison destinations in the synchronization: if a file in `src` is included in one of those reference directories, then it will not be copied to `target`.
75
98
 
76
99
  ## Run a config
77
100
 
@@ -92,6 +115,14 @@ yd run photos
92
115
  | `--src-home PATH` | Override `src_home` from the config. Use `-` to read the value from standard input. |
93
116
  | `--target-home PATH` | Override `target_home` from the config. Use `-` to read the value from standard input. |
94
117
 
118
+ ## Logging
119
+
120
+ Set `YD_LOGLEVEL` to a numeric [Python logging level](https://docs.python.org/3/library/logging.html#logging-levels), such as `10` for debug, `20` for info, or `40` for errors.
121
+ When set, `yd` appends *JSON* Lines records to `.yd.jsonl` in the current working directory.
122
+ Records contain `time`, `level`, `logger`, and `message` fields, plus exception `type`, `message`, and `traceback` when applicable.
123
+
124
+ Logging is effectively disabled by default. Enable it when diagnosing a failed or interrupted run.
125
+
95
126
  ## List configs
96
127
 
97
128
  List available configurations with:
@@ -105,5 +136,5 @@ This shows the configuration name together with the optional leading-comment des
105
136
  ## Why `yd`?
106
137
 
107
138
  - Has one character from `synchronize` and one from `directory`.
108
- - Easy to type with both *QWERTZ* and *QUERTY* keyboards.
139
+ - Easy to type with both *QWERTZ* and *QWERTY* keyboards.
109
140
  - Name was still available on *PyPI*.
@@ -4,7 +4,7 @@ requires = [ "uv-build>=0.10,<0.12" ]
4
4
 
5
5
  [project]
6
6
  name = "yd-cli"
7
- version = "0.10"
7
+ version = "0.12"
8
8
  description = "CLI tool to synchronize directories using rsync."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -23,9 +23,9 @@ classifiers = [
23
23
  "Typing :: Typed",
24
24
  ]
25
25
  dependencies = [
26
- "msgspec>=0.20",
27
- "rich>=14.3",
28
- "typer>=0.24",
26
+ "msgspec>=0.21",
27
+ "rich>=15",
28
+ "typer>=0.26",
29
29
  ]
30
30
  urls.Repository = "https://codeberg.org/christianheinze/yd-cli"
31
31
  scripts.yd = "yd.cli:app"
@@ -38,9 +38,8 @@ dev = [
38
38
  { include-group = "test" },
39
39
  ]
40
40
  test = [
41
- # pytest-asyncio does not support pytest>=9 yet.
41
+ "anyio>=4.12",
42
42
  "pytest>=9",
43
- "pytest-asyncio>=1.3",
44
43
  "pytest-cov>=7",
45
44
  "pytest-randomly>=4",
46
45
  ]
@@ -51,8 +50,8 @@ format = [
51
50
  "ruff>=0.15.8",
52
51
  ]
53
52
  lint = [
53
+ "pyrefly>=1",
54
54
  "ruff>=0.15.8",
55
- "ty>=0.0.27",
56
55
  ]
57
56
 
58
57
  [tool.uv]
@@ -116,6 +115,7 @@ lint.select = [
116
115
  lint.ignore = [
117
116
  # Any allowed.
118
117
  "ANN401",
118
+ # Using pathlib operations in coroutines is ok here.
119
119
  "COM812",
120
120
  "COM819",
121
121
  # Missing documentation allowed.
@@ -173,28 +173,26 @@ lint.flake8-type-checking.runtime-evaluated-decorators = [
173
173
  "pydantic.validate_call",
174
174
  ]
175
175
  lint.flake8-unused-arguments.ignore-variadic-names = true
176
- lint.isort.required-imports = [ "from __future__ import annotations" ]
177
176
 
178
177
  [tool.pyproject-fmt]
179
178
  column_width = 88
180
179
  indent = 4
181
180
  max_supported_python = "3.14"
182
181
 
183
- [tool.ty]
184
- environment.python-platform = "linux"
185
- environment.root = [ "src/" ]
186
- src.include = [ "src/", "tests/" ]
187
- src.respect-ignore-files = false
182
+ [tool.pyrefly]
183
+ min-severity = "info"
184
+ preset = "strict"
185
+ project-includes = [ "src/**/*.py", "tests/**/*.py", "scripts/*.py" ]
186
+ use-ignore-files = false
188
187
 
189
188
  [tool.pytest]
190
- minversion = "9.0"
191
189
  addopts = [
192
190
  "--import-mode=importlib",
193
191
  "--strict-markers",
194
192
  "--cov=yd",
195
193
  "--cov=tests",
196
194
  ]
197
- testpaths = [ "tests" ]
198
- python_files = [ "test_*.py" ]
199
195
  filterwarnings = [ "error" ]
200
- asyncio_default_fixture_loop_scope = "function"
196
+ minversion = "9.0"
197
+ python_files = [ "test_*.py" ]
198
+ testpaths = [ "tests" ]
@@ -8,8 +8,6 @@ triggers `__getattr__` and thereby eager importing of the module. Instead, impor
8
8
  `yd` and use attribute access.
9
9
  """
10
10
 
11
- from __future__ import annotations
12
-
13
11
  import importlib
14
12
  import importlib.metadata
15
13
 
@@ -3,8 +3,6 @@
3
3
  # SPDX-License-Identifier: MIT
4
4
  """CLI entry point."""
5
5
 
6
- from __future__ import annotations
7
-
8
6
  if __name__ == "__main__":
9
7
  from yd import cli
10
8