I'm struggling to get my dependency injection &amp...
# plugins
p
I'm struggling to get my dependency injection & inference working in my
stevedore_extensions
plugin. https://github.com/st2sandbox/st2/tree/pants/pants-plugins/stevedore_extensions There are two pieces. 1. I have a
stevedore_extension
target with an
entry_points
field. That target should have python deps based on those entry_points using the
inject_stevedore_entry_points_dependencies
rule. But, when I do
./pants dependencies contrib/runners/noop_runner:runner
(where runner is the name of my stevedore_extension target), I get nothing. 2. I added a
stevedore_namespaces
field to the
python_tests
target. Each
stevedore_extension
target declares that it implements one stevedore
namespace
and this
stevedore_namespaces
field should infer additional dependencies for that test by going from namespace to the extension targets that implement the namespace, and by depending on those stevedore_extension targets, they should also get transitive dependencies on the modules that implement the relevant entry points. That should happen via the
infer_stevedore_dependencies
rule. But if I do
./pants dependees contrib//runners/noop_runner:runner
it does not list the python_tests target where I added my
stevedore_namespaces
field. So, can anyone help me debug where I'm going wrong wiring all of this up?
h
side note, using
await Get
in a
for
loop is almost always not ideal for
target_types_rules.py
110-111. It means you run sequentially when it could be concurrent. I recommend instead using
await MultiGet
right before, like this: https://github.com/pantsbuild/pants/blob/5e0c5859b7e7868b26ed83d80fe16ab6a756a9c2/src/python/pants/backend/python/dependency_inference/rules.py#L148-L164
👍 1
Ah ha, this is the issue for #1 I think: https://github.com/st2sandbox/st2/blob/a9ff6a5713cdb5a3f70e8da3b6ea3c068c6880ec/pants-plugins/stevedore_extensions/target_types_rules.py#L85 Note that you need a
Dependencies
field for
StevedoreExtension
target, and it needs to subclass
Dependencies
so that you can set
inject_for
the right way
For
python_tests
, use dependency injection instead of dependency inference, given that you don't need to look at the
sources
field for this to work Set
inject_for
to
PythonTestsDependencies
from
pants.backend.python.target_types
p
K. so would you add a dummy
Dependencies
field on
StevedoreExtension
target similar to how I added the dummy sources field? (dummy sources field was for the codegen bit)
h
Yeah, although it isn't quite as much of a dummy field - the
StevedoreExtension
target does in fact have dependencies on the relevant
python_library
target You can choose to make the
Dependencies
alias
be private if you want to exclusively rely on your dependency injection rule and not have the field show up with
./pants help
, though, if you'd like
p
private = prefix it with
_
?
h
yeah, Pants hides those fields from
./pants help
. (Altho nothing stops a user from putting in in the BUILD file)
p
woohoo, it's calling my inject_stevedore_entry_points_dependencies rule!
🤘 1
h
Awesome! Is the
python_tests
injection working now too?
p
working on it.
Copy code
original_tgt = await Get(WrappedTarget, Address, request.dependencies_field.address)
namespaces: StevedoreNamespacesField = original_tgt[StevedoreNamespacesField]
So
request.dependencies_field
is
PythonTestsDependencies
which lets me retrieve the
original_tgt
which is a
PythonTests
target. Not all
python_tests
will have my plugin injected field, so is this still the right way to get the field?
target[PluginField]
Or would I need to do
target.has_field()
?
Copy code
original_tgt = await Get(WrappedTarget, Address, request.dependencies_field.address)
    if not original_tgt.has_field(StevedoreNamespacesField):
        return InjectedDependencies()
    namespaces: StevedoreNamespacesField = original_tgt[StevedoreNamespacesField]
like that?
h
Exactly. You can either use
target.has_field()
to early return, or use
target.get(PluginField)
to get a default instance of the field: https://www.pantsbuild.org/docs/rules-api-and-target-api#how-to-read-values-from-a-target
Yeah, that looks good. I think that's better than
target.get()
b/c it's more explicit what your intent is
p
Hmm. Except that that field is now on all PythonTests targets with a None value. Guess I need to do the None check instead.
h
Ah ha, true. So, then I recommend the predicate be
bool(tgt.get(MyField).value)
or
tgt.get(MyField).value is not None
p
boom. That worked 🙂
🚀 1
Here's the largest of those stevedore_extensions definitions: https://github.com/st2sandbox/st2/blob/pants/contrib/runners/orquesta_runner/BUILD
👀 1
🚀 1