-
-
Notifications
You must be signed in to change notification settings - Fork 779
Add pants-plugins/stevedore_extensions to add teach pants' dependency inference about our runtime-loaded plugins
#5869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
pants-plugins/stevedore_extensions to add teach pants' dependency inference about our runtime-loaded plugins
138135c to
f06f8c1
Compare
amanda11
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few queries.
pants-plugins/stevedore_extensions/python_target_dependencies.py
Outdated
Show resolved
Hide resolved
| async def resolve_stevedore_entry_points( | ||
| request: ResolveStevedoreEntryPointsRequest, | ||
| ) -> ResolvedStevedoreEntryPoints: | ||
| # based on: pants.backend.python.target_types_rules.resolve_pex_entry_point |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
b4515dd to
0eb1354
Compare
|
Rebased on master |
amanda11
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy with the changes, just the change on the comment as per suggestion to add.
pants-plugins/stevedore_extensions/python_target_dependencies.py
Outdated
Show resolved
Hide resolved
Targets other than python_tests will get stevedore_namespaces fields later.
This should improve error messages to make it easier to identify any issues.
and fix a bug identified by the test (Dependencies field was missing).
to better reflect the purpose of rules in that file
3731eec to
45cb023
Compare
|
rebased |
This backend provides dependency inference for apps that use openstack/stevedore to load plugins at runtime. This was originally developed for the StackStorm project: StackStorm/st2#5869
|
I submitted pantsbuild/pants#18132 to try and get this plugin into upstream pants instead of in our repo. In doing that I realized I could vastly simplify it, so I did a major refactor. Even if it's not accepted upstream, the new version of the plugin will be easier to review with fewer and smaller PRs to get it all in. I'm marking this as draft until I see where the upstreaming effort lands. |
This adds `pants.backend.python.framework.stevedore`. This was originally developed for the StackStorm project in StackStorm/st2#5869 but it seems general enough to include in pants itself. Other people on [slack](https://pantsbuild.slack.com/archives/C01CQHVDMMW/p1674865736900199) agree, so here's the PR. ## What is openstack/stevedore? Python projects can use [openstack/stevedore](https://github.com/openstack/stevedore) for dynamic (discovered at runtime) extensions/plugins. I find this [page in the stevedore docs](https://docs.openstack.org/stevedore/latest/user/tutorial/naming.html) to be most helpful in understanding what stevedore does. Here are some of the key points: > Stevedore uses setuptools entry points to define and load plugins. An entry point is standard way to refer to a named object defined inside a Python module or package. The name can be a reference to any class, function, or instance, as long as it is created when the containing module is imported (i.e., it needs to be a module-level global). > > Entry points are registered using a _name_ in a _namespace_. > > Entry point names are usually considered user-visible. ... Because they are public, names are typically as short as possible while remaining descriptive. ... > > Namespaces, on the other hand, are an implementation detail, and while they are known to developers they are not usually exposed to users. The namespace naming syntax looks a lot like Python’s package syntax (*a.b.c*) but _namespaces do not correspond to Python packages._ ... > > Each namespace is owned by the code that consumes the plugins and is used to search for entry points. ... ## About the stevedore pants plugin The primary focus of this plugin is to facilitate testing projects that use `openstack/stevedore` by adding the extensions/plugins to the pytest sandbox and ensuring they are "discoverable" by stevedore. ### How does this plugin facilitate testing code that uses stevedore? Since a stevedore extension does not use the python import system, pants does not know how to infer dependencies on any of this code. We need to extend the dependency inference system to teach it how to handle stevedore extensions. This PR adds a pants plugin that strives to accomplish that by allowing us to: - use `python_distribution(entry_points={...}, ...)` to define the stevedore namespaces and plugins, - differentiate namespaces in the `entry_points` field with a special `stevedore_namespace` object. - use `stevedore_namespaces` fields to record dependencies on extensions in the given namespaces. So far, I've only added the `stevedore_namespaces` field to the `python_test` and `python_tests` targets as testing has been my primary focus. We could add it to other targets later if anyone finds that helpful. When a target has the `stevedore_namespaces` field, this plugin will: 1. look up all of the `python_distribution` targets with an `entry_points` field that have `stevedore_namespace` tagged keys. - [`@rule python_target_dependencies.find_all_python_distributions_with_any_stevedore_entry_points`](https://github.com/pantsbuild/pants/pull/18132/files#diff-f50253674b1c85da837a8a04c18c23cad6dec5220b6b8a1ac62838e40346e01dR56) - [`@rule python_target_dependencies.map_stevedore_extensions`](https://github.com/pantsbuild/pants/pull/18132/files#diff-f50253674b1c85da837a8a04c18c23cad6dec5220b6b8a1ac62838e40346e01dR85) - [`@rule python_target_dependencies.find_python_distributions_with_entry_points_in_stevedore_namespaces`](https://github.com/pantsbuild/pants/pull/18132/files#diff-f50253674b1c85da837a8a04c18c23cad6dec5220b6b8a1ac62838e40346e01dR103) 2. add/infer dependencies from the test targets to all of the python code that provides the entry points in the required namespaces; in other words, we infer dependencies on a subset of the `python_distribution` target, not on the `python_distribution` target itself. - [`@rule python_target_dependencies.infer_stevedore_namespace_dependencies`](https://github.com/pantsbuild/pants/pull/18132/files#diff-f50253674b1c85da837a8a04c18c23cad6dec5220b6b8a1ac62838e40346e01dR142) 3. generate a `{module_path}.egg-info/entry_points.txt` file in the pytest sandbox for each relevant `python_distribution` target (the `entry_points.txt` file will only contain entry_points for the required namespaces). - [`@rule rules.generate_entry_points_txt_from_stevedore_extension`](https://github.com/pantsbuild/pants/pull/18132/files#diff-1d487c2b704cac1a36e9398cc29dd75e5601535e53224f67923f641c8c320a4eR42) For example, if an project used the namespace `st2common.runners.runner`, then we could set `stevedore_namespaces=["st2common.runners.runner"]` on a `python_tests()` target. Then pants will include all of he python code that provides the named entry points in those namespaces. And then the generated `entry_points.txt` files make that python code appear to be "installed" (not just added to PYTHONPATH), thus allowing stevedore to discover the entry points and load the plugins during the tests.
|
Woohoo! This was merged upstream: pantsbuild/pants#18132 I will revisit this once there is a pants release we can use (prob dev or rc) that includes this plugin. Then we'll be able to add all the stevedore entry points metadata without adding the plugin. In the meantime, I plan to add the |
Background
This is another part of introducing pants, as discussed in various TSC meetings.
Related PRs can be found in:
Overview of this PR
We use openstack/stevedore for several dynamic (discovered at runtime) StackStorm plugins. We use this to load:
Since a stevedore extension does not use the python import system, pants does not know how to infer dependencies on any of this code. We need to extend the dependency inference system to teach it how to handle stevedore extensions. This PR adds a pants plugin that strives to accomplish that by allowing us to:
stevedore_extensiontargets to inform pants about what code is required for a given extension (where each extension is identified by a stevedore namespace and a plugin name), andstevedore_namespacefields to record dependencies on extensions in the given namespace.When a target has the
stevedore_namespacefield, this plugin will add dependencies on all of thestevedore_extensiontargets that define plugins in that namespace. For example, that means that pants will include all of our runners whenever code depends on thest2common.runners.runnernamespace.Scope of this PR
This PR only adds the
stevedore_extensiontarget and adds thestevedore_namespacefield to thepython_testsandpython_testtargets.After adding the dependency inference (in this PR) there is one more thing required for
python_testtargets to successfully get access, via stevedore, to the relevant python code. We need to generate anentry_points.txtfile. We will include that in the next PR, which you can preview at: pants-plugins-stevedore_extensions...pants-plugins-stevedore_extensions-entry_points_txtAnother follow-up PR will also add the
stevedore_namespacesfield topython_distributiontargets (a wheel is a distribution). If you want a preview of that PR, you can look at: pants-plugins-stevedore_extensions-entry_points_txt...pants-plugins-stevedore_extensions-setup_pyNote, also, that I have not enabled the plugin yet:
st2/pants.toml
Line 30 in 7148058
That keeps this PR focused on the plugin itself including adding tests for it. A third follow-up PR will add the
stevedore_extensiontarget andstevedore_namespacesfield metadata to our BUILD files. If you want to explore some of that metadata, you can look at: pants-plugins-stevedore_extensions-setup_py...pants-stevedore_extensionsstevedore_extensiontargetIn the plugin, the
stevedore_extensiontarget is defined here:st2/pants-plugins/stevedore_extensions/target_types.py
Lines 124 to 132 in 7148058
There are several fields on this target. In this example BUILD file, we see three fields:
name,namespace, andentry_points. (Yes, there are other fields available on the target. But, those are only needed for other pants features; we won't use them in our BUILD files.)st2/contrib/runners/noop_runner/BUILD
Lines 1 to 7 in b0d27d8
Look in
target_types.pyto see the definition of thenamespace(StevedoreNamespaceField) andentry_points(StevedoreEntryPointsField) fields. In particular, please review the help text for each of these fields.stevedore_namespacesfield (onpython_tests/python_testtargets)In the plugin, the
stevedore_namespacesfield is defined here:st2/pants-plugins/stevedore_extensions/target_types.py
Lines 136 to 147 in 7148058
When we identify tests that need particular stevedore extensions, we list the required namespaces in BUILD files like this:
st2/st2common/tests/unit/BUILD
Lines 6 to 13 in b0d27d8
In this example, the unit tests get a dependency on all of the runners.
Dependency inference rules
To make dependency inference add these dependencies, the pants plugin adds several rules.
Dependencies on
stevedore_extensiontargetsStarting with the inferred dependencies, and going backwards in the rule graph, here are the rules to infer dependencies on
stevedore_extensiontargets.st2/pants-plugins/stevedore_extensions/python_dependency_injection.py
Lines 79 to 86 in 7148058
This rule needs
StevedoreExtensionswhich comes from this rule:st2/pants-plugins/stevedore_extensions/python_dependency_injection.py
Lines 53 to 59 in 7148058
Which needs
AllStevedoreExtensionsfrom this rule (which getsAllTargetsfrom pants provided rules):st2/pants-plugins/stevedore_extensions/target_types_rules.py
Lines 50 to 53 in 7148058
stevedore_extensiontargets depend on python codeThe
stevedore_extensiontargets would not be very helpful if they didn't pull in dependencies on relevant python code. So, we parse the entry_points field and infer dependencies on all of the python code that provides those entry points. Starting fromst2/pants-plugins/stevedore_extensions/target_types_rules.py
Lines 158 to 165 in 7148058
In that rule, it requests
ResolvedStevedoreEntryPointsfrom the pants engine, which pulls in this rule:st2/pants-plugins/stevedore_extensions/target_types_rules.py
Lines 59 to 65 in 7148058
Thus we have an inferred set of dependencies from
python_testthroughstevedore_extensiontopython_source.Developing pants plugins
Pants has extensive documentation on the plugin API, including how to create targets, how to write rules, and there's even a mini tutorial about how to add a formatter (adding formatters is a very common thing for plugins to do).