Skip to content

Commit

Permalink
add func
Browse files Browse the repository at this point in the history
  • Loading branch information
xyluo25 committed Dec 23, 2024
1 parent 20bd731 commit 09fe28a
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 10 deletions.
22 changes: 12 additions & 10 deletions pyufunc/util_magic/_import_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ def import_package(pkg_name: Union[str, tuple, list],
Args:
package_name (str): the package name, it can be a string or tuple or list.
- if it's a string, it's the package name for both installation and import.
if it's a string, it's the package name for both installation and import.
- if it's a tuple or list, it has two elements:
- first element is the package name, for pip or conda installation;
- second element is the package name, for import the package;
if it's a tuple or list, it has two elements:
first element is the package name, for pip or conda installation;
second element is the package name, for import the package;
- eg: "numpy" or "numpy==1.19.5";
- eg: ("pillow", "PIL");
- eg: ["pillow==8.3.1", "PIL"];
- eg: ["opencv-python", "cv2"];
eg: "numpy" or "numpy==1.19.5";
eg: ("pillow", "PIL");
eg: ["pillow==8.3.1", "PIL"];
eg: ["opencv-python", "cv2"];
options (list, optional): the installation optional inputs.
- eg: '--force-reinstall', '--ignore-installed'. Defaults to ["--user"].
eg: '--force-reinstall', '--ignore-installed'. Defaults to ["--user"].
verbose (bool, optional): print the error message if the package is not available.
Defaults to True.
Expand Down Expand Up @@ -297,7 +297,9 @@ def get_user_imported_module(obj: object) -> dict:
with open(obj, mode="r") as f:
file_contents = "".join(f.readlines())
imported_members = defaultdict(list)
for m, v_wb, v_nb in re.findall(pattern=r"(?:^|(?<=\n))(?:from\s+(.+?)\s+)?import\s+(?:\(((?:.|\s)*?)\)|((?:(?<!\()(?:.|\s))*?))\n", string=file_contents):
for m, v_wb, v_nb in re.findall(pattern=(r"(?:^|(?<=\n))(?:from\s+(.+?)\s+)?import\s+"
r"(?:\(((?:.|\s)*?)\)|((?:(?<!\()(?:.|\s))*?))\n"),
string=file_contents):
imported_members[m].extend(
[str_strip(v) for v in (v_wb + v_nb).split(" as ")[0].split(",")])
return imported_members
75 changes: 75 additions & 0 deletions pyufunc/util_pathio/_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pathlib import Path
import os
import re
import sys
from typing import Callable, Union
from pyufunc.pkg_configs import config_color

Expand Down Expand Up @@ -542,3 +543,77 @@ def walk(self, dirname, depth=1, print_prefix=""):
filepaths = [str(p) for p in root.glob(pattern)]
tree = Tree(filepaths=filepaths, show_all=show_all, max_level=max_level)
tree.run(str(root))


def add_pkg_to_sys_path(pkg_name: str, verbose: bool = True) -> None:
"""Automatically finds an importable Python package by its name in the current directory,
parent directories, or child directories, and adds it to the system path.
This is useful when writing test functions and needing to import a package that is not installed.
Args:
package_name (str): The name of the package to locate and add.
verbose (bool): Whether to print the process info. Defaults to True.
Location:
pyufunc/util_pathio/_path.py
Examples:
>>> import pyufunc as pf
>>> pf.add_pkg_to_sys_path('my_package', False)
Returns:
None: None
"""

# TDD: check if the package path is a string
if not isinstance(pkg_name, str):
raise ValueError("pkg_path should be a string.")

# Helper function to check if a directory is an importable Python package
def is_importable_package(path):
return os.path.isdir(path) and (
# Check for traditional package
os.path.isfile(os.path.join(path, '__init__.py'))
# Accept single-module package
or any(fname.endswith('.py') for fname in os.listdir(path))
)

# Helper function to locate the package in the directory tree
def locate_package(start_path, package_name):
for root, dirs, _ in os.walk(start_path):
if package_name in dirs:
package_path = os.path.join(root, package_name)
if is_importable_package(package_path):
return package_path
return None

# Start searching in the current directory and parent directories
current_dir = os.getcwd()
while True:
# Look for the package in the current directory and its subdirectories
package_path = locate_package(current_dir, pkg_name)
if package_path:
break
# Move to the parent directory
parent_dir = os.path.dirname(current_dir)
if parent_dir == current_dir: # Stop if we've reached the root
break
current_dir = parent_dir

# If found, add to the system path
if package_path:
absolute_path = Path(os.path.abspath(package_path))
absolute_path_parent = absolute_path.parent.absolute()

if absolute_path_parent not in sys.path:
sys.path.insert(0, str(absolute_path_parent))
if verbose:
print(f"Added {absolute_path_parent} to system path.")
else:
if verbose:
print(f"{absolute_path_parent} is already in the system path.")
return absolute_path

print(f" :Importable package '{pkg_name}' not found"
"in the current directory, parent directories, or children.")

0 comments on commit 09fe28a

Please sign in to comment.