pyselfupdate 0.5.4__tar.gz → 0.5.5__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.
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/PKG-INFO +3 -3
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/README.md +2 -2
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/pyproject.toml +18 -19
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/install.py +5 -4
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/notifier.py +0 -4
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/typercmd.py +39 -12
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/updater.py +2 -3
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/.gitignore +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/LICENSE +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/__init__.py +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/config.py +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/errors.py +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/github.py +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/py.typed +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/source.py +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/state.py +0 -0
- {pyselfupdate-0.5.4 → pyselfupdate-0.5.5}/src/pyselfupdate/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pyselfupdate
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.5
|
|
4
4
|
Summary: Self-update and update notification for Python CLIs installed with uv tool
|
|
5
5
|
Project-URL: Repository, https://github.com/datapointchris/pyselfupdate
|
|
6
6
|
Project-URL: Issues, https://github.com/datapointchris/pyselfupdate/issues
|
|
@@ -143,8 +143,8 @@ fail in ways that are hard to read.
|
|
|
143
143
|
|
|
144
144
|
So make `update` the last thing the process does, then call `exit_now`. Or call
|
|
145
145
|
`update_and_reexec`, which replaces the process with the release it installed,
|
|
146
|
-
running the same command line.
|
|
147
|
-
|
|
146
|
+
running the same command line. `update_and_reexec` writes `lock_warning` to
|
|
147
|
+
stderr itself before the re-exec, because its caller never sees the `Result`.
|
|
148
148
|
|
|
149
149
|
`check` reports what `update` would install, and installs nothing:
|
|
150
150
|
|
|
@@ -120,8 +120,8 @@ fail in ways that are hard to read.
|
|
|
120
120
|
|
|
121
121
|
So make `update` the last thing the process does, then call `exit_now`. Or call
|
|
122
122
|
`update_and_reexec`, which replaces the process with the release it installed,
|
|
123
|
-
running the same command line.
|
|
124
|
-
|
|
123
|
+
running the same command line. `update_and_reexec` writes `lock_warning` to
|
|
124
|
+
stderr itself before the re-exec, because its caller never sees the `Result`.
|
|
125
125
|
|
|
126
126
|
`check` reports what `update` would install, and installs nothing:
|
|
127
127
|
|
|
@@ -42,7 +42,7 @@ dev = [
|
|
|
42
42
|
"mypy>=1.10.0",
|
|
43
43
|
"pre-commit>=4.3.0",
|
|
44
44
|
"pytest>=8.0.0",
|
|
45
|
-
"ruff==0.
|
|
45
|
+
"ruff==0.17.1",
|
|
46
46
|
"typer>=0.12.0",
|
|
47
47
|
]
|
|
48
48
|
|
|
@@ -95,6 +95,7 @@ exclude = [
|
|
|
95
95
|
"build",
|
|
96
96
|
"dist",
|
|
97
97
|
]
|
|
98
|
+
extend-exclude = ["*.md"]
|
|
98
99
|
|
|
99
100
|
[tool.ruff.format]
|
|
100
101
|
quote-style = "single"
|
|
@@ -158,12 +159,28 @@ major_on_zero = false
|
|
|
158
159
|
typeCheckingMode = "standard"
|
|
159
160
|
analyzeUnannotatedFunctions = true # or pylance stops analyzing in vscode
|
|
160
161
|
|
|
162
|
+
[tool.hatch.version]
|
|
163
|
+
source = "uv-dynamic-versioning"
|
|
164
|
+
|
|
165
|
+
[tool.uv-dynamic-versioning]
|
|
166
|
+
style = "semver"
|
|
167
|
+
|
|
168
|
+
# A new commit or tag changes the version, so it has to invalidate uv's cache.
|
|
169
|
+
[tool.uv]
|
|
170
|
+
cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true, tags = true } }]
|
|
171
|
+
|
|
172
|
+
# The published sdist holds the package and its metadata, and none of the
|
|
173
|
+
# repo's tooling or tests. hatchling's default takes the whole tree.
|
|
174
|
+
[tool.hatch.build.targets.sdist]
|
|
175
|
+
only-include = ["src"]
|
|
176
|
+
|
|
161
177
|
[tool.forge]
|
|
162
178
|
# Keys the shared toolchain standard owns, written by its generator.
|
|
163
179
|
# Dropping one from the template removes it here on the next sync; a key absent
|
|
164
180
|
# from this list belongs to the project and is never touched. Do not hand-edit.
|
|
165
181
|
managed = [
|
|
166
182
|
["ruff", "line-length"],
|
|
183
|
+
["ruff", "extend-exclude"],
|
|
167
184
|
["ruff", "format", "quote-style"],
|
|
168
185
|
["ruff", "format", "indent-style"],
|
|
169
186
|
["ruff", "format", "skip-magic-trailing-comma"],
|
|
@@ -197,24 +214,6 @@ managed = [
|
|
|
197
214
|
# and extra that names them, so a local run and CI cannot disagree.
|
|
198
215
|
pinned = ["ruff"]
|
|
199
216
|
|
|
200
|
-
# The release tag is the version. python-semantic-release finds no file to
|
|
201
|
-
# stamp, so it tags the merge commit itself and writes no release commit.
|
|
202
|
-
# uv_build cannot do this: its metadata has no dynamic version field.
|
|
203
|
-
[tool.hatch.version]
|
|
204
|
-
source = "uv-dynamic-versioning"
|
|
205
|
-
|
|
206
|
-
[tool.uv-dynamic-versioning]
|
|
207
|
-
style = "semver"
|
|
208
|
-
|
|
209
|
-
# A new commit or tag changes the version, so it has to invalidate uv's cache.
|
|
210
|
-
[tool.uv]
|
|
211
|
-
cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true, tags = true } }]
|
|
212
|
-
|
|
213
|
-
# The published sdist holds the package and its metadata, and none of the
|
|
214
|
-
# repo's tooling or tests, as uv_build's did.
|
|
215
|
-
[tool.hatch.build.targets.sdist]
|
|
216
|
-
only-include = ["src"]
|
|
217
|
-
|
|
218
217
|
[build-system]
|
|
219
218
|
requires = ["hatchling", "uv-dynamic-versioning"]
|
|
220
219
|
build-backend = "hatchling.build"
|
|
@@ -95,6 +95,7 @@ def tool_dir() -> Path:
|
|
|
95
95
|
`UV_TOOL_DIR` first. Otherwise uv's data directory: `%APPDATA%\\uv` on
|
|
96
96
|
Windows, where uv ignores `XDG_DATA_HOME`, and `$XDG_DATA_HOME/uv` or
|
|
97
97
|
`~/.local/share/uv` everywhere else.
|
|
98
|
+
|
|
98
99
|
Resolved from the environment rather than by running `uv tool dir`, which
|
|
99
100
|
costs a subprocess on a path that runs before every command.
|
|
100
101
|
"""
|
|
@@ -442,11 +443,11 @@ def _run(command: list[str], cwd: Path | None = None) -> subprocess.CompletedPro
|
|
|
442
443
|
|
|
443
444
|
|
|
444
445
|
def _reason(completed: subprocess.CompletedProcess[str]) -> str:
|
|
445
|
-
"""Everything a failing command printed
|
|
446
|
+
"""Everything a failing command printed.
|
|
446
447
|
|
|
447
|
-
uv puts a lock's schema error on its
|
|
448
|
-
|
|
449
|
-
sentence.
|
|
448
|
+
No single line carries the reason: uv puts a lock's schema error on its
|
|
449
|
+
first line, git puts a missing ref on its last, and uv wraps a resolution
|
|
450
|
+
failure so its last line is half a sentence.
|
|
450
451
|
"""
|
|
451
452
|
return (completed.stderr or completed.stdout or '').strip() or f'exit status {completed.returncode}'
|
|
452
453
|
|
|
@@ -124,10 +124,6 @@ def _asking_for_help() -> bool:
|
|
|
124
124
|
screen. Nothing a notice is for happens on a help screen, and the check
|
|
125
125
|
costs a releases-API call and a state write every time.
|
|
126
126
|
|
|
127
|
-
It lands hardest on a reader that walks a tool's help. Reading every
|
|
128
|
-
command's help is one invocation per command plus one for the root, and
|
|
129
|
-
each of them reaches this.
|
|
130
|
-
|
|
131
127
|
A `--` ends the scan, because everything after it is the command's own
|
|
132
128
|
argument. Skipping when it should not have costs a missed notice, which is
|
|
133
129
|
the cheap direction to be wrong in.
|
|
@@ -32,10 +32,39 @@ from pyselfupdate.updater import install_release
|
|
|
32
32
|
from pyselfupdate.updater import require_updatable
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def update_help(tool: str, name: str, markup_mode: str | None) -> str:
|
|
36
|
+
"""The update command's help: one line on what it does, then annotated examples.
|
|
37
|
+
|
|
38
|
+
Each example keeps a line of its own under each of typer's markup modes,
|
|
39
|
+
which lay out a help's later paragraphs differently. Markdown joins a
|
|
40
|
+
paragraph's lines, so the examples sit in a fenced block there. Rich markup
|
|
41
|
+
keeps the lines as written and would print a fence's backticks. Without
|
|
42
|
+
rich, click rewraps every paragraph that does not open with its `\\b`
|
|
43
|
+
marker.
|
|
44
|
+
"""
|
|
45
|
+
command = f'{tool} {name}'
|
|
46
|
+
width = len(command) + len(' --no-changelog') + 2
|
|
47
|
+
examples = '\n'.join(
|
|
48
|
+
f'{call:<{width}}{purpose}'
|
|
49
|
+
for call, purpose in (
|
|
50
|
+
(command, 'install the newest and list its commits'),
|
|
51
|
+
(f'{command} --check', 'only report whether a newer one exists'),
|
|
52
|
+
(f'{command} --no-changelog', 'install it without listing its commits'),
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
if markup_mode == 'markdown':
|
|
56
|
+
block = f'```text\n{examples}\n```'
|
|
57
|
+
elif markup_mode == 'rich':
|
|
58
|
+
block = examples
|
|
59
|
+
else:
|
|
60
|
+
block = f'\b\n{examples}'
|
|
61
|
+
return f'Update {tool} to the latest release\n\nExamples:\n\n{block}'
|
|
62
|
+
|
|
63
|
+
|
|
35
64
|
def add_update_command(app: typer.Typer, config: Config, *, name: str = 'update') -> None:
|
|
36
65
|
"""Register `<tool> update` on an existing typer app."""
|
|
37
66
|
|
|
38
|
-
@app.command(name=name, help=
|
|
67
|
+
@app.command(name=name, help=update_help(config.tool, name, app.rich_markup_mode))
|
|
39
68
|
def update_command(
|
|
40
69
|
check_only: bool = typer.Option(False, '--check', help='Report whether an update is available without installing it'),
|
|
41
70
|
skip_changelog: bool = typer.Option(False, '--no-changelog', help='Do not list the commits between versions'),
|
|
@@ -52,17 +81,15 @@ def run_update(config: Config, *, check_only: bool = False, skip_changelog: bool
|
|
|
52
81
|
library report an update in the same words.
|
|
53
82
|
|
|
54
83
|
`check_only` reads the receipt first, as an update does, and refuses the
|
|
55
|
-
same installs.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
transport module. The release it had just installed did not depend on that
|
|
65
|
-
module, so the install had deleted it.
|
|
84
|
+
same installs. `updater.installed_from_release` says why a version alone
|
|
85
|
+
cannot decide.
|
|
86
|
+
|
|
87
|
+
Everything that reaches the network or imports a module happens before the
|
|
88
|
+
install; after it, this process only prints what it already holds and exits
|
|
89
|
+
without unwinding. An import after the install can name a module the new
|
|
90
|
+
release no longer ships, which the install has already deleted. An HTTP
|
|
91
|
+
client's lazy import of its transport is one, and it raises ImportError
|
|
92
|
+
after the update has succeeded.
|
|
66
93
|
"""
|
|
67
94
|
tool = config.tool
|
|
68
95
|
try:
|
|
@@ -97,9 +97,8 @@ def installed_from_release(installation: Installation, tag_prefix: str) -> bool:
|
|
|
97
97
|
|
|
98
98
|
An index install is. A git install is when its revision is a release tag:
|
|
99
99
|
`tag_prefix` followed by a semantic version, the form a release's
|
|
100
|
-
`install_ref` takes.
|
|
101
|
-
|
|
102
|
-
branch from a tag.
|
|
100
|
+
`install_ref` takes. `Installation.revision` holds a branch or a commit in
|
|
101
|
+
the same field, so only the value tells them apart.
|
|
103
102
|
|
|
104
103
|
A build from a branch reports a version that ranks wrongly against a
|
|
105
104
|
release. Versioned from git tags, a branch three commits past v1.2.3 builds
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|