yd-cli 0.11__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.11
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
@@ -56,7 +56,7 @@ yd edit --new photos
56
56
  This command
57
57
 
58
58
  - creates `~/.config/yd/photos.toml` (or under `$XDG_CONFIG_HOME/yd` if set; relative paths are resolved from your home directory), and
59
- - opens it in the editor selected via `EDITOR`.
59
+ - opens it with the executable selected via `EDITOR`, or `nvim` when `EDITOR` is unset.
60
60
 
61
61
  Reopen an existing configuration with:
62
62
 
@@ -104,19 +104,20 @@ Leading comment lines directly at the top of the file are treated as the configu
104
104
  | Key | Meaning |
105
105
  | --- | --- |
106
106
  | `src` | Relative source directory below `src_home`. |
107
- | `target` | Relative target directory below `target_home`; defaults to `src`. `strftime` placeholders (`%Y`, `%m`, and `%d` only!) 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. |
108
108
  | `delete_extra` | Delete files in the target that do not exist in the source. Defaults to `true`. |
109
109
  | `exclude` | Extra exclude patterns for this command only. |
110
110
 
111
111
  ### Notes
112
112
 
113
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.
114
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).
115
116
  - Exactly one of `--src-home -` and `--target-home -` may read from standard input in a single run.
116
117
  - If `backup` is omitted, `yd` creates a timestamped backup directory automatically unless `--no-backup` is specified.
117
- - 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 `strftime` placeholders are included in the `target`, then the `target_home` is scanned for directories that may have been created by this rule in the past. All matches are included as additional references in the synchronization: if a file in `src` is included in one of those reference directories, then it will not be copied to `target`.
119
- - If the `target` directory did not exist before and no files are transferred into it, then it will be removed again.
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`.
120
121
 
121
122
  ## Run a config
122
123
 
@@ -137,6 +138,14 @@ yd run photos
137
138
  | `--src-home PATH` | Override `src_home` from the config. Use `-` to read the value from standard input. |
138
139
  | `--target-home PATH` | Override `target_home` from the config. Use `-` to read the value from standard input. |
139
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
+
140
149
  ## List configs
141
150
 
142
151
  List available configurations with:
@@ -150,5 +159,5 @@ This shows the configuration name together with the optional leading-comment des
150
159
  ## Why `yd`?
151
160
 
152
161
  - Has one character from `synchronize` and one from `directory`.
153
- - Easy to type with both *QWERTZ* and *QUERTY* keyboards.
162
+ - Easy to type with both *QWERTZ* and *QWERTY* keyboards.
154
163
  - Name was still available on *PyPI*.
@@ -33,7 +33,7 @@ yd edit --new photos
33
33
  This command
34
34
 
35
35
  - creates `~/.config/yd/photos.toml` (or under `$XDG_CONFIG_HOME/yd` if set; relative paths are resolved from your home directory), and
36
- - opens it in the editor selected via `EDITOR`.
36
+ - opens it with the executable selected via `EDITOR`, or `nvim` when `EDITOR` is unset.
37
37
 
38
38
  Reopen an existing configuration with:
39
39
 
@@ -81,19 +81,20 @@ Leading comment lines directly at the top of the file are treated as the configu
81
81
  | Key | Meaning |
82
82
  | --- | --- |
83
83
  | `src` | Relative source directory below `src_home`. |
84
- | `target` | Relative target directory below `target_home`; defaults to `src`. `strftime` placeholders (`%Y`, `%m`, and `%d` only!) 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. |
85
85
  | `delete_extra` | Delete files in the target that do not exist in the source. Defaults to `true`. |
86
86
  | `exclude` | Extra exclude patterns for this command only. |
87
87
 
88
88
  ### Notes
89
89
 
90
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.
91
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).
92
93
  - Exactly one of `--src-home -` and `--target-home -` may read from standard input in a single run.
93
94
  - If `backup` is omitted, `yd` creates a timestamped backup directory automatically unless `--no-backup` is specified.
94
- - 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 `strftime` placeholders are included in the `target`, then the `target_home` is scanned for directories that may have been created by this rule in the past. All matches are included as additional references in the synchronization: if a file in `src` is included in one of those reference directories, then it will not be copied to `target`.
96
- - If the `target` directory did not exist before and no files are transferred into it, then it will be removed again.
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`.
97
98
 
98
99
  ## Run a config
99
100
 
@@ -114,6 +115,14 @@ yd run photos
114
115
  | `--src-home PATH` | Override `src_home` from the config. Use `-` to read the value from standard input. |
115
116
  | `--target-home PATH` | Override `target_home` from the config. Use `-` to read the value from standard input. |
116
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
+
117
126
  ## List configs
118
127
 
119
128
  List available configurations with:
@@ -127,5 +136,5 @@ This shows the configuration name together with the optional leading-comment des
127
136
  ## Why `yd`?
128
137
 
129
138
  - Has one character from `synchronize` and one from `directory`.
130
- - Easy to type with both *QWERTZ* and *QUERTY* keyboards.
139
+ - Easy to type with both *QWERTZ* and *QWERTY* keyboards.
131
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.11"
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