Update deps

This commit is contained in:
Sangye Ince-Johannsen 2025-01-17 22:28:41 +00:00
parent f569f1b11d
commit f7fe2ae2a5

215
deps
View file

@ -217,7 +217,6 @@ def check_library_on_pypi(library):
Returns True if 'library' is on PyPI, else False. Returns True if 'library' is on PyPI, else False.
Using urllib to avoid external dependencies. Using urllib to avoid external dependencies.
""" """
import urllib.request
url = f"https://pypi.org/pypi/{library}/json" url = f"https://pypi.org/pypi/{library}/json"
try: try:
with urllib.request.urlopen(url, timeout=5) as resp: with urllib.request.urlopen(url, timeout=5) as resp:
@ -244,92 +243,6 @@ def append_to_file(line, filename):
with open(filename, 'a') as f: with open(filename, 'a') as f:
f.write(line + '\n') f.write(line + '\n')
############################
# Subcommand: install
############################
def subcmd_install(args):
"""
If user typed exactly `deps install` or `deps install -r`, we gather imports from current dir,
check PyPI availability, and install them with conda/mamba/pip (unless --no-conda given).
Otherwise we do the normal logic of:
- installing from a requirements file with `-r req.txt`
- installing from a .py file
- installing direct package names
"""
# Check for --no-conda (remove it from args to not confuse other logic)
skip_conda = False
filtered_args = []
i = 0
while i < len(args):
if args[i] == '--no-conda':
skip_conda = True
i += 1
else:
filtered_args.append(args[i])
i += 1
args = filtered_args
# If user typed exactly: deps install (no arguments) or deps install -r (only that arg)
if not args or (args == ['-r']):
is_recursive = (args == ['-r'])
imports_found = find_imports_in_path('.', recurse=is_recursive)
if not imports_found:
print("No imports found in current directory.")
return
# Filter out those that are on PyPI
to_install = []
for lib in sorted(imports_found):
if check_library_on_pypi(lib):
to_install.append(lib)
else:
print(f"Skipping '{lib}' (not found on PyPI).")
if not to_install:
print("No PyPI-available packages found to install.")
return
print("Installing packages:", ', '.join(to_install))
for pkg in to_install:
install_package(pkg, skip_conda=skip_conda)
return
# Otherwise, normal logic with direct packages, .py files, or -r <filename>
packages_to_install = set()
i = 0
while i < len(args):
arg = args[i]
if arg == '-r':
# next arg is a requirements file
if i + 1 < len(args):
req_file = args[i + 1]
if os.path.isfile(req_file):
pkgs = process_requirements_file(req_file)
packages_to_install.update(pkgs)
else:
print(f"Requirements file not found: {req_file}")
i += 2
else:
print("Error: -r requires a file path.")
return
elif arg.endswith('.py'):
# parse imports from that script
if os.path.isfile(arg):
pkgs = process_python_file(arg)
packages_to_install.update(pkgs)
else:
print(f"File not found: {arg}")
i += 1
else:
# treat as a direct package name
packages_to_install.add(arg)
i += 1
# Install all packages in packages_to_install
for pkg in sorted(packages_to_install):
install_package(pkg, skip_conda=skip_conda)
############################ ############################
# Subcommand: ls # Subcommand: ls
############################ ############################
@ -361,6 +274,80 @@ def subcmd_ls(parsed_args):
print("\nWrote results to requirements.txt (PyPI-available) and missing-packages.txt (unavailable).") print("\nWrote results to requirements.txt (PyPI-available) and missing-packages.txt (unavailable).")
############################
# Subcommand: install
############################
def subcmd_install(parsed_args):
"""
If the user typed no direct packages/scripts or only used '-r' for recursion with no other args,
we gather imports from the current dir, check PyPI availability, and install them with conda/mamba/pip
(unless --no-conda is given).
Otherwise, if the user typed e.g. '-R <reqfile>', or a .py file, or direct package names, we handle them.
"""
skip_conda = parsed_args.no_conda
is_recursive = parsed_args.recurse
# If user typed no leftover arguments or only the recursion flag, we do the "auto-scan & install" mode
if not parsed_args.packages:
# Means: "deps install" or "deps install -r"
imports_found = find_imports_in_path('.', recurse=is_recursive)
if not imports_found:
print("No imports found in current directory.")
return
# Filter out those that are on PyPI
to_install = []
for lib in sorted(imports_found):
if check_library_on_pypi(lib):
to_install.append(lib)
else:
print(f"Skipping '{lib}' (not found on PyPI).")
if not to_install:
print("No PyPI-available packages found to install.")
return
print("Installing packages:", ', '.join(to_install))
for pkg in to_install:
install_package(pkg, skip_conda=skip_conda)
return
# Otherwise, we have leftover items: direct packages, .py files, or "-R" requirements.
leftover_args = parsed_args.packages
packages_to_install = set()
i = 0
while i < len(leftover_args):
arg = leftover_args[i]
if arg == '-R':
# next arg is a requirements file
if i + 1 < len(leftover_args):
req_file = leftover_args[i + 1]
if os.path.isfile(req_file):
pkgs = process_requirements_file(req_file)
packages_to_install.update(pkgs)
else:
print(f"Requirements file not found: {req_file}")
i += 2
else:
print("Error: -R requires a file path.")
return
elif arg.endswith('.py'):
# parse imports from that script
if os.path.isfile(arg):
pkgs = process_python_file(arg)
packages_to_install.update(pkgs)
else:
print(f"File not found: {arg}")
i += 1
else:
# treat as a direct package name
packages_to_install.add(arg)
i += 1
# Now install them
for pkg in sorted(packages_to_install):
install_package(pkg, skip_conda=skip_conda)
############################ ############################
# Main # Main
############################ ############################
@ -369,21 +356,6 @@ def main():
parser = argparse.ArgumentParser(description='deps - Manage and inspect Python dependencies.') parser = argparse.ArgumentParser(description='deps - Manage and inspect Python dependencies.')
subparsers = parser.add_subparsers(dest='subcommand', required=True) subparsers = parser.add_subparsers(dest='subcommand', required=True)
# Subcommand: install
install_parser = subparsers.add_parser(
'install',
help="Install packages or dependencies from .py files / current folder / subfolders."
)
install_parser.add_argument(
'args',
nargs=argparse.REMAINDER,
help=(
"If empty, scans current dir. If '-r' only, scans recursively. "
"Otherwise, pass script names, package names, or '-r <file>'. "
"Use --no-conda to skip mamba/conda usage."
)
)
# Subcommand: ls # Subcommand: ls
ls_parser = subparsers.add_parser( ls_parser = subparsers.add_parser(
'ls', 'ls',
@ -400,16 +372,39 @@ def main():
default='.', default='.',
help='File or directory to scan (default is current directory).' help='File or directory to scan (default is current directory).'
) )
ls_parser.set_defaults(func=subcmd_ls)
# Subcommand: install
install_parser = subparsers.add_parser(
'install',
help="Install packages or dependencies from .py files / current folder / subfolders."
)
install_parser.add_argument(
'-r', '--recurse',
action='store_true',
help="If no packages are specified, scanning current dir for imports will be recursive."
)
install_parser.add_argument(
'--no-conda',
action='store_true',
help="Skip using mamba/conda entirely and install only with pip."
)
install_parser.add_argument(
'packages',
nargs='*',
help=(
"Direct package names, .py files, or '-R <reqfile>'. If empty, scans current dir; "
"if combined with -r, scans recursively. Example usage:\n"
" deps install requests flask\n"
" deps install script.py\n"
" deps install -R requirements.txt\n"
" deps install -r (recursively scan current dir)\n"
)
)
install_parser.set_defaults(func=subcmd_install)
parsed_args = parser.parse_args() parsed_args = parser.parse_args()
parsed_args.func(parsed_args)
if parsed_args.subcommand == 'install':
# We manually parse the remainder ourselves in subcmd_install
# so we pass them as is
subcmd_install(parsed_args.args)
elif parsed_args.subcommand == 'ls':
subcmd_ls(parsed_args)
if __name__ == "__main__": if __name__ == "__main__":
main() main()