Make find_versions aspect more robust for rules that don't define a `deps` attr

It'll still only propagate down the deps, but at least it'll fall back on not doing any propagation, rather than spuriously aborting.

Fixes #8024.

RELNOTES: None
PiperOrigin-RevId: 243859871
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/PythonSrcsVersionAspectTest.java b/src/test/java/com/google/devtools/build/lib/rules/python/PythonSrcsVersionAspectTest.java
index 5a40945..a097323 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/PythonSrcsVersionAspectTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/PythonSrcsVersionAspectTest.java
@@ -449,4 +449,28 @@
             "");
     assertThat(result).isEqualTo(golden);
   }
+
+  @Test
+  public void toleratesTargetsWithoutDepsAttr() throws Exception {
+    scratch.file(
+        "pkg/rules.bzl",
+        "def _dummy_rule_impl(ctx):",
+        "    info = PyInfo(transitive_sources = depset([]))",
+        "    return [info]",
+        "dummy_rule = rule(",
+        "    implementation = _dummy_rule_impl,",
+        ")");
+    scratch.file(
+        "pkg/BUILD",
+        "load(':rules.bzl', 'dummy_rule')",
+        "dummy_rule(",
+        "    name = 'lib',",
+        ")",
+        "py_binary(",
+        "    name = 'bin',",
+        "    srcs = ['bin.py'],",
+        "    deps = [':lib'],",
+        ")");
+    evaluateAspectFor("//pkg:bin");
+  }
 }
diff --git a/tools/python/srcs_version.bzl b/tools/python/srcs_version.bzl
index c6ea8f4..53fce79 100644
--- a/tools/python/srcs_version.bzl
+++ b/tools/python/srcs_version.bzl
@@ -176,10 +176,13 @@
             fail("Illegal state")
 
     # No good, check the direct deps' provider fields.
-    return not any([
-        _has_version_requirement(dep, version)
-        for dep in target_attr.deps
-    ])
+    if not hasattr(target_attr, "deps"):
+        return True
+    else:
+        return not any([
+            _has_version_requirement(dep, version)
+            for dep in target_attr.deps
+        ])
 
 def _empty_depswithpaths():
     """Initializes an empty `_DepsWithPathsInfo` object."""
@@ -235,11 +238,14 @@
     # Determine whether this target introduces a requirement. If so, any deps
     # that introduce that requirement are not propagated, though they might
     # still be considered top-most if an alternate path exists.
-    dep_tv_infos = [
-        d[_TransitiveVersionInfo]
-        for d in ctx.rule.attr.deps
-        if _TransitiveVersionInfo in d
-    ]
+    if not hasattr(ctx.rule.attr, "deps"):
+        dep_tv_infos = []
+    else:
+        dep_tv_infos = [
+            d[_TransitiveVersionInfo]
+            for d in ctx.rule.attr.deps
+            if _TransitiveVersionInfo in d
+        ]
 
     if not _has_version_requirement(target, "PY2"):
         new_py2 = _empty_depswithpaths()