[docs]classRequirementParser:""" Parse a requirements file content to resolve each requirement line as a ``PackageRequirement`` object. Multiline directive is not supported. """
[docs]defget_nested_content(self,line,basepath):""" Find the requirement file to include its content from an inclusion directive. Arguments: line (string): basepath (Path): Returns: string: The file content to include. """parts=line.split()# When there is the inclusion argument without a following requirement file# path, we just ignore the inclusion lineiflen(parts)<2:returnNonerequirement_path=basepath/Path(parts[1])ifnotrequirement_path.exists():raiseRequirementParserError("Unable to find included source: {}".format(requirement_path))returnrequirement_path.read_text()
[docs]defparse_recursive_lines(self,content,environment=None,basepath=None):""" Recursively parse requirement lines to store them as PackageRequirement objects. Inclusion directive are resolved and replaced with their requirements if basepath is given. Commentaries and empty lines (starting with ``#``) are directly filtered out at this stage. .. Warning:: There is no check about circular import in inclusions (like a ``base.txt`` requirement including ``dev.txt`` requirement which include ``base.txt``). Arguments: content (string or Path): Content to load. Either a string for the content to parse or a Path object to open and read as content to parse. Keyword Arguments: environment (dict): Environment variables as defined from `PEP 508 <https://peps.python.org/pep-0508/>` to use for marker evaluations on parsed requirement items. basepath (Path): A directory path where to search for requirement inclusions (directive ``-r foo.txt``) from requirements file. If not given inclusions will be ignored and PackageRequirement will assume it as an unsupported argument. Returns: list: List of PackageRequirement objects for all involved requirements. """ifisinstance(content,Path):content=content.read_text()resolved=[]forlineincontent.splitlines():# Always ignore empty lines and commentariesifnotline.strip()orline.strip().startswith("#"):continue# Inclusion directive to resolveelifbasepathandline.strip().startswith("-r "):inclusion=self.get_nested_content(line,basepath)ifinclusion:resolved.extend(self.parse_recursive_lines(inclusion,environment=environment,basepath=basepath))# Default behavior for everything else (that can be valid, invalid,# unsupported, etc..), package parser will take it in chargeelse:resolved.append(PackageRequirement(line.strip(),environment=environment))returnresolved
[docs]defparse_requirements(self,content,environment=None,basepath=None):""" Load content as requirements. Arguments: content (string or Path): Content to load. Either a string for the content to parse or a Path object to open and read as content to parse. Keyword Arguments: environment (dict): Environment variables as defined from `PEP 508 <https://peps.python.org/pep-0508/>` to use for marker evaluations on parsed requirement items. basepath (Path): A directory path where to search for requirement inclusions (directive ``-r foo.txt``) from requirements file. If not given inclusions will be ignored and PackageRequirement will assume it as an unsupported argument. Returns: list: List of PackageRequirement objects for all involved requirements. """# Parse each line as a requirement except empty line and commentsreturnself.parse_recursive_lines(content,environment=environment,basepath=basepath)