Repository: pantsbuild/pants

Issue:
Visibility: cannot match `python_requirements` specified at the root level
**Describe the bug**
Using the new visibility feature `__dependencies_rules__`  I cannot target a requirements file at the root project level.

Example: `//:requirements#numpy`
A workaround for now is to use a glob: `//**/:requirements#numpy`.

I think the issue is related to this line [here](https://github.com/pantsbuild/pants/blob/70a5cc8d9b4cdb93b17818f9067eb7ce088d7d24/src/python/pants/backend/visibility/glob.py#L76). I'm not sure it should remove the `//` prefix. I think the intention is to remove `./././` and `/././.` prefixes.




**Pants version**
2.16.0.dev1

**OS**
MacOS.

**Additional info**

My repo layout is:
```
core/BUILD
pants
pants.toml
requirements.in
BUILD
```

In `BUILD`:

`python_requirements` are specified as  `python_requirements(name="requirements", source="requirements.in")`




In `core/BUILD`:
Visibility is defined as:

This doesn't work:
```
__dependencies_rules__(
      (
        "*",
        "/**",
        "//:requirements#numpy",
        "!*"
      ),
)
```


This **does** work:
```
__dependencies_rules__(
      (
        "*",
        "/**",
        "//**/:requirements#numpy",
        "!*"
      ),
)
```






Discussion:

Resolving patch:
diff --git a/src/python/pants/backend/visibility/glob.py b/src/python/pants/backend/visibility/glob.py
--- a/src/python/pants/backend/visibility/glob.py
+++ b/src/python/pants/backend/visibility/glob.py
@@ -236,18 +236,18 @@ def address_path(address: Address) -> str:
         if address.is_file_target:
             return address.filename
         elif address.is_generated_target:
-            return address.spec
+            return address.spec.replace(":", "/").lstrip("/")
         else:
             return address.spec_path
 
     def match(self, address: Address, adaptor: TargetAdaptor, base: str) -> bool:
-        # type
+        # target type
         if self.type_ and not fnmatchcase(adaptor.type_alias, self.type_):
             return False
-        # path
+        # target path (includes filename for source targets)
         if self.path and not self.path.match(self.address_path(address), base):
             return False
-        # tags
+        # target tags
         if self.tags:
             # Use adaptor.kwargs with caution, unvalidated input data from BUILD file.
             target_tags = adaptor.kwargs.get("tags")
diff --git a/src/python/pants/backend/visibility/rule_types.py b/src/python/pants/backend/visibility/rule_types.py
--- a/src/python/pants/backend/visibility/rule_types.py
+++ b/src/python/pants/backend/visibility/rule_types.py
@@ -256,11 +256,7 @@ def _get_address_relpath(address: Address) -> str:
 
     @staticmethod
     def _get_address_path(address: Address) -> str:
-        if address.is_file_target:
-            return address.filename
-        if address.is_generated_target:
-            return address.spec
-        return address.spec_path
+        return TargetGlob.address_path(address)
 
     def get_action(
         self,
@@ -284,7 +280,7 @@ def get_action(
                         softwrap(
                             f"""
                             {visibility_rule.action.name}: type={adaptor.type_alias}
-                            address={address} other={other_address}
+                            address={address} [{relpath}] other={other_address} [{path}]
                             rule={str(visibility_rule)!r} {self.path}:
                             {', '.join(map(str, ruleset.rules))}
                             """


Test patch:
diff --git a/src/python/pants/backend/visibility/glob_test.py b/src/python/pants/backend/visibility/glob_test.py
--- a/src/python/pants/backend/visibility/glob_test.py
+++ b/src/python/pants/backend/visibility/glob_test.py
@@ -296,3 +296,18 @@ def test_targetglob_match(expected: bool, target_spec: str) -> None:
     adaptor = TargetAdaptor("file", None, tags=["tag-a", "tag-c"])
     address = Address(os.path.dirname(path), relative_file_path=os.path.basename(path))
     assert expected == TargetGlob.parse(target_spec, "src").match(address, adaptor, "src")
+
+
+@pytest.mark.parametrize(
+    "address, path",
+    [
+        (Address("src", relative_file_path="file"), "src/file"),
+        (Address("src", target_name="name"), "src"),
+        (Address("src", target_name="gen", generated_name="name"), "src/gen#name"),
+        (Address("", relative_file_path="file"), "file"),
+        (Address("", target_name="name"), ""),
+        (Address("", target_name="gen", generated_name="name"), "gen#name"),
+    ],
+)
+def test_address_path(address: Address, path: str) -> None:
+    assert TargetGlob.address_path(address) == path
diff --git a/src/python/pants/backend/visibility/rule_types_test.py b/src/python/pants/backend/visibility/rule_types_test.py
--- a/src/python/pants/backend/visibility/rule_types_test.py
+++ b/src/python/pants/backend/visibility/rule_types_test.py
@@ -595,7 +595,7 @@ def BUILD(dependencies: tuple = (), dependents: tuple = (), extra: str = "") ->
         expect_logged=[
             (
                 logging.DEBUG,
-                "WARN: type=target address=src/a/a2:joker other=src/a:a rule='?*' "
+                "WARN: type=target address=src/a/a2:joker [src/a/a2] other=src/a:a [src/a] rule='?*' "
                 "src/a/a2/BUILD: ?*",
             ),
         ],
@@ -617,7 +617,7 @@ def BUILD(dependencies: tuple = (), dependents: tuple = (), extra: str = "") ->
         expect_logged=[
             (
                 logging.DEBUG,
-                "DENY: type=resources address=src/a:internal other=src/b:b rule='!*' "
+                "DENY: type=resources address=src/a:internal [src/a] other=src/b:b [src/b] rule='!*' "
                 "src/a/BUILD: ., !*",
             ),
         ],
@@ -636,7 +636,7 @@ def BUILD(dependencies: tuple = (), dependents: tuple = (), extra: str = "") ->
         expect_logged=[
             (
                 logging.DEBUG,
-                "DENY: type=resources address=src/a:internal other=src/b:b rule='!*' "
+                "DENY: type=resources address=src/a:internal [src/a] other=src/b:b [src/b] rule='!*' "
                 "src/a/BUILD: ., !*",
             ),
         ],