from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass, field from pathlib import Path from typing import Any @dataclass class Dependency: name: str version: str language: str file_path: Path extras: list[str] = field(default_factory=list) markers: str = "" optional: bool = False dev: bool = False indirect: bool = False license: str | None = None homepage: str | None = None repository: str | None = None @dataclass class ParsedManifest: language: str file_path: Path project_name: str | None = None project_version: str | None = None dependencies: list[Dependency] = field(default_factory=list) raw_data: dict[str, Any] = field(default_factory=dict) class Parser(ABC): language: str = "unknown" @abstractmethod def can_parse(self, file_path: Path) -> bool: pass @abstractmethod def parse(self, file_path: Path) -> ParsedManifest: pass def _create_dependency( self, file_path: Path, name: str, version: str, extras: list[str] | None = None, markers: str = "", optional: bool = False, dev: bool = False, indirect: bool = False, ) -> Dependency: return Dependency( name=name, version=version, language=self.language, file_path=file_path, extras=extras or [], markers=markers, optional=optional, dev=dev, indirect=indirect, )