@@ -441,6 +441,39 @@ def _resolve_and_update_lockfile(
441441 return upgrade_lock_data
442442
443443
444+ def _clean_unused_dependencies (
445+ project , lockfile , category , full_lock_resolution , original_lockfile
446+ ):
447+ """
448+ Remove dependencies that are no longer needed after an upgrade.
449+
450+ Args:
451+ project: The project instance
452+ lockfile: The current lockfile being built
453+ category: The category to clean (e.g., 'default', 'develop')
454+ full_lock_resolution: The complete resolution of dependencies
455+ original_lockfile: The original lockfile before the upgrade
456+ """
457+ if category not in lockfile or category not in original_lockfile :
458+ return
459+
460+ # Get the set of packages in the new resolution
461+ resolved_packages = set (full_lock_resolution .keys ())
462+
463+ # Get the set of packages in the original lockfile for this category
464+ original_packages = set (original_lockfile [category ].keys ())
465+
466+ # Find packages that were in the original lockfile but not in the new resolution
467+ unused_packages = original_packages - resolved_packages
468+
469+ # Remove unused packages from the lockfile
470+ for package_name in unused_packages :
471+ if package_name in lockfile [category ]:
472+ if project .s .is_verbose ():
473+ err .print (f"Removing unused dependency: { package_name } " )
474+ del lockfile [category ][package_name ]
475+
476+
444477def upgrade (
445478 project ,
446479 pre = False ,
@@ -456,6 +489,11 @@ def upgrade(
456489):
457490 """Enhanced upgrade command with dependency conflict detection."""
458491 lockfile = project .lockfile ()
492+ # Store the original lockfile for comparison later
493+ original_lockfile = {
494+ k : v .copy () if isinstance (v , dict ) else v for k , v in lockfile .items ()
495+ }
496+
459497 if not pre :
460498 pre = project .settings .get ("allow_prereleases" )
461499
@@ -504,6 +542,8 @@ def upgrade(
504542
505543 # Process each category
506544 requested_packages = defaultdict (dict )
545+ category_resolutions = {}
546+
507547 for category in categories :
508548 pipfile_category = get_pipfile_category_using_lockfile_section (category )
509549
@@ -528,7 +568,7 @@ def upgrade(
528568 )
529569
530570 # Resolve dependencies and update lockfile
531- _resolve_and_update_lockfile (
571+ upgrade_lock_data = _resolve_and_update_lockfile (
532572 project ,
533573 requested_packages ,
534574 pipfile_category ,
@@ -540,6 +580,26 @@ def upgrade(
540580 lockfile ,
541581 )
542582
583+ # Store the full resolution for this category
584+ if upgrade_lock_data :
585+ complete_packages = project .parsed_pipfile .get (pipfile_category , {})
586+ full_lock_resolution = venv_resolve_deps (
587+ complete_packages ,
588+ which = project ._which ,
589+ project = project ,
590+ lockfile = {},
591+ pipfile_category = pipfile_category ,
592+ pre = pre ,
593+ allow_global = system ,
594+ pypi_mirror = pypi_mirror ,
595+ )
596+ category_resolutions [category ] = full_lock_resolution
597+
598+ # Clean up unused dependencies
599+ _clean_unused_dependencies (
600+ project , lockfile , category , full_lock_resolution , original_lockfile
601+ )
602+
543603 # Reset package args for next category if needed
544604 if not has_package_args :
545605 package_args = []
0 commit comments