def __call__( self, requirements_relpath: str = "requirements.txt", *, module_mapping: Optional[Mapping[str, Iterable[str]]] = None, type_stubs_module_mapping: Optional[Mapping[str, Iterable[str]]] = None, ) -> None: """ :param requirements_relpath: The relpath from this BUILD file to the requirements file. Defaults to a `requirements.txt` file sibling to the BUILD file. :param module_mapping: a mapping of requirement names to a list of the modules they provide. For example, `{"ansicolors": ["colors"]}`. Any unspecified requirements will use the requirement name as the default module, e.g. "Django" will default to `modules=["django"]`. """ req_file_tgt = self._parse_context.create_object( "_python_requirements_file", name=requirements_relpath.replace(os.path.sep, "_"), sources=[requirements_relpath], ) requirements_dep = f":{req_file_tgt.name}" normalized_module_mapping = normalize_module_mapping(module_mapping) normalized_type_stubs_module_mapping = normalize_module_mapping(type_stubs_module_mapping) req_file = Path(get_buildroot(), self._parse_context.rel_path, requirements_relpath) requirements = parse_requirements_file( req_file.read_text(), rel_path=str(req_file.relative_to(get_buildroot())) ) grouped_requirements = groupby(requirements, lambda parsed_req: parsed_req.project_name) for project_name, parsed_reqs_ in grouped_requirements: normalized_proj_name = canonicalize_project_name(project_name) req_module_mapping = ( {normalized_proj_name: normalized_module_mapping[normalized_proj_name]} if normalized_proj_name in normalized_module_mapping else {} ) req_stubs_mapping = ( {normalized_proj_name: normalized_type_stubs_module_mapping[normalized_proj_name]} if normalized_proj_name in normalized_type_stubs_module_mapping else {} ) self._parse_context.create_object( "python_requirement_library", name=project_name, requirements=list(parsed_reqs_), module_mapping=req_module_mapping, type_stubs_module_mapping=req_stubs_mapping, dependencies=[requirements_dep], )
def __call__( self, *, source: str = "requirements.txt", module_mapping: Mapping[str, Iterable[str]] | None = None, type_stubs_module_mapping: Mapping[str, Iterable[str]] | None = None, overrides: OVERRIDES_TYPE = None, ) -> None: """ :param module_mapping: a mapping of requirement names to a list of the modules they provide. For example, `{"ansicolors": ["colors"]}`. Any unspecified requirements will use the requirement name as the default module, e.g. "Django" will default to `modules=["django"]`. """ req_file_tgt = self._parse_context.create_object( "_python_requirements_file", name=source.replace(os.path.sep, "_"), sources=[source], ) requirements_dep = f":{req_file_tgt.name}" normalized_module_mapping = normalize_module_mapping(module_mapping) normalized_type_stubs_module_mapping = normalize_module_mapping( type_stubs_module_mapping) req_file = Path(get_buildroot(), self._parse_context.rel_path, source) requirements = parse_requirements_file( req_file.read_text(), rel_path=str(req_file.relative_to(get_buildroot()))) dependencies_overrides = flatten_overrides_to_dependency_field( overrides, macro_name="python_requirements", build_file_dir=self._parse_context.rel_path) grouped_requirements = groupby( requirements, lambda parsed_req: parsed_req.project_name) for project_name, parsed_reqs_ in grouped_requirements: normalized_proj_name = canonicalize_project_name(project_name) self._parse_context.create_object( "python_requirement", name=project_name, requirements=list(parsed_reqs_), modules=normalized_module_mapping.get(normalized_proj_name), type_stub_modules=normalized_type_stubs_module_mapping.get( normalized_proj_name), dependencies=[ requirements_dep, *dependencies_overrides.get(normalized_proj_name, []), ], )
def __call__( self, pyproject_toml_relpath: str = "pyproject.toml", *, module_mapping: Optional[Mapping[str, Iterable[str]]] = None, type_stubs_module_mapping: Optional[Mapping[str, Iterable[str]]] = None, ) -> None: """ :param pyproject_toml_relpath: The relpath from this BUILD file to the requirements file. Defaults to a `requirements.txt` file sibling to the BUILD file. :param module_mapping: a mapping of requirement names to a list of the modules they provide. For example, `{"ansicolors": ["colors"]}`. Any unspecified requirements will use the requirement name as the default module, e.g. "Django" will default to `modules=["django"]`. """ req_file_tgt = self._parse_context.create_object( "_python_requirements_file", name=pyproject_toml_relpath.replace(os.path.sep, "_"), sources=[pyproject_toml_relpath], ) requirements_dep = f":{req_file_tgt.name}" normalized_module_mapping = normalize_module_mapping(module_mapping) normalized_type_stubs_module_mapping = normalize_module_mapping( type_stubs_module_mapping) requirements = parse_pyproject_toml( PyProjectToml.create(self._parse_context, pyproject_toml_relpath)) for parsed_req in requirements: normalized_proj_name = canonicalize_project_name( parsed_req.project_name) req_module_mapping = ({ normalized_proj_name: normalized_module_mapping[normalized_proj_name] } if normalized_proj_name in normalized_module_mapping else {}) req_stubs_mapping = ({ normalized_proj_name: normalized_type_stubs_module_mapping[normalized_proj_name] } if normalized_proj_name in normalized_type_stubs_module_mapping else {}) self._parse_context.create_object( "python_requirement_library", name=parsed_req.project_name, requirements=[parsed_req], module_mapping=req_module_mapping, type_stubs_module_mapping=req_stubs_mapping, dependencies=[requirements_dep], )
def __call__( self, *, source: str = "pyproject.toml", module_mapping: Mapping[str, Iterable[str]] | None = None, type_stubs_module_mapping: Mapping[str, Iterable[str]] | None = None, overrides: OVERRIDES_TYPE = None, ) -> None: """ :param module_mapping: a mapping of requirement names to a list of the modules they provide. For example, `{"ansicolors": ["colors"]}`. Any unspecified requirements will use the requirement name as the default module, e.g. "Django" will default to `modules=["django"]`. """ req_file_tgt = self._parse_context.create_object( TargetGeneratorSourcesHelperTarget.alias, name=source.replace(os.path.sep, "_"), sources=[source], ) requirements_dep = f":{req_file_tgt.name}" normalized_module_mapping = normalize_module_mapping(module_mapping) normalized_type_stubs_module_mapping = normalize_module_mapping( type_stubs_module_mapping) dependencies_overrides = flatten_overrides_to_dependency_field( overrides, macro_name="python_requirements", build_file_dir=self._parse_context.rel_path) requirements = parse_pyproject_toml( PyProjectToml.deprecated_macro_create(self._parse_context, source)) for parsed_req in requirements: normalized_proj_name = canonicalize_project_name( parsed_req.project_name) self._parse_context.create_object( "python_requirement", name=parsed_req.project_name, requirements=[parsed_req], modules=normalized_module_mapping.get(normalized_proj_name), type_stub_modules=normalized_type_stubs_module_mapping.get( normalized_proj_name), dependencies=[ requirements_dep, *dependencies_overrides.get(normalized_proj_name, []), ], )
def __call__( self, requirements_relpath: str = "Pipfile.lock", module_mapping: Optional[Mapping[str, Iterable[str]]] = None, type_stubs_module_mapping: Optional[Mapping[str, Iterable[str]]] = None, pipfile_target: Optional[str] = None, ) -> None: """ :param requirements_relpath: The relpath from this BUILD file to the requirements file. Defaults to a `Pipfile.lock` file sibling to the BUILD file. :param module_mapping: a mapping of requirement names to a list of the modules they provide. For example, `{"ansicolors": ["colors"]}`. Any unspecified requirements will use the requirement name as the default module, e.g. "Django" will default to `modules=["django"]`. :param pipfile_target: a `_python_requirements_file` target to provide for cache invalidation if the requirements_relpath value is not in the current rel_path """ requirements_path = Path(get_buildroot(), self._parse_context.rel_path, requirements_relpath) lock_info = json.loads(requirements_path.read_text()) if pipfile_target: requirements_dep = pipfile_target else: requirements_file_target_name = requirements_relpath self._parse_context.create_object( "_python_requirements_file", name=requirements_file_target_name, sources=[requirements_relpath], ) requirements_dep = f":{requirements_file_target_name}" normalized_module_mapping = normalize_module_mapping(module_mapping) normalized_type_stubs_module_mapping = normalize_module_mapping( type_stubs_module_mapping) requirements = { **lock_info.get("default", {}), **lock_info.get("develop", {}) } for req, info in requirements.items(): extras = [x for x in info.get("extras", [])] extras_str = f"[{','.join(extras)}]" if extras else "" req_str = f"{req}{extras_str}{info.get('version','')}" if info.get("markers"): req_str += f";{info['markers']}" parsed_req = Requirement.parse(req_str) normalized_proj_name = canonicalize_project_name( parsed_req.project_name) req_module_mapping = ({ normalized_proj_name: normalized_module_mapping[normalized_proj_name] } if normalized_proj_name in normalized_module_mapping else {}) req_stubs_mapping = ({ normalized_proj_name: normalized_type_stubs_module_mapping[normalized_proj_name] } if normalized_proj_name in normalized_type_stubs_module_mapping else {}) self._parse_context.create_object( "python_requirement_library", name=parsed_req.project_name, requirements=[parsed_req], dependencies=[requirements_dep], module_mapping=req_module_mapping, type_stubs_module_mapping=req_stubs_mapping, )
def compute_value( # type: ignore[override] cls, raw_value: Dict[str, Iterable[str]], address: Address) -> FrozenDict[str, Tuple[str, ...]]: value_or_default = super().compute_value(raw_value, address) return normalize_module_mapping(value_or_default)
def test_normalize_module_mapping( raw_value: dict[str, Iterable[str]] | None, expected: dict[str, tuple[str, ...]] ) -> None: assert normalize_module_mapping(raw_value) == FrozenDict(expected)
def __call__( self, *, source: str = "Pipfile.lock", module_mapping: Mapping[str, Iterable[str]] | None = None, type_stubs_module_mapping: Mapping[str, Iterable[str]] | None = None, pipfile_target: str | None = None, overrides: OVERRIDES_TYPE = None, ) -> None: """ :param module_mapping: a mapping of requirement names to a list of the modules they provide. For example, `{"ansicolors": ["colors"]}`. Any unspecified requirements will use the requirement name as the default module, e.g. "Django" will default to `modules=["django"]`. :param pipfile_target: a `_python_requirements_file` target to provide for cache invalidation if the requirements_relpath value is not in the current rel_path """ requirements_path = Path(get_buildroot(), self._parse_context.rel_path, source) lock_info = json.loads(requirements_path.read_text()) if pipfile_target: requirements_dep = pipfile_target else: requirements_file_target_name = source self._parse_context.create_object( "_python_requirements_file", name=requirements_file_target_name, sources=[source], ) requirements_dep = f":{requirements_file_target_name}" normalized_module_mapping = normalize_module_mapping(module_mapping) normalized_type_stubs_module_mapping = normalize_module_mapping( type_stubs_module_mapping) dependencies_overrides = flatten_overrides_to_dependency_field( overrides, macro_name="python_requirements", build_file_dir=self._parse_context.rel_path) requirements = { **lock_info.get("default", {}), **lock_info.get("develop", {}) } for req, info in requirements.items(): extras = [x for x in info.get("extras", [])] extras_str = f"[{','.join(extras)}]" if extras else "" req_str = f"{req}{extras_str}{info.get('version','')}" if info.get("markers"): req_str += f";{info['markers']}" parsed_req = PipRequirement.parse(req_str) normalized_proj_name = canonicalize_project_name( parsed_req.project_name) self._parse_context.create_object( "python_requirement", name=parsed_req.project_name, requirements=[parsed_req], dependencies=[ requirements_dep, *dependencies_overrides.get(normalized_proj_name, []), ], modules=normalized_module_mapping.get(normalized_proj_name), type_stub_modules=normalized_type_stubs_module_mapping.get( normalized_proj_name), )