Source code for util.codescan
"""
Courier.util.codescan
~~~~~~~~~~~~~~~~~~~~~
Scans python files for unsatisfied imports.
Codescan [verb] (my definition): To scan code for unmet dependencies.
Codescan [noun] (my definition): A report of unmet dependencies.
:copyright: (c) 2023 by Joshua Rose.
:license: MIT, see LICENSE for more details.
TODO: codescan configuration file
"""
import logging
import os
import pathlib
import pkg_resources
from .package import Package
from .update import load_logging_ini
[docs]class Codescan:
"""Hold methods pertaining to the codescan function.
BUG: Some modules are not included, despite being present in project.
TODO: Optimize `local_modules` such that only working modules are called.
"""
local_modules = [d.project_name for d in pkg_resources.working_set]
if "util" in local_modules:
local_modules.remove("util")
[docs] @classmethod
def scan(cls):
"""Scan for imports in collected files.
Calls `Package.auto_install()` to fetch files matching
a given regex. `scan()` then recursively iterates through
fetched files and extracts imports. Imports are then
validated in `install_dependencies()` to ensure that
they meet the criteria for external dependencies.
:return: List of import expressions extracted from `Package.auto_install()`
:rtype: list[str]
"""
py_files: list = Package.auto_install() # pyright: ignore
dependencies = set()
folders = [i.name for i in pathlib.Path(".").rglob("*") if i.is_dir()]
for file in py_files:
if not os.path.isdir(file):
with open(str(file.resolve()), "r") as f:
for line in f.readlines():
if not line.startswith("#"):
if ("import" or ("import" and "from")) in line:
if "from" not in line.split(" "):
if line.split(" ")[1] not in folders:
dependencies.add(line.split(" ")[1])
dependency = line.split(" ")[1]
dependencies.add(dependency)
f.close()
return dependencies
[docs] @classmethod
def install_dependencies(cls):
"""Install previous dependencies collected from scan.
The scan is run within the `install_dependencies` method.
"""
dependencies = cls.scan()
for dependency in dependencies:
if dependency in Codescan.local_modules:
Package.update_package(dependency)
load_logging_ini()
logger = logging.getLogger()