python-update-checker 0.5__py3-none-any.whl → 0.7__py3-none-any.whl

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.
puc/cli.py CHANGED
@@ -9,6 +9,7 @@ import argparse
9
9
  import sys
10
10
  import logging
11
11
  import os
12
+ import shlex
12
13
  import tempfile
13
14
  from packaging.utils import canonicalize_name
14
15
  from typing import TextIO, Any
@@ -63,6 +64,11 @@ def get_option_parser() -> argparse.ArgumentParser:
63
64
  dest="exclude_newer",
64
65
  help="Limit package versions to those that were uploaded prior to the given date",
65
66
  )
67
+ parser.add_argument(
68
+ "--exclude-newer-package",
69
+ dest="exclude_newer_package",
70
+ help="Limit candidate packages for specific packages to those that were uploaded prior to the given date. Accepts package-date pairs in the format PACKAGE=DATE.",
71
+ )
66
72
  parser.add_argument(
67
73
  "--constraints",
68
74
  dest="constraints",
@@ -133,6 +139,7 @@ def handle_dependency_file(dep_file: str, optargs, constraint_file):
133
139
  packages=packages,
134
140
  command=optargs.command,
135
141
  exclude_newer=optargs.exclude_newer,
142
+ exclude_newer_package=optargs.exclude_newer_package,
136
143
  constraint_file=constraint_file,
137
144
  color=optargs.color,
138
145
  )
@@ -143,6 +150,7 @@ def handle_dependency_file(dep_file: str, optargs, constraint_file):
143
150
  packages=packages,
144
151
  command=optargs.command,
145
152
  exclude_newer=optargs.exclude_newer,
153
+ exclude_newer_package=optargs.exclude_newer_package,
146
154
  constraint_file=constraint_file,
147
155
  color=optargs.color,
148
156
  )
@@ -153,6 +161,7 @@ def handle_dependency_file(dep_file: str, optargs, constraint_file):
153
161
  packages=packages,
154
162
  command=optargs.command,
155
163
  exclude_newer=optargs.exclude_newer,
164
+ exclude_newer_package=optargs.exclude_newer_package,
156
165
  constraint_file=constraint_file,
157
166
  color=optargs.color,
158
167
  )
@@ -165,6 +174,7 @@ def handle_dependency_file(dep_file: str, optargs, constraint_file):
165
174
 
166
175
  def main() -> int:
167
176
  """Parse options and check or update dependencies."""
177
+ logger.info(f"{shlex.join(sys.argv)}")
168
178
  # parse options
169
179
  try:
170
180
  optargs = get_option_parser().parse_args(sys.argv[1:])
@@ -208,7 +218,3 @@ def main() -> int:
208
218
  os.unlink(constraint_file)
209
219
  # check command returns non-zero exit code when updates are available
210
220
  return 1 if optargs.command == "check" and updatable > 0 else 0
211
-
212
-
213
- # if __name__ == "__main__":
214
- # sys.exit(main(sys.argv[1:]))
puc/dependencies.py CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  import subprocess
6
6
  import re
7
+ import logging
7
8
  from packaging.requirements import Requirement
8
9
  from packaging.markers import Variable, MarkerList
9
10
  from packaging.version import parse as parse_version
@@ -12,8 +13,9 @@ from .logging import logger
12
13
 
13
14
  def get_latest_version(
14
15
  package: str,
15
- exclude_newer: None | str = None,
16
- constraint_file: None | str = None,
16
+ exclude_newer: str | None = None,
17
+ exclude_newer_package: str | None = None,
18
+ constraint_file: str | None = None,
17
19
  python_platform: str | None = None,
18
20
  python_version: str | None = None,
19
21
  ) -> str:
@@ -27,14 +29,19 @@ def get_latest_version(
27
29
  "compile",
28
30
  "-",
29
31
  "--color=never",
30
- "--quiet",
31
32
  "--no-deps",
32
33
  "--no-header",
33
34
  "--no-annotate",
34
35
  "--no-progress",
35
36
  ]
37
+ if logger.getEffectiveLevel() <= logging.DEBUG:
38
+ cmd.append("--verbose")
39
+ else:
40
+ cmd.append("--quiet")
36
41
  if exclude_newer:
37
42
  cmd.extend(("--exclude-newer", exclude_newer))
43
+ if exclude_newer_package:
44
+ cmd.extend(("--exclude-newer-package", exclude_newer_package))
38
45
  if constraint_file:
39
46
  cmd.extend(("--constraints", constraint_file))
40
47
  if python_platform:
@@ -119,9 +126,9 @@ def get_min_python_version_from_req(pkg_req: Requirement) -> str | None:
119
126
 
120
127
  def parse_requirement(
121
128
  line: str,
122
- exclude_newer: None | str = None,
123
- constraint_file: None | str = None,
124
- ) -> None | str | Requirement:
129
+ exclude_newer: str | None = None,
130
+ constraint_file: str | None = None,
131
+ ) -> str | Requirement | None:
125
132
  """Parse one line of a requirements.txt file."""
126
133
  line = line.strip()
127
134
  if not line or line.startswith("#"):
puc/pyprojecttoml.py CHANGED
@@ -5,6 +5,7 @@
5
5
  import subprocess
6
6
  import os
7
7
  import tomllib
8
+ import logging
8
9
  from packaging.utils import canonicalize_name
9
10
  from packaging.requirements import Requirement
10
11
 
@@ -14,15 +15,17 @@ from .dependencies import (
14
15
  get_python_platform_from_req,
15
16
  get_min_python_version_from_req,
16
17
  check_requirement,
18
+ is_newer_version,
17
19
  )
18
20
 
19
21
 
20
22
  def handle_pyproject_toml(
21
23
  pyproject_path: str,
22
- command: None | str = None,
24
+ command: str | None = None,
23
25
  packages=None,
24
- exclude_newer: None | str = None,
25
- constraint_file: None | str = None,
26
+ exclude_newer: str | None = None,
27
+ exclude_newer_package: str | None = None,
28
+ constraint_file: str | None = None,
26
29
  color: bool = True,
27
30
  ) -> int:
28
31
  """Check or update pinned dependencies of a pyproject.toml file.
@@ -53,6 +56,7 @@ def handle_pyproject_toml(
53
56
  command=command,
54
57
  packages=packages,
55
58
  exclude_newer=exclude_newer,
59
+ exclude_newer_package=exclude_newer_package,
56
60
  constraint_file=constraint_file,
57
61
  color=color,
58
62
  )
@@ -67,6 +71,7 @@ def handle_pyproject_toml(
67
71
  command=command,
68
72
  packages=packages,
69
73
  exclude_newer=exclude_newer,
74
+ exclude_newer_package=exclude_newer_package,
70
75
  constraint_file=constraint_file,
71
76
  color=color,
72
77
  )
@@ -80,6 +85,7 @@ def handle_pyproject_toml(
80
85
  command=command,
81
86
  packages=packages,
82
87
  exclude_newer=exclude_newer,
88
+ exclude_newer_package=exclude_newer_package,
83
89
  constraint_file=constraint_file,
84
90
  color=color,
85
91
  )
@@ -92,12 +98,13 @@ def update_pyproject_dependencies(
92
98
  dependencies: list[str | dict],
93
99
  project_dir: str,
94
100
  projectname: str,
95
- group: None | str = None,
101
+ group: str | None = None,
96
102
  optional=False,
97
- command: None | str = None,
103
+ command: str | None = None,
98
104
  packages=None,
99
- exclude_newer: None | str = None,
100
- constraint_file: None | str = None,
105
+ exclude_newer: str | None = None,
106
+ exclude_newer_package: str | None = None,
107
+ constraint_file: str | None = None,
101
108
  color: bool = True,
102
109
  ) -> int:
103
110
  """Update given dependency list of a pyproject.toml file."""
@@ -122,6 +129,7 @@ def update_pyproject_dependencies(
122
129
  latest_version = get_latest_version(
123
130
  pkg_req.name,
124
131
  exclude_newer=exclude_newer,
132
+ exclude_newer_package=exclude_newer_package,
125
133
  constraint_file=constraint_file,
126
134
  python_platform=get_python_platform_from_req(pkg_req),
127
135
  python_version=get_min_python_version_from_req(pkg_req),
@@ -134,6 +142,10 @@ def update_pyproject_dependencies(
134
142
  spec = next(s for s in pkg_req.specifier)
135
143
  if latest_version is not None and latest_version != spec.version:
136
144
  updatable += 1
145
+ if not is_newer_version(spec.version, latest_version):
146
+ logger.warning(
147
+ f"{pkg_req.name} latest version {latest_version} is older than specified version {spec.version}"
148
+ )
137
149
  version = (
138
150
  colorize_updated_version(spec.version, latest_version)
139
151
  if color
@@ -154,7 +166,7 @@ def update_pyproject_pkg(
154
166
  dependency: str,
155
167
  package: str,
156
168
  projectdir: str,
157
- group: None | str = None,
169
+ group: str | None = None,
158
170
  optional: bool = False,
159
171
  ) -> None:
160
172
  """Update one package in pyproject.toml."""
@@ -163,11 +175,15 @@ def update_pyproject_pkg(
163
175
  "add",
164
176
  "--project",
165
177
  projectdir,
166
- "--quiet",
167
178
  "--frozen",
168
179
  "--color=never",
169
- f"--upgrade-package={package}",
180
+ "--upgrade-package",
181
+ package,
170
182
  ]
183
+ if logger.getEffectiveLevel() <= logging.DEBUG:
184
+ command.append("--verbose")
185
+ else:
186
+ command.append("--quiet")
171
187
  if optional and group:
172
188
  command.append("--optional")
173
189
  command.append(group)
puc/requirementstxt.py CHANGED
@@ -14,6 +14,7 @@ from .dependencies import (
14
14
  get_python_platform_from_req,
15
15
  get_min_python_version_from_req,
16
16
  parse_requirement,
17
+ is_newer_version,
17
18
  )
18
19
 
19
20
 
@@ -23,10 +24,11 @@ max_rec_level = 5
23
24
 
24
25
  def handle_requirements_txt(
25
26
  requirements_txt_path: str,
26
- command: None | str = None,
27
+ command: str | None = None,
27
28
  packages=None,
28
- exclude_newer: None | str = None,
29
- constraint_file: None | str = None,
29
+ exclude_newer: str | None = None,
30
+ exclude_newer_package: str | None = None,
31
+ constraint_file: str | None = None,
30
32
  color: bool = True,
31
33
  rec_level: int = 0,
32
34
  handled_files: list[str] | None = None,
@@ -62,6 +64,7 @@ def handle_requirements_txt(
62
64
  command,
63
65
  packages=packages,
64
66
  exclude_newer=exclude_newer,
67
+ exclude_newer_package=exclude_newer_package,
65
68
  constraint_file=constraint_file,
66
69
  color=color,
67
70
  rec_level=rec_level + 1,
@@ -72,6 +75,7 @@ def handle_requirements_txt(
72
75
  latest_version = get_latest_version(
73
76
  pkg_req.name,
74
77
  exclude_newer=exclude_newer,
78
+ exclude_newer_package=exclude_newer_package,
75
79
  constraint_file=constraint_file,
76
80
  python_platform=get_python_platform_from_req(pkg_req),
77
81
  python_version=get_min_python_version_from_req(pkg_req),
@@ -88,6 +92,10 @@ def handle_requirements_txt(
88
92
  output.write(line)
89
93
  elif latest_version is not None and latest_version != spec.version:
90
94
  updatable += 1
95
+ if not is_newer_version(spec.version, latest_version):
96
+ logger.warning(
97
+ f"{pkg_req.name} latest version {latest_version} is older than specified version {spec.version}"
98
+ )
91
99
  version = (
92
100
  colorize_updated_version(spec.version, latest_version)
93
101
  if color
puc/uvlock.py CHANGED
@@ -16,10 +16,11 @@ from .dependencies import (
16
16
 
17
17
  def handle_uv_lock(
18
18
  uvlock_path: str,
19
- command: None | str = None,
19
+ command: str | None = None,
20
20
  packages=None,
21
- exclude_newer: None | str = None,
22
- constraint_file: None | str = None,
21
+ exclude_newer: str | None = None,
22
+ exclude_newer_package: str | None = None,
23
+ constraint_file: str | None = None,
23
24
  color: bool = True,
24
25
  ) -> int:
25
26
  """Check or update pinned dependencies of a uv.lock file."""
@@ -55,6 +56,7 @@ def handle_uv_lock(
55
56
  command=command,
56
57
  packages=packages,
57
58
  exclude_newer=exclude_newer,
59
+ exclude_newer_package=exclude_newer_package,
58
60
  constraint_file=constraint_file,
59
61
  color=color,
60
62
  )
@@ -67,10 +69,11 @@ def update_uvlock_dependency(
67
69
  package,
68
70
  version,
69
71
  project_dir: str,
70
- command: None | str = None,
72
+ command: str | None = None,
71
73
  packages=None,
72
- exclude_newer: None | str = None,
73
- constraint_file: None | str = None,
74
+ exclude_newer: str | None = None,
75
+ exclude_newer_package: str | None = None,
76
+ constraint_file: str | None = None,
74
77
  color: bool = True,
75
78
  ) -> int:
76
79
  """Update uv lock dependency."""
@@ -82,6 +85,7 @@ def update_uvlock_dependency(
82
85
  latest_version = get_latest_version(
83
86
  package,
84
87
  exclude_newer=exclude_newer,
88
+ exclude_newer_package=exclude_newer_package,
85
89
  constraint_file=constraint_file,
86
90
  )
87
91
  except subprocess.CalledProcessError as exc:
@@ -110,7 +114,7 @@ def update_uvlock_dependency(
110
114
  def update_uvlock_pkg(
111
115
  package: str,
112
116
  projectdir: str,
113
- exclude_newer: None | str = None,
117
+ exclude_newer: str | None = None,
114
118
  ) -> None:
115
119
  """Update one package in pyproject.toml."""
116
120
  command = [
@@ -120,7 +124,8 @@ def update_uvlock_pkg(
120
124
  projectdir,
121
125
  "--quiet",
122
126
  "--color=never",
123
- f"--upgrade-package={package}",
127
+ "--upgrade-package",
128
+ package,
124
129
  ]
125
130
  if exclude_newer:
126
131
  command.extend(
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-update-checker
3
- Version: 0.5
3
+ Version: 0.7
4
4
  License-Expression: GPL-3.0-only
5
+ Classifier: Development Status :: 4 - Beta
5
6
  Classifier: Environment :: Console
6
7
  Classifier: Intended Audience :: Developers
7
- Classifier: Development Status :: 4 - Beta
8
8
  Classifier: Operating System :: OS Independent
9
9
  Classifier: Programming Language :: Python :: 3 :: Only
10
10
  Classifier: Programming Language :: Python :: 3.11
@@ -16,21 +16,25 @@ Requires-Dist: packaging>=26.1
16
16
  Requires-Python: >=3.11
17
17
  Description-Content-Type: text/markdown
18
18
 
19
- python-update-checker
20
- ======================
19
+ # python-update-checker
20
+
21
21
  Python-update-checker (puc) checks or updates pinned dependencies
22
22
  in `pyproject.toml`, `requirements.txt` or `uv.lock` files.
23
23
 
24
- See https://github.com/astral-sh/uv/issues/6794 for a discussion
25
- about different pinning strategies.
24
+ If you are developing an application you should pin all dependencies.
25
+ When developing a library, only development dependencies should be pinned.
26
+ Since puc updates pinned dependencies, it is mostly suitable
27
+ when developing applications.
26
28
 
29
+ See [https://github.com/astral-sh/uv/issues/6794] for a discussion
30
+ about different pinning strategies.
27
31
 
28
- Features
29
- ---------
32
+ ## Features
30
33
 
31
34
  * updates pinned dependencies, ignores unpinned dependencies
32
35
  * supports pyproject.toml, uv.lock and requirements.txt formats
33
- * supports `[project.dependencies]`, `[project.optional-dependencies]` and `[dependency-groups]` in pyproject.toml
36
+ * supports `[project.dependencies]`, `[project.optional-dependencies]`
37
+ and `[dependency-groups]` in pyproject.toml
34
38
  * supports recursive references (-r) in requirements.txt formats
35
39
  * can run in check only mode, ie. it checks if updates are available
36
40
  * limit updates to specific packages
@@ -39,11 +43,18 @@ Features
39
43
  * (limited) support for environment markers, ie. `"pywin32==311; os_name=='nt'"`
40
44
  * runs on Linux, MacOS and Windows platforms
41
45
 
46
+ ## Quickstart
47
+
48
+ ```bash
42
49
 
43
- Examples
44
- ---------
50
+ uvx --from python-update-checker puc --exclude-newer "1 day" update pyproject.toml
51
+ uv sync
52
+ ```
53
+
54
+ ## Examples
45
55
 
46
56
  ```bash
57
+
47
58
  $ # check all pinned packages for updates in pyproject.toml
48
59
  $ puc check pyproject.toml
49
60
  puc INFO: check pyproject file pyproject.toml
@@ -55,6 +66,8 @@ $ puc --exclude-newer="7 days" update pyproject.toml
55
66
  puc INFO: update pyproject file pyproject.toml
56
67
  puc INFO: updating 'ty==0.0.29' --> 0.0.31
57
68
  puc INFO: Wrote 1 updated package version(s) to pyproject.toml
69
+ $ # update the project environment after upgrading pyproject.toml
70
+ $ uv sync
58
71
 
59
72
  $ # check all pinned packages for updates in requirements.txt
60
73
  $ puc check requirements.txt
@@ -65,55 +78,49 @@ puc WARNING: found update 'Django==5.2.0' --> 6.0.4
65
78
  $ # update only the django package version in requirements.txt
66
79
  $ # limit updates to django versions less than 6
67
80
  $ puc --package="Django" --constraints="Django<6" update requirements.txt
68
- INFO: update requirements file requirements.txt
69
- INFO: updating 'Django==5.2.0' --> 5.2.13
70
- INFO: Wrote 1 updated package version(s) to requirements.txt
81
+ puc INFO: update requirements file requirements.txt
82
+ puc INFO: updating 'Django==5.2.0' --> 5.2.13
83
+ puc INFO: Wrote 1 updated package version(s) to requirements.txt
71
84
  ```
72
85
 
73
- Script behaviour
74
- -----------------
86
+ ## Script behaviour
75
87
 
76
88
  The exit code of `puc check` is non-zero when updates are available.
77
89
 
78
90
  Checking a `pyproject.toml` or `uv.lock`file with `puc` should be done
79
- from the project of the `pyproject.toml` file,
80
- especially if your project relies on a [project directory](https://docs.astral.sh/uv/concepts/projects/layout/) (for example to define additional packages index in pyproject.toml).
91
+ from the directory of the `pyproject.toml` file,
92
+ especially if your project relies on a [project directory](https://docs.astral.sh/uv/concepts/projects/layout/)
93
+ (for example to define additional package indexes in pyproject.toml).
81
94
 
82
95
  After updating versions in pyproject.toml, run `uv lock --upgrade` to update
83
- the transitive dependencies in `uv.lock`.
96
+ the transitive dependencies in `uv.lock` and `uv sync` to update your
97
+ virtual environment.
84
98
 
85
- Pinned dependencies are packages with `==` or `===` constraints and no wildcards in the version.
99
+ Pinned dependencies are packages with `==` or `===` constraints
100
+ and no wildcards in the version.
86
101
 
87
-
88
- Installation
89
- -------------
102
+ ## Installation
90
103
 
91
104
  1) Install [python uv](https://docs.astral.sh/uv/getting-started/installation/)
92
- 2) Install puc with `uv pip install python-update-checker`.
93
-
105
+ 2) Install puc with `uv pip install python-update-checker`
106
+ or run with `uvx --from python-update-checker puc ...`
94
107
 
95
-
96
- Architecture
97
- -------------
108
+ ## Architecture
98
109
 
99
110
  Dependencies are
100
111
 
101
112
  * [uv](https://docs.astral.sh/uv/):
102
113
  The uv binary must be available for the script to call.
103
114
  puc uses `echo "package" | uv pip compile -` to get latest package versions.
104
- puc uses `uv add "package==<version>"` to update pyproject.toml dependencies.
115
+ puc uses `uv add "package==<version>"` to update pyproject.toml
116
+ dependencies and `uv lock --upgrade-package` to update uv.lock dependencies.
105
117
 
106
118
  * [packaging](https://packaging.pypa.io/):
107
119
  Parses dependencies with the packaging.requirements.Requirement class.
108
120
 
109
121
  puc needs Python >= 3.11 since it uses the tomllib Python module.
110
122
 
111
- puc consists of a single python script. The script uses [inline script metadata](https://peps.python.org/pep-0723/) to be executed directly with `uv run --script`.
112
- This enables simple packaging and installation.
113
-
114
-
115
- Limitations
116
- ------------
123
+ ## Limitations
117
124
 
118
125
  * No support for custom dependency formats in pyproject.toml
119
126
  (eg. `[tool.poetry.dependencies]`).
@@ -0,0 +1,11 @@
1
+ puc/__init__.py,sha256=QCJeo6rsztgAeIuufaaId2f-x_XYLjs4UywOPp4w7ks,67
2
+ puc/cli.py,sha256=mzbs7TZsuI0_PgRgIAzHRxmKDa02cBrLjtn7qTE2wwQ,7417
3
+ puc/dependencies.py,sha256=4XLPiCnulGVT29bVB6Blkh9irjUGxfChP01YqqofYTw,6717
4
+ puc/logging.py,sha256=VBojYqr7-l-aLeNqrBqTJyHuEINzdBx1CObQg5XiC-k,2222
5
+ puc/pyprojecttoml.py,sha256=pJxA9oZoxiiB7b06yr0hub7um1A1eyrKf7WgPf1KBEU,6905
6
+ puc/requirementstxt.py,sha256=xzEKVmWvZVbIQt9lZ0hVykOapn8xX24a7FixX1dY4lU,5076
7
+ puc/uvlock.py,sha256=O_y3iwJ4pfq0wtrDYJoOdmAHn2XY71N0Iql0ycrRoW0,4160
8
+ python_update_checker-0.7.dist-info/WHEEL,sha256=y6e-a5KI2W-qDAJKfh9Xr81bin8NgUdfWgz3VSXXpe4,80
9
+ python_update_checker-0.7.dist-info/entry_points.txt,sha256=mQuGfBukyjyo7ssOHSIycAlRdQkrA1ewAth6tsV_T60,38
10
+ python_update_checker-0.7.dist-info/METADATA,sha256=5rmVjEA_PA4so2oFay-ZbrocnMn7TlYWZQ_cxe1yGxE,4883
11
+ python_update_checker-0.7.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.11.11
2
+ Generator: uv 0.12.9
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,11 +0,0 @@
1
- puc/__init__.py,sha256=QCJeo6rsztgAeIuufaaId2f-x_XYLjs4UywOPp4w7ks,67
2
- puc/cli.py,sha256=aLQ52sA59lc8xAK7gjR36nTqUYxZvkvh467i0cx8Zso,6956
3
- puc/dependencies.py,sha256=7MY8fyGGGayztpQfPAyCKXnlPUABXJDF9mwqmeMEjZs,6450
4
- puc/logging.py,sha256=VBojYqr7-l-aLeNqrBqTJyHuEINzdBx1CObQg5XiC-k,2222
5
- puc/pyprojecttoml.py,sha256=TMhNEWqlRfjichuU0nVGHbBHFhYALu12DuOSyobT5oE,6179
6
- puc/requirementstxt.py,sha256=V075kYSuD35cGJ8XGdjq_24_aSUcJi43KH9ALov4rSQ,4604
7
- puc/uvlock.py,sha256=mKc3x2RhcmHzYe8PHfUQZBkJI0DzN4qpDCmOQzrYnAE,3948
8
- python_update_checker-0.5.dist-info/WHEEL,sha256=iCTolw4aw2dP3yfM-EQCGTDsFCXL_ymmbYnBRVH7plA,81
9
- python_update_checker-0.5.dist-info/entry_points.txt,sha256=mQuGfBukyjyo7ssOHSIycAlRdQkrA1ewAth6tsV_T60,38
10
- python_update_checker-0.5.dist-info/METADATA,sha256=RgatXY5cl_Oy8z2NisqECNj5msIVOv2VlEsBKdQA5Eo,4562
11
- python_update_checker-0.5.dist-info/RECORD,,