Beispiel #1
0
def test_multiple_versions(rule_runner: RuleRunner) -> None:
    """This tests that we correctly create a new python_requirement for each unique dependency name
    in a requirements.txt file, grouping duplicated dependency names to handle multiple requirement
    strings per PEP 508."""
    file_addr = Address("", target_name="reqs", relative_file_path="requirements.txt")
    assert_python_requirements(
        rule_runner,
        "python_requirements(name='reqs')",
        dedent(
            """\
            Django>=3.2
            Django==3.2.7
            confusedmonkey==86
            repletewateringcan>=7
            """
        ),
        expected_targets={
            PythonRequirementTarget(
                {
                    "requirements": ["Django>=3.2", "Django==3.2.7"],
                    "dependencies": [file_addr.spec],
                },
                Address("", target_name="reqs", generated_name="Django"),
            ),
            PythonRequirementTarget(
                {"requirements": ["confusedmonkey==86"], "dependencies": [file_addr.spec]},
                Address("", target_name="reqs", generated_name="confusedmonkey"),
            ),
            PythonRequirementTarget(
                {"requirements": ["repletewateringcan>=7"], "dependencies": [file_addr.spec]},
                Address("", target_name="reqs", generated_name="repletewateringcan"),
            ),
            TargetGeneratorSourcesHelperTarget({"sources": ["requirements.txt"]}, file_addr),
        },
    )
def test_pipfile_lock(rule_runner: RuleRunner) -> None:
    """This tests that we correctly create a new `python_requirement` target for each entry in a
    Pipfile.lock file.

    Edge cases:
    * Develop and Default requirements are used
    * If a module_mapping is given, and the project is in the map, we set `modules`. It
      works regardless of capitalization.
    """
    assert_pipenv_requirements(
        rule_runner,
        "pipenv_requirements(module_mapping={'ANSIcolors': ['colors']})",
        {
            "default": {
                "ansicolors": {
                    "version": ">=1.18.0"
                }
            },
            "develop": {
                "cachetools": {
                    "markers": "python_version ~= '3.5'",
                    "version": "==4.1.1"
                }
            },
        },
        expected_file_dep=PythonRequirementsFile(
            {"sources": ["Pipfile.lock"]},
            Address("", target_name="Pipfile.lock")),
        expected_targets=[
            PythonRequirementTarget(
                {
                    "requirements":
                    [PipRequirement.parse("ansicolors>=1.18.0")],
                    "dependencies": [":Pipfile.lock"],
                    "modules": ["colors"],
                },
                Address("", target_name="ansicolors"),
            ),
            PythonRequirementTarget(
                {
                    "requirements": [
                        PipRequirement.parse(
                            "cachetools==4.1.1;python_version ~= '3.5'")
                    ],
                    "dependencies": [":Pipfile.lock"],
                },
                Address("", target_name="cachetools"),
            ),
        ],
    )
Beispiel #3
0
def test_pipfile_lock(rule_runner: RuleRunner) -> None:
    """This tests that we correctly create a new python_requirement_library for each entry in a
    Pipfile.lock file.

    Edge cases:

    * Develop and Default requirements are used
    * module_mapping works.
    """
    file_addr = Address("",
                        target_name="reqs",
                        relative_file_path="Pipfile.lock")
    assert_pipenv_requirements(
        rule_runner,
        "pipenv_requirements(name='reqs', module_mapping={'ansicolors': ['colors']})",
        {
            "default": {
                "ansicolors": {
                    "version": ">=1.18.0"
                }
            },
            "develop": {
                "cachetools": {
                    "markers": "python_version ~= '3.5'",
                    "version": "==4.1.1",
                    "extras": ["ring", "mongo"],
                }
            },
        },
        expected_targets={
            PythonRequirementTarget(
                {
                    "requirements": ["ansicolors>=1.18.0"],
                    "modules": ["colors"],
                    "dependencies": [file_addr.spec],
                },
                Address("", target_name="reqs", generated_name="ansicolors"),
            ),
            PythonRequirementTarget(
                {
                    "requirements":
                    ["cachetools[ring, mongo]==4.1.1;python_version ~= '3.5'"],
                    "dependencies": [file_addr.spec],
                },
                Address("", target_name="reqs", generated_name="cachetools"),
            ),
            TargetGeneratorSourcesHelperTarget({"source": "Pipfile.lock"},
                                               file_addr),
        },
    )
def test_supply_python_requirements_file(rule_runner: RuleRunner) -> None:
    """This tests that we can supply our own `_python_requirements_file`."""
    assert_pipenv_requirements(
        rule_runner,
        dedent(
            """
            pipenv_requirements(
                source='custom/pipfile/Pipfile.lock',
                pipfile_target='//:custom_pipfile_target'
            )

            _generator_sources_helper(
                name='custom_pipfile_target',
                sources=['custom/pipfile/Pipfile.lock']
            )
            """
        ),
        {"default": {"ansicolors": {"version": ">=1.18.0"}}},
        expected_file_dep=TargetGeneratorSourcesHelperTarget(
            {"sources": ["custom/pipfile/Pipfile.lock"]},
            Address("", target_name="custom_pipfile_target"),
        ),
        expected_targets=[
            PythonRequirementTarget(
                {
                    "requirements": [PipRequirement.parse("ansicolors>=1.18.0")],
                    "dependencies": ["//:custom_pipfile_target"],
                },
                Address("", target_name="ansicolors"),
            ),
        ],
        pipfile_lock_relpath="custom/pipfile/Pipfile.lock",
    )
    def generate_tgt(raw_req: str, info: dict) -> PythonRequirementTarget:
        if info.get("extras"):
            raw_req += f"[{','.join(info['extras'])}]"
        raw_req += info.get("version", "")
        if info.get("markers"):
            raw_req += f";{info['markers']}"

        parsed_req = PipRequirement.parse(raw_req)
        normalized_proj_name = canonicalize_project_name(
            parsed_req.project_name)
        tgt_overrides = overrides.pop(normalized_proj_name, {})
        if Dependencies.alias in tgt_overrides:
            tgt_overrides[Dependencies.alias] = list(
                tgt_overrides[Dependencies.alias]) + [file_tgt.address.spec]

        return PythonRequirementTarget(
            {
                **inherited_fields,
                PythonRequirementsField.alias: [parsed_req],
                PythonRequirementModulesField.alias:
                module_mapping.get(normalized_proj_name),
                PythonRequirementTypeStubModulesField.alias:
                stubs_mapping.get(normalized_proj_name),
                # This may get overridden by `tgt_overrides`, which will have already added in
                # the file tgt.
                Dependencies.alias: [file_tgt.address.spec],
                **tgt_overrides,
            },
            generator.address.create_generated(parsed_req.project_name),
        )
def test_no_compatible_resolve_error() -> None:
    python_setup = create_subsystem(PythonSetup, resolves={"a": "", "b": ""}, enable_resolves=True)
    targets = [
        PythonRequirementTarget(
            {PythonRequirementsField.alias: [], PythonResolveField.alias: "a"},
            Address("", target_name="t1"),
        ),
        PythonSourceTarget(
            {PythonSourceField.alias: "f.py", PythonResolveField.alias: "a"},
            Address("", target_name="t2"),
        ),
        PythonSourceTarget(
            {PythonSourceField.alias: "f.py", PythonResolveField.alias: "b"},
            Address("", target_name="t3"),
        ),
    ]
    assert str(NoCompatibleResolveException(python_setup, "Prefix", targets)).startswith(
        dedent(
            """\
            Prefix:

            a:
              * //:t1
              * //:t2

            b:
              * //:t3
            """
        )
    )
    def generate_tgt(
        project_name: str, parsed_reqs: Iterable[PipRequirement]
    ) -> PythonRequirementTarget:
        normalized_proj_name = canonicalize_project_name(project_name)
        tgt_overrides = overrides.pop(normalized_proj_name, {})
        if Dependencies.alias in tgt_overrides:
            tgt_overrides[Dependencies.alias] = list(tgt_overrides[Dependencies.alias]) + [
                file_tgt.address.spec
            ]

        return PythonRequirementTarget(
            {
                **inherited_fields,
                PythonRequirementsField.alias: list(parsed_reqs),
                PythonRequirementModulesField.alias: module_mapping.get(normalized_proj_name),
                PythonRequirementTypeStubModulesField.alias: stubs_mapping.get(
                    normalized_proj_name
                ),
                # This may get overridden by `tgt_overrides`, which will have already added in
                # the file tgt.
                Dependencies.alias: [file_tgt.address.spec],
                **tgt_overrides,
            },
            generator.address.create_generated(project_name),
        )
def test_source_override(rule_runner: RuleRunner) -> None:
    assert_poetry_requirements(
        rule_runner,
        "poetry_requirements(source='subdir/pyproject.toml')",
        dedent("""\
            [tool.poetry.dependencies]
            ansicolors = ">=1.18.0"
            [tool.poetry.dev-dependencies]
            """),
        pyproject_toml_relpath="subdir/pyproject.toml",
        expected_file_dep=TargetGeneratorSourcesHelperTarget(
            {"sources": ["subdir/pyproject.toml"]},
            address=Address("", target_name="subdir_pyproject.toml"),
        ),
        expected_targets=[
            PythonRequirementTarget(
                {
                    "dependencies": [":subdir_pyproject.toml"],
                    "requirements":
                    [PipRequirement.parse("ansicolors>=1.18.0")],
                },
                address=Address("", target_name="ansicolors"),
            ),
        ],
    )
def test_source_override(rule_runner: RuleRunner) -> None:
    file_addr = Address("",
                        target_name="reqs",
                        relative_file_path="subdir/pyproject.toml")
    assert_poetry_requirements(
        rule_runner,
        "poetry_requirements(name='reqs', source='subdir/pyproject.toml')",
        dedent("""\
            [tool.poetry.dependencies]
            ansicolors = ">=1.18.0"
            [tool.poetry.dev-dependencies]
            """),
        pyproject_toml_relpath="subdir/pyproject.toml",
        expected_targets={
            PythonRequirementTarget(
                {
                    "dependencies": [file_addr.spec],
                    "requirements": ["ansicolors>=1.18.0"]
                },
                address=Address("",
                                target_name="reqs",
                                generated_name="ansicolors"),
            ),
            TargetGeneratorSourcesHelperTarget(
                {"sources": ["subdir/pyproject.toml"]}, file_addr),
        },
    )
def test_multiple_versions(rule_runner: RuleRunner) -> None:
    """This tests that we correctly create a new python_requirement for each unique dependency name
    in a requirements.txt file, grouping duplicated dependency names to handle multiple requirement
    strings per PEP 508."""

    assert_python_requirements(
        rule_runner,
        "python_requirements()",
        dedent("""\
            Django>=3.2
            Django==3.2.7
            confusedmonkey==86
            repletewateringcan>=7
            """),
        expected_file_dep=TargetGeneratorSourcesHelperTarget(
            {"sources": ["requirements.txt"]},
            Address("", target_name="requirements.txt"),
        ),
        expected_targets=[
            PythonRequirementTarget(
                {
                    "dependencies": [":requirements.txt"],
                    "requirements": [
                        PipRequirement.parse("Django>=3.2"),
                        PipRequirement.parse("Django==3.2.7"),
                    ],
                },
                Address("", target_name="Django"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":requirements.txt"],
                    "requirements":
                    [PipRequirement.parse("confusedmonkey==86")],
                },
                Address("", target_name="confusedmonkey"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":requirements.txt"],
                    "requirements":
                    [PipRequirement.parse("repletewateringcan>=7")],
                },
                Address("", target_name="repletewateringcan"),
            ),
        ],
    )
def test_properly_creates_extras_requirements(rule_runner: RuleRunner) -> None:
    """This tests the proper parsing of requirements installed with specified extras."""
    assert_pipenv_requirements(
        rule_runner,
        "pipenv_requirements()",
        {
            "default": {
                "ansicolors": {
                    "version": ">=1.18.0",
                    "extras": ["neon"]
                }
            },
            "develop": {
                "cachetools": {
                    "markers": "python_version ~= '3.5'",
                    "version": "==4.1.1",
                    "extras": ["ring", "mongo"],
                }
            },
        },
        expected_file_dep=PythonRequirementsFile(
            {"sources": ["Pipfile.lock"]},
            Address("", target_name="Pipfile.lock")),
        expected_targets=[
            PythonRequirementTarget(
                {
                    "requirements":
                    [PipRequirement.parse("ansicolors[neon]>=1.18.0")],
                    "dependencies": [":Pipfile.lock"],
                },
                Address("", target_name="ansicolors"),
            ),
            PythonRequirementTarget(
                {
                    "requirements": [
                        PipRequirement.parse(
                            "cachetools[ring,mongo]==4.1.1;python_version ~= '3.5'"
                        )
                    ],
                    "dependencies": [":Pipfile.lock"],
                },
                Address("", target_name="cachetools"),
            ),
        ],
    )
Beispiel #12
0
 def create_tgt(dist: str, module: str) -> PythonRequirementTarget:
     return PythonRequirementTarget(
         {
             PythonRequirementsField.alias: (f"{dist}{version}", ),
             PythonRequirementModulesField.alias: (module, ),
             **request.template,
         },
         request.template_address.create_generated(dist),
         union_membership,
     )
Beispiel #13
0
 def create_tgt(dist: str, module: str) -> PythonRequirementTarget:
     return PythonRequirementTarget(
         {
             PythonRequirementsField.alias: (f"{dist}{version}", ),
             PythonRequirementModulesField.alias: (module, ),
             PythonRequirementResolveField.alias:
             generator[PythonRequirementResolveField].value,
         },
         generator.address.create_generated(dist),
     )
Beispiel #14
0
def test_source_override(rule_runner: RuleRunner) -> None:
    file_addr = Address("", target_name="reqs", relative_file_path="subdir/requirements.txt")
    assert_python_requirements(
        rule_runner,
        "python_requirements(name='reqs', source='subdir/requirements.txt')",
        "ansicolors>=1.18.0",
        requirements_txt_relpath="subdir/requirements.txt",
        expected_targets={
            PythonRequirementTarget(
                {"requirements": ["ansicolors>=1.18.0"], "dependencies": [file_addr.spec]},
                Address("", target_name="reqs", generated_name="ansicolors"),
            ),
            TargetGeneratorSourcesHelperTarget({"sources": ["subdir/requirements.txt"]}, file_addr),
        },
    )
def test_source_override(rule_runner: RuleRunner) -> None:
    assert_python_requirements(
        rule_runner,
        "python_requirements(source='subdir/requirements.txt')",
        "ansicolors>=1.18.0",
        requirements_txt_relpath="subdir/requirements.txt",
        expected_file_dep=TargetGeneratorSourcesHelperTarget(
            {"sources": ["subdir/requirements.txt"]},
            Address("", target_name="subdir_requirements.txt"),
        ),
        expected_targets=[
            PythonRequirementTarget(
                {
                    "dependencies": [":subdir_requirements.txt"],
                    "requirements":
                    [PipRequirement.parse("ansicolors>=1.18.0")],
                },
                Address("", target_name="ansicolors"),
            ),
        ],
    )
Beispiel #16
0
    def generate_tgt(parsed_req: PipRequirement) -> PythonRequirementTarget:
        normalized_proj_name = canonicalize_project_name(parsed_req.project_name)
        tgt_overrides = overrides.pop(normalized_proj_name, {})
        if Dependencies.alias in tgt_overrides:
            tgt_overrides[Dependencies.alias] = list(tgt_overrides[Dependencies.alias]) + [
                file_tgt.address.spec
            ]

        return PythonRequirementTarget(
            {
                **request.template,
                PythonRequirementsField.alias: [parsed_req],
                PythonRequirementModulesField.alias: module_mapping.get(normalized_proj_name),
                PythonRequirementTypeStubModulesField.alias: stubs_mapping.get(
                    normalized_proj_name
                ),
                # This may get overridden by `tgt_overrides`, which will have already added in
                # the file tgt.
                Dependencies.alias: [file_tgt.address.spec],
                **tgt_overrides,
            },
            request.template_address.create_generated(parsed_req.project_name),
            union_membership,
        )
def test_pyproject_toml(rule_runner: RuleRunner) -> None:
    """This tests that we correctly create a new python_requirement for each entry in a
    pyproject.toml file.

    Note that this just ensures proper targets are created; see prior tests for specific parsing
    edge cases.
    """
    assert_poetry_requirements(
        rule_runner,
        dedent("""\
            poetry_requirements(
                # module_mapping should work regardless of capitalization.
                module_mapping={'ansiCOLORS': ['colors']},
                type_stubs_module_mapping={'Django-types': ['django']},
            )
            """),
        dedent("""\
            [tool.poetry.dependencies]
            Django = {version = "3.2", python = "3"}
            Django-types = "2"
            Un-Normalized-PROJECT = "1.0.0"
            [tool.poetry.dev-dependencies]
            ansicolors = ">=1.18.0"
            """),
        expected_file_dep=TargetGeneratorSourcesHelperTarget(
            {"sources": ["pyproject.toml"]},
            address=Address("", target_name="pyproject.toml"),
        ),
        expected_targets=[
            PythonRequirementTarget(
                {
                    "dependencies": [":pyproject.toml"],
                    "requirements":
                    [PipRequirement.parse("ansicolors>=1.18.0")],
                    "modules": ["colors"],
                },
                address=Address("", target_name="ansicolors"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":pyproject.toml"],
                    "requirements": [
                        PipRequirement.parse(
                            "Django==3.2 ; python_version == '3'")
                    ],
                },
                address=Address("", target_name="Django"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":pyproject.toml"],
                    "requirements": [PipRequirement.parse("Django-types==2")],
                    "type_stub_modules": ["django"],
                },
                address=Address("", target_name="Django-types"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":pyproject.toml"],
                    "requirements":
                    [PipRequirement.parse("Un_Normalized_PROJECT == 1.0.0")],
                },
                address=Address("", target_name="Un-Normalized-PROJECT"),
            ),
        ],
    )
Beispiel #18
0
def test_requirements_txt(rule_runner: RuleRunner) -> None:
    """This tests that we correctly create a new python_requirement for each entry in a
    requirements.txt file, where each dependency is unique.

    Some edge cases:
    * We ignore comments and options (values that start with `--`).
    * module_mapping works regardless of capitalization.
    * Projects get normalized thanks to Requirement.parse().
    * Overrides works, including for dependencies.
    """
    file_addr = Address("",
                        target_name="reqs",
                        relative_file_path="requirements.txt")
    assert_python_requirements(
        rule_runner,
        dedent("""\
            python_requirements(
                name='reqs',
                module_mapping={'ansiCOLORS': ['colors']},
                type_stubs_module_mapping={'Django-types': ['django']},
                overrides={
                  "ansicolors": {"tags": ["overridden"]},
                  "Django": {"dependencies": ["#Django-types"]},
                },
            )
            """),
        dedent("""\
            # Comment.
            --find-links=https://duckduckgo.com
            ansicolors>=1.18.0
            Django==3.2 ; python_version>'3'
            Django-types
            Un-Normalized-PROJECT  # Inline comment.
            pip@ git+https://github.com/pypa/pip.git
            """),
        expected_targets={
            PythonRequirementTarget(
                {
                    "requirements": ["ansicolors>=1.18.0"],
                    "modules": ["colors"],
                    "dependencies": [file_addr.spec],
                    "tags": ["overridden"],
                },
                Address("", target_name="reqs", generated_name="ansicolors"),
            ),
            PythonRequirementTarget(
                {
                    "requirements": ["Django==3.2 ; python_version>'3'"],
                    "dependencies": ["#Django-types", file_addr.spec],
                },
                Address("", target_name="reqs", generated_name="Django"),
            ),
            PythonRequirementTarget(
                {
                    "requirements": ["Django-types"],
                    "type_stub_modules": ["django"],
                    "dependencies": [file_addr.spec],
                },
                Address("", target_name="reqs", generated_name="Django-types"),
            ),
            PythonRequirementTarget(
                {
                    "requirements": ["Un_Normalized_PROJECT"],
                    "dependencies": [file_addr.spec]
                },
                Address("",
                        target_name="reqs",
                        generated_name="Un-Normalized-PROJECT"),
            ),
            PythonRequirementTarget(
                {
                    "requirements":
                    ["pip@ git+https://github.com/pypa/pip.git"],
                    "dependencies": [file_addr.spec],
                },
                Address("", target_name="reqs", generated_name="pip"),
            ),
            TargetGeneratorSourcesHelperTarget({"source": "requirements.txt"},
                                               file_addr),
        },
    )
Beispiel #19
0
def test_no_compatible_resolve_error() -> None:
    python_setup = create_subsystem(PythonSetup,
                                    resolves={
                                        "a": "",
                                        "b": ""
                                    },
                                    enable_resolves=True)
    t1 = PythonRequirementTarget(
        {
            PythonRequirementsField.alias: [],
            PythonResolveField.alias: "a",
            Dependencies.alias: ["//:t3"],
        },
        Address("", target_name="t1"),
    )
    t2 = PythonSourceTarget(
        {
            PythonSourceField.alias: "f.py",
            PythonResolveField.alias: "a",
            Dependencies.alias: ["//:t3"],
        },
        Address("", target_name="t2"),
    )
    t3 = PythonSourceTarget(
        {
            PythonSourceField.alias: "f.py",
            PythonResolveField.alias: "b"
        },
        Address("", target_name="t3"),
    )

    def maybe_get_resolve(t: Target) -> str | None:
        if not t.has_field(PythonResolveField):
            return None
        return t[PythonResolveField].normalized_value(python_setup)

    bad_roots_err = str(
        NoCompatibleResolveException.bad_input_roots(
            [t2, t3],
            maybe_get_resolve=maybe_get_resolve,
            doc_url_slug="",
            workaround=None))
    assert bad_roots_err.startswith(
        softwrap("""
            The input targets did not have a resolve in common.

            a:
              * //:t2

            b:
              * //:t3

            Targets used together must use the same resolve, set by the `resolve` field.
            """))

    bad_single_dep_err = str(
        NoCompatibleResolveException.bad_dependencies(
            maybe_get_resolve=maybe_get_resolve,
            doc_url_slug="",
            root_targets=[t1],
            root_resolve="a",
            dependencies=[t3],
        ))
    assert bad_single_dep_err.startswith(
        softwrap("""
            The target //:t1 uses the `resolve` `a`, but some of its
            dependencies are not compatible with that resolve:

              * //:t3 (b)

            All dependencies must work with the same `resolve`. To fix this, either change
            the `resolve=` field on those dependencies to `a`, or change
            the `resolve=` of the target //:t1.
            """))

    bad_multiple_deps_err = str(
        NoCompatibleResolveException.bad_dependencies(
            maybe_get_resolve=maybe_get_resolve,
            doc_url_slug="",
            root_targets=[t1, t2],
            root_resolve="a",
            dependencies=[t3],
        ))
    assert bad_multiple_deps_err.startswith(
        softwrap("""
            The input targets use the `resolve` `a`, but some of their
            dependencies are not compatible with that resolve.

            Input targets:

              * //:t1
              * //:t2

            Bad dependencies:

              * //:t3 (b)

            All dependencies must work with the same `resolve`. To fix this, either change
            the `resolve=` field on those dependencies to `a`, or change
            the `resolve=` of the input targets.
            """))
def test_requirements_txt(rule_runner: RuleRunner) -> None:
    """This tests that we correctly create a new python_requirement for each entry in a
    requirements.txt file, where each dependency is unique.

    Some edge cases:
    * We ignore comments and options (values that start with `--`).
    * If a module_mapping is given, and the project is in the map, we copy over a subset of the
      mapping to the created target. It works regardless of capitalization.
    * Projects get normalized thanks to Requirement.parse().
    """
    assert_python_requirements(
        rule_runner,
        dedent("""\
            python_requirements(
                module_mapping={'ansiCOLORS': ['colors']},
                type_stubs_module_mapping={'Django-types': ['django']},
            )
            """),
        dedent("""\
            # Comment.
            --find-links=https://duckduckgo.com
            ansicolors>=1.18.0
            Django==3.2 ; python_version>'3'
            Django-types
            Un-Normalized-PROJECT  # Inline comment.
            pip@ git+https://github.com/pypa/pip.git
            """),
        expected_file_dep=TargetGeneratorSourcesHelperTarget(
            {"sources": ["requirements.txt"]},
            Address("", target_name="requirements.txt"),
        ),
        expected_targets=[
            PythonRequirementTarget(
                {
                    "dependencies": [":requirements.txt"],
                    "requirements":
                    [PipRequirement.parse("ansicolors>=1.18.0")],
                    "modules": ["colors"],
                },
                Address("", target_name="ansicolors"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":requirements.txt"],
                    "requirements":
                    [PipRequirement.parse("Django==3.2 ; python_version>'3'")],
                },
                Address("", target_name="Django"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":requirements.txt"],
                    "requirements": [PipRequirement.parse("Django-types")],
                    "type_stub_modules": ["django"],
                },
                Address("", target_name="Django-types"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":requirements.txt"],
                    "requirements":
                    [PipRequirement.parse("Un_Normalized_PROJECT")],
                },
                Address("", target_name="Un-Normalized-PROJECT"),
            ),
            PythonRequirementTarget(
                {
                    "dependencies": [":requirements.txt"],
                    "requirements": [
                        PipRequirement.parse(
                            "pip@ git+https://github.com/pypa/pip.git")
                    ],
                },
                Address("", target_name="pip"),
            ),
        ],
    )