Skip to content

Commit b8c1ed1

Browse files
author
PyCompiler ARK++
committed
Add venv site-packages support to package_copier module
1 parent 8b430bd commit b8c1ed1

1 file changed

Lines changed: 139 additions & 0 deletions

File tree

Core/package_copier.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
- Verify package integrity
2828
- Handle .dist-info and .egg-info metadata
2929
- Support for namespace packages
30+
- Auto-detect and copy to venv site-packages
3031
"""
3132

3233
import os
@@ -503,6 +504,96 @@ def get_statistics(self) -> Dict:
503504
"total_size_mb": round(total_size / (1024 * 1024), 2),
504505
}
505506

507+
@staticmethod
508+
def find_venv_site_packages(venv_path: Optional[str] = None) -> Optional[str]:
509+
"""
510+
Find the site-packages directory in a virtual environment.
511+
512+
Args:
513+
venv_path: Path to virtual environment. If None, uses current venv.
514+
515+
Returns:
516+
Path to site-packages directory or None.
517+
"""
518+
if venv_path is None:
519+
# Try to detect current venv
520+
venv_path = os.environ.get("VIRTUAL_ENV")
521+
if not venv_path:
522+
logger.warning("No virtual environment detected")
523+
return None
524+
525+
# Common site-packages locations
526+
possible_paths = [
527+
os.path.join(venv_path, "lib", "python3.9", "site-packages"),
528+
os.path.join(venv_path, "lib", "python3.10", "site-packages"),
529+
os.path.join(venv_path, "lib", "python3.11", "site-packages"),
530+
os.path.join(venv_path, "lib", "python3.12", "site-packages"),
531+
os.path.join(venv_path, "lib", "python3.13", "site-packages"),
532+
os.path.join(venv_path, "Lib", "site-packages"), # Windows
533+
]
534+
535+
for path in possible_paths:
536+
if os.path.isdir(path):
537+
logger.debug(f"Found venv site-packages: {path}")
538+
return path
539+
540+
logger.warning(f"Could not find site-packages in venv: {venv_path}")
541+
return None
542+
543+
def copy_to_venv(
544+
self,
545+
package_names: List[str],
546+
venv_path: Optional[str] = None,
547+
include_metadata: bool = True,
548+
skip_errors: bool = True,
549+
) -> Tuple[List[str], Dict[str, str]]:
550+
"""
551+
Copy packages to virtual environment site-packages.
552+
553+
Args:
554+
package_names: List of package names to copy.
555+
venv_path: Path to virtual environment. If None, uses current venv.
556+
include_metadata: Whether to copy metadata.
557+
skip_errors: Whether to continue on error.
558+
559+
Returns:
560+
Tuple of (copied_packages, failed_packages).
561+
"""
562+
site_packages = self.find_venv_site_packages(venv_path)
563+
if not site_packages:
564+
error_msg = "Could not find venv site-packages directory"
565+
logger.error(error_msg)
566+
return [], {name: error_msg for name in package_names}
567+
568+
logger.info(f"Copying packages to venv: {site_packages}")
569+
return self.copy_packages(package_names, site_packages, include_metadata, skip_errors)
570+
571+
def copy_to_venv_with_dependencies(
572+
self,
573+
package_names: List[str],
574+
venv_path: Optional[str] = None,
575+
include_metadata: bool = True,
576+
) -> Tuple[List[str], Dict[str, str]]:
577+
"""
578+
Copy packages and their dependencies to virtual environment.
579+
580+
Args:
581+
package_names: List of package names to copy.
582+
venv_path: Path to virtual environment. If None, uses current venv.
583+
include_metadata: Whether to copy metadata.
584+
585+
Returns:
586+
Tuple of (copied_packages, failed_packages).
587+
"""
588+
site_packages = self.find_venv_site_packages(venv_path)
589+
if not site_packages:
590+
error_msg = "Could not find venv site-packages directory"
591+
logger.error(error_msg)
592+
return [], {name: error_msg for name in package_names}
593+
594+
logger.info(f"Copying packages with dependencies to venv: {site_packages}")
595+
return self.copy_packages_with_dependencies(package_names, site_packages, include_metadata)
596+
506597

507598
def copy_package_simple(
508599
package_name: str, destination: str, source_dir: Optional[str] = None
@@ -566,6 +657,54 @@ def list_system_packages(source_dir: Optional[str] = None) -> List[str]:
566657
return []
567658

568659

660+
def copy_to_venv_simple(
661+
package_names: List[str],
662+
venv_path: Optional[str] = None,
663+
source_dir: Optional[str] = None,
664+
) -> Tuple[List[str], Dict[str, str]]:
665+
"""
666+
Simple function to copy packages to virtual environment.
667+
668+
Args:
669+
package_names: List of package names to copy.
670+
venv_path: Path to virtual environment. If None, uses current venv.
671+
source_dir: Source directory (optional).
672+
673+
Returns:
674+
Tuple of (copied_packages, failed_packages).
675+
"""
676+
try:
677+
copier = PackageCopier(source_dir=source_dir)
678+
return copier.copy_to_venv(package_names, venv_path)
679+
except Exception as e:
680+
logger.error(f"Error copying to venv: {e}")
681+
return [], {name: str(e) for name in package_names}
682+
683+
684+
def copy_to_venv_with_deps_simple(
685+
package_names: List[str],
686+
venv_path: Optional[str] = None,
687+
source_dir: Optional[str] = None,
688+
) -> Tuple[List[str], Dict[str, str]]:
689+
"""
690+
Simple function to copy packages with dependencies to virtual environment.
691+
692+
Args:
693+
package_names: List of package names to copy.
694+
venv_path: Path to virtual environment. If None, uses current venv.
695+
source_dir: Source directory (optional).
696+
697+
Returns:
698+
Tuple of (copied_packages, failed_packages).
699+
"""
700+
try:
701+
copier = PackageCopier(source_dir=source_dir)
702+
return copier.copy_to_venv_with_dependencies(package_names, venv_path)
703+
except Exception as e:
704+
logger.error(f"Error copying to venv with dependencies: {e}")
705+
return [], {name: str(e) for name in package_names}
706+
707+
569708
if __name__ == "__main__":
570709
# Example usage
571710
import argparse

0 commit comments

Comments
 (0)