Skip to content

Instantly share code, notes, and snippets.

@nicksspirit
Last active June 24, 2023 04:28
Show Gist options
  • Select an option

  • Save nicksspirit/c5ad35610e06b3f2085da310b13dc3e3 to your computer and use it in GitHub Desktop.

Select an option

Save nicksspirit/c5ad35610e06b3f2085da310b13dc3e3 to your computer and use it in GitHub Desktop.
Gist of python programs that can be remotely executed
"""
Command Line tool that provides compatibility between poetry and cyclonus docker scans
"""
import argparse
import sys
from contextlib import contextmanager
from itertools import chain
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
import tomli
MaybeDict = Union[Dict, None]
Extras = Optional[List[str]]
Dependencies = Iterable[Tuple[str, Union[str, Dict[str, Any]]]]
@contextmanager
def toml_handler(toml_file: Path):
"""Context manager to handle common errors working with toml.
Args:
toml_file (Path): pyproject.toml file.
"""
try:
toml_text = toml_file.read_text()
toml_dict = toml.loads(toml_text)
yield toml_dict
except toml.TomlDecodeError as exc:
print(f"TOML File Not Valid: {toml_file.absolute()}")
print(exc)
sys.exit(1)
def _to_requirement_txt(name: str, version: str, extras: Extras = None) -> str:
"""Formats package name and version into a valid requirements.txt
package version specifier.
Args:
name (str): Name of the package
version (str): Version of the package specified in pyproject.toml
extras (Extras, optional): Extra packages for the package. Defaults to None.
Returns:
str: Valid requirement.txt package dependency specifier
"""
result = ""
if extras:
name = f"{name}[{','.join(extras)}]"
if version.startswith("~"):
result = f"{name}~={version.strip('~')}"
elif version.startswith("^"):
result = f"{name}=={version.strip('^')}"
elif version.startswith(">") or version.startswith("<"):
result = f"{name}{version}"
else:
result = f"{name}=={version}"
return result
def export_toplevel_dependencies(toml_file: Path):
"""Exports the top level dependencies defined in pyproject.toml's
main group to a requirements.txt format.
Args:
toml_file (Path): pyproject.toml file.
"""
with toml_handler(toml_file) as toml_dict:
base_poetry_dict: Dict = toml_dict.get("tool", {}).get("poetry", {})
main_dependency_dict: Dict = base_poetry_dict.get("dependencies", {})
if not main_dependency_dict:
print(
"Dependencies Not Found: Did you forget to add dependencies via poetry add?"
)
sys.exit(1)
dependencies: Dependencies = main_dependency_dict.items()
requirements_txt = toml_file.parent / "requirements.txt"
requirements_txt.touch(exist_ok=True)
with open(requirements_txt, mode="w", encoding="utf-8") as file:
for package_name, package_data in dependencies:
if package_name == "python":
continue
if isinstance(package_data, dict):
package_extras = package_data.get("extras", [])
package_version = package_data["version"]
else:
package_extras = []
package_version = package_data
# Write the formated result to file
package_dependency = _to_requirement_txt(
package_name, package_version, package_extras
)
file.write(package_dependency + "\n")
def main() -> None:
parser = argparse.ArgumentParser("poetry-tools")
parser.add_argument(
"toml_config",
metavar="pyproject.toml",
default=".",
nargs="?",
help="Path to poetry's pyproject.toml file.",
type=Path,
)
parser.add_argument(
"--export-toplevel",
action="store_true",
help=(
"Exports the top-level dependencies from poetry pyproject.toml's "
"main group to a requirement.txt format"
),
)
cmd_args = parser.parse_args()
toml_file: Path = cmd_args.toml_config
is_export_toplevel: bool = cmd_args.export_toplevel
if toml_file.is_dir() or not toml_file.exists():
print(f"TOML File Not Found: {toml_file.absolute()}")
parser.print_usage()
sys.exit(1)
if is_export_toplevel:
export_toplevel_dependencies(toml_file)
if __name__ == "__main__":
main()
setenv PYTHONPATH ./.venv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment