pipu-cli 0.1.dev4__py3-none-any.whl → 0.1.dev6__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.
pipu_cli/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from .config import LOG_LEVEL
3
3
 
4
- __version__ = '0.1.dev4'
4
+ __version__ = '0.1.dev6'
5
5
 
6
6
 
7
7
  # Configure logging
pipu_cli/cli.py CHANGED
@@ -7,16 +7,63 @@ from .common import console
7
7
  from pip._internal.commands.install import InstallCommand
8
8
 
9
9
 
10
- def _install_packages(package_specs: List[str]) -> int:
10
+ def _install_packages(package_names: List[str], packages_being_updated: List[str] = None) -> int:
11
11
  """
12
- Install packages using pip API.
12
+ Install packages using pip API with filtered constraints.
13
13
 
14
- :param package_specs: List of package specifications to install
14
+ :param package_names: List of package names to install
15
+ :param packages_being_updated: List of package names being updated (to exclude from constraints)
15
16
  :returns: Exit code (0 for success, non-zero for failure)
16
17
  """
17
- install_cmd = InstallCommand("install", "Install packages")
18
- install_args = ["--upgrade"] + package_specs
19
- return install_cmd.main(install_args)
18
+ import tempfile
19
+ import os
20
+ from packaging.utils import canonicalize_name
21
+
22
+ # If packages_being_updated not provided, use package_names
23
+ if packages_being_updated is None:
24
+ packages_being_updated = package_names
25
+
26
+ # Get all current constraints and filter out packages being updated
27
+ from .package_constraints import read_constraints
28
+ all_constraints = read_constraints()
29
+
30
+ # Get canonical names of packages being updated
31
+ packages_being_updated_canonical = {canonicalize_name(pkg) for pkg in packages_being_updated}
32
+
33
+ # Filter out constraints for packages being updated to avoid conflicts
34
+ filtered_constraints = {
35
+ pkg: constraint
36
+ for pkg, constraint in all_constraints.items()
37
+ if pkg not in packages_being_updated_canonical
38
+ }
39
+
40
+ # Create a temporary constraints file if there are any constraints to apply
41
+ constraint_file_path = None
42
+ try:
43
+ if filtered_constraints:
44
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
45
+ constraint_file_path = f.name
46
+ for pkg, constraint in filtered_constraints.items():
47
+ f.write(f"{pkg}{constraint}\n")
48
+
49
+ # Set environment variable for pip to use the filtered constraints
50
+ os.environ['PIP_CONSTRAINT'] = constraint_file_path
51
+ console.print(f"[dim]Using filtered constraints (excluding {len(packages_being_updated_canonical)} package(s) being updated)[/dim]")
52
+
53
+ install_cmd = InstallCommand("install", "Install packages")
54
+ install_args = ["--upgrade"] + package_names
55
+ return install_cmd.main(install_args)
56
+
57
+ finally:
58
+ # Clean up: remove the constraint file and unset environment variable
59
+ if constraint_file_path:
60
+ if 'PIP_CONSTRAINT' in os.environ:
61
+ del os.environ['PIP_CONSTRAINT']
62
+ if os.path.exists(constraint_file_path):
63
+ try:
64
+ os.unlink(constraint_file_path)
65
+ except Exception:
66
+ pass # Best effort cleanup
20
67
 
21
68
 
22
69
  def launch_tui() -> None:
@@ -202,21 +249,13 @@ def update(pre, yes):
202
249
  console.print()
203
250
  console.print("[bold green]Installing updates...[/bold green]")
204
251
 
205
- # Create list of package specs to install
206
- package_specs = []
207
- for package in packages_to_update:
208
- # Check if package has a constraint that should be applied instead of latest version
209
- constraint = package.get('constraint')
210
- if constraint:
211
- # Apply the constraint instead of pinning to latest version
212
- spec = f"{package['name']}{constraint}"
213
- else:
214
- # No constraint, use latest version
215
- spec = f"{package['name']}=={package['latest_version']}"
216
- package_specs.append(spec)
252
+ # Create list of package names to install
253
+ # Use --upgrade without version pinning to allow pip's dependency resolver
254
+ # to handle interdependent packages (e.g., pydantic and pydantic-core)
255
+ package_names = [package['name'] for package in packages_to_update]
217
256
 
218
- # Install packages using pip API
219
- exit_code = _install_packages(package_specs)
257
+ # Install packages using pip API with filtered constraints
258
+ exit_code = _install_packages(package_names, packages_being_updated=package_names)
220
259
 
221
260
  if exit_code == 0:
222
261
  console.print("[bold green]✓ All packages updated successfully![/bold green]")
pipu_cli/internals.py CHANGED
@@ -787,10 +787,10 @@ def update_packages_preserving_editable(
787
787
 
788
788
  if not is_editable:
789
789
  # Regular package update
790
- if latest_version:
791
- install_cmd = [sys.executable, "-m", "pip", "install", f"{package_name}=={latest_version}"]
792
- else:
793
- install_cmd = [sys.executable, "-m", "pip", "install", "--upgrade", package_name]
790
+ # Use --upgrade instead of pinning to specific versions to allow pip's
791
+ # dependency resolver to handle interdependent packages correctly
792
+ # (e.g., pydantic and pydantic-core, boto3 and botocore)
793
+ install_cmd = [sys.executable, "-m", "pip", "install", "--upgrade", package_name]
794
794
 
795
795
  returncode, stdout, stderr = run_with_cancel(install_cmd, timeout=timeout)
796
796
 
@@ -1020,20 +1020,12 @@ class PackageUpdateScreen(ModalScreen[None]):
1020
1020
  constraint_file.close()
1021
1021
  self.app.call_from_thread(self._log_message, f"[dim]Using filtered constraints (excluding {len(packages_being_updated)} package(s) being updated)[/dim]")
1022
1022
 
1023
- # Build list of package specs to update, respecting constraints
1024
- package_specs = []
1023
+ # Build list of package names to update
1024
+ # Use --upgrade instead of pinning versions to avoid dependency conflicts
1025
+ # when updating interdependent packages (e.g., pydantic and pydantic-core)
1025
1026
  package_names = []
1026
1027
  for pkg in self.selected_packages:
1027
1028
  package_names.append(pkg["name"])
1028
- # Check if package has a constraint that should be applied instead of latest version
1029
- constraint = pkg.get('constraint')
1030
- if constraint:
1031
- # Apply the constraint instead of pinning to latest version
1032
- spec = f"{pkg['name']}{constraint}"
1033
- else:
1034
- # No constraint, use latest version
1035
- spec = f"{pkg['name']}=={pkg['latest_version']}"
1036
- package_specs.append(spec)
1037
1029
 
1038
1030
  self.app.call_from_thread(self._update_status, f"Updating {total_packages} packages...")
1039
1031
  self.app.call_from_thread(self._log_message, f"{'='*70}")
@@ -1042,8 +1034,10 @@ class PackageUpdateScreen(ModalScreen[None]):
1042
1034
  self.app.call_from_thread(self._log_message, f" ... and {len(package_names) - 5} more")
1043
1035
  self.app.call_from_thread(self._log_message, f"{'='*70}\n")
1044
1036
 
1045
- # Prepare pip command to install all packages at once with proper version specs
1046
- pip_cmd = [sys.executable, "-m", "pip", "install"] + package_specs
1037
+ # Prepare pip command to install all packages with --upgrade
1038
+ # This allows pip's dependency resolver to find compatible versions
1039
+ # for interdependent packages (e.g., pydantic requires specific pydantic-core)
1040
+ pip_cmd = [sys.executable, "-m", "pip", "install", "--upgrade"] + package_names
1047
1041
 
1048
1042
  # Set up environment with constraint file if available
1049
1043
  env = os.environ.copy()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pipu-cli
3
- Version: 0.1.dev4
3
+ Version: 0.1.dev6
4
4
  Summary: A cute Python package updater
5
5
  Author-email: Scott Arne Johnson <scott.arne.johnson@gmail.com>
6
6
  License-Expression: MIT
@@ -1,19 +1,19 @@
1
- pipu_cli/__init__.py,sha256=ftE6SwRQUnMZwrCU25nvb-X0ASkV_TPiqhURZfbbaPU,1190
2
- pipu_cli/cli.py,sha256=aCN2Fz1bWhXs8MC7kqy5GdzJggNtTdumW4PQkxKOBpg,39993
1
+ pipu_cli/__init__.py,sha256=6tnAKZMPjf830m0TO279lIHtF7_B5gnWQTiYCidkeYU,1190
2
+ pipu_cli/cli.py,sha256=4pZh9kh0JO8FRbDBewVUJWt8iQrEC5w4AylOghYWkd4,41838
3
3
  pipu_cli/common.py,sha256=g5krfXFsvVJpOf87Vw4DGi5WIduDgMlRuONKXqO328M,78
4
4
  pipu_cli/config.py,sha256=xsfNU4ORAujla_FGfsMKpxy7QTpd_bJhRF_u4IPKLW0,3635
5
- pipu_cli/internals.py,sha256=u8J2df2rirOSgpeX3yp3ZHRLWyiqm7cMgo6TRFE8shU,35032
5
+ pipu_cli/internals.py,sha256=m_aF-yrOT5UJt54vv6X2gEukgokFXkz0m9SAKRofir0,35101
6
6
  pipu_cli/package_constraints.py,sha256=6LSFlC93HNIFym7dYkfYn0fsOic6QDe1ADyghK94Pk8,93052
7
7
  pipu_cli/thread_safe.py,sha256=zdQyCoMVJW73MC-d1pL_4ZO-K4AwkI0JeVyQsd8x7nY,7545
8
8
  pipu_cli/utils.py,sha256=ijSHKVuKbjmRbj2RwD9S1606PeY4oDiutzhutpX25wM,5842
9
9
  pipu_cli/ui/__init__.py,sha256=nCb_3G_vZXy5_Or9z9r-3XhYV1ppUR1r7nMZ9_6Srwg,1432
10
10
  pipu_cli/ui/apps.py,sha256=ltH24sg-3nqVpoomgCwhVYuAwq3hBUwYRH60JXtV2Yg,59771
11
11
  pipu_cli/ui/constants.py,sha256=HBPf4KYWHiT18c7ciQ0HeI7gZE3VIFOT0uobLU8YxQA,445
12
- pipu_cli/ui/modal_dialogs.py,sha256=_Q6BIJBX9l6CpqDILH3WqPfKYMqRlDnMLNUelIhZdUM,48248
12
+ pipu_cli/ui/modal_dialogs.py,sha256=-Trh60n2mev6Pr-aIvetJHnXqqoJaVDmA3c8xH_xePM,47974
13
13
  pipu_cli/ui/table_widgets.py,sha256=PC0CqqrK3KgMbTCYRPG01lxkEtRBz9xr9PN8EzoObz8,14322
14
- pipu_cli-0.1.dev4.dist-info/licenses/LICENSE,sha256=q6TxVbSI0WMB9ulF2V0FWQfeA5om3d-T9X7QwuhdiYE,1075
15
- pipu_cli-0.1.dev4.dist-info/METADATA,sha256=jSrp9kzQLwM6zr60AwSeiiZ6eqpBD1TK0IsoWLwQPSs,13200
16
- pipu_cli-0.1.dev4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- pipu_cli-0.1.dev4.dist-info/entry_points.txt,sha256=VSv6od00zOPblnFPflNLaci4jBtQIgLYJjL1BKxLz_o,42
18
- pipu_cli-0.1.dev4.dist-info/top_level.txt,sha256=z3Yce93-jGQjGRpsGZUZvbS8osh3OyS7MVpzG0uBE5M,9
19
- pipu_cli-0.1.dev4.dist-info/RECORD,,
14
+ pipu_cli-0.1.dev6.dist-info/licenses/LICENSE,sha256=q6TxVbSI0WMB9ulF2V0FWQfeA5om3d-T9X7QwuhdiYE,1075
15
+ pipu_cli-0.1.dev6.dist-info/METADATA,sha256=JqoGCM76nI14oiMrjwdvm2HjNRbVWQagOuxa_Q5ybsM,13200
16
+ pipu_cli-0.1.dev6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ pipu_cli-0.1.dev6.dist-info/entry_points.txt,sha256=VSv6od00zOPblnFPflNLaci4jBtQIgLYJjL1BKxLz_o,42
18
+ pipu_cli-0.1.dev6.dist-info/top_level.txt,sha256=z3Yce93-jGQjGRpsGZUZvbS8osh3OyS7MVpzG0uBE5M,9
19
+ pipu_cli-0.1.dev6.dist-info/RECORD,,