Files
Hotel-Booking/Backend/venv/lib/python3.12/site-packages/safety/tool/poetry/parser.py
Iliyan Angelov 62c1fe5951 updates
2025-12-01 06:50:10 +02:00

135 lines
4.0 KiB
Python

from typing import Dict, Optional, Union, Set
from ..base import ToolCommandLineParser
from ..intents import Dependency, ToolIntentionType
class PoetryParser(ToolCommandLineParser):
def get_tool_name(self) -> str:
return "poetry"
def get_command_hierarchy(self) -> Dict[str, Union[ToolIntentionType, Dict]]:
"""
Allow base parser to recognize poetry commands and intentions.
"""
return {
"add": ToolIntentionType.ADD_PACKAGE,
"remove": ToolIntentionType.REMOVE_PACKAGE,
"update": ToolIntentionType.UPDATE_PACKAGE,
"install": ToolIntentionType.SYNC_PACKAGES,
"build": ToolIntentionType.BUILD_PROJECT,
"show": ToolIntentionType.LIST_PACKAGES,
"init": ToolIntentionType.INIT_PROJECT,
}
def get_known_flags(self) -> Dict[str, Set[str]]:
"""
Flags that DO NOT take a value, derived from `poetry --help` and subcommand helps.
"""
return {
"global": {
"help",
"h",
"quiet",
"q",
"version",
"V",
"ansi",
"no-ansi",
"no-interaction",
"n",
"no-plugins",
"no-cache",
"verbose",
"v",
"vv",
"vvv",
},
"add": {
"dev",
"D",
"editable",
"e",
"allow-prereleases",
"dry-run",
"lock",
},
"remove": {
"dev",
"D",
"dry-run",
"lock",
},
"update": {
"sync",
"dry-run",
"lock",
},
"install": {
"sync",
"no-root",
"no-directory",
"dry-run",
"all-extras",
"all-groups",
"only-root",
"compile",
},
"build": {
"clean",
},
}
def _parse_package_spec(
self, spec_str: str, arg_index: int
) -> Optional[Dependency]:
"""
Parse a package specification string into a Dependency object.
Handles various formats including Poetry-specific syntax and standard PEP 508 requirements.
Args:
spec_str: Package specification string (e.g. "requests>=2.25.0[security]")
Returns:
Dependency: Parsed dependency information
Raises:
ValueError: If the specification cannot be parsed
"""
try:
# TODO: This is a very basic implementation and not well tested
# our main target for now is to get the package name.
from packaging.requirements import Requirement
include_specifier = False
# Handle @ operator (package@version)
if "@" in spec_str and not spec_str.startswith("git+"):
name = spec_str.split("@")[0]
# Handle caret requirements (package^version)
elif "^" in spec_str:
name = spec_str.split("^")[0]
# Handle tilde requirements (package~version)
elif "~" in spec_str and "~=" not in spec_str:
name = spec_str.split("~")[0]
else:
# Common PEP 440 cases
name = spec_str
include_specifier = True
req = Requirement(name)
return Dependency(
name=req.name,
version_constraint=str(req.specifier) if include_specifier else None,
extras=req.extras,
arg_index=arg_index,
original_text=spec_str,
)
except Exception:
# If spec parsing fails, just ignore for now
return None