-
-
Notifications
You must be signed in to change notification settings - Fork 631
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
add entry_points field on python_distribution #11872
Conversation
I've left three
Also, I've not done any dependency inference here yet.. either this will be good enough without, and we can address that in #11807 or we resolve both issues in this PR. |
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.
Thanks @kaos. Sorry for the delay here. I may have missed some context since Eric was working more closely with you on this, so please push back if anything I've pointed out has already been worked out in contradiction.
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.
Really great stuff! Thank you! If you're willing, I think it would be best to include the dependency inference PR directly in this one. That way, the new deprecated feature is not degrading the experience from before.
You could also maybe leave off the deprecation part of this PR and save for a followup. That way, in the changelog, we would have something like "Add entry_points
field to python_distribution
" target (new feature), and then the followup could be "Deprecate .with_binaries()
in favor of entry_points
field".
(Also pardon the delay in reviewing this!) |
Don't worry about it. We all have priorities to consider :) |
OK, this has been long overdue. Sorry for that (I practically had to start over, as I'd forgot all context in this.. so can only guess you have too) I opted to go with a little more liberal approach to determine if it is a build target address. As long as there is a slash in the address, it will never be a setuptools entry point (at the risk of them introducing that.. but I think that risk is rather low) It is easy enough to tighten this requirement up, of course (it is just a single if statement doing this check) Dependency inference should work for distribution entry points as well. Let me know what you think, and I'll fix them up sooner than in another quarter ;) |
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.
Thanks @kaos! Pardon the delay, I think I now understand what we're after, specifically with pex_binary
and console_scripts
. Thanks for the great PR description :)
"console_scripts":{ | ||
"b_cmd": "project.app:main" | ||
} |
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.
You'll also want to check using a pex_binary
address, can even be the same one used above for with_binaries
.
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.
Also a dep on ansicolors
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.
not sure what you me to test wrgt ansicolors
.. ? (how/where?)
I see there is a requirement library for ansicolors in the test, that doesn't seem to do anything.. but don't know how to pull that in, in a useful way.
support dependency inferrence on entry_points. fixes pantsbuild#11807. fixes pantsbuild#11808. Signed-off-by: Andreas Stenius <andreas.stenius@svenskaspel.se> [ci skip-rust] [ci skip-build-wheels] support binary targets in entry points.
# Rust tests and lints will be skipped. Delete if not intended. [ci skip-rust] # Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
assert_injected( | ||
Address("project", target_name="dist-b"), | ||
Address("project", relative_file_path="app.py", target_name="my_library"), | ||
Address("who_knows", relative_file_path="module.py", target_name="random_lib"), |
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.
Notice a small difference here, compared to .with_binaries()
here you get a dependency on the owner of the source file that implements the entry point, whereas for .with_binaries()
you get a dependency on the pex_binary
itself.
Not sure if this is cause for any issues, down the road.. ?
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.
Oh hm....good eye! You're right that this is a problem. When you have an address to a pex_binary
, we want a dep on the pex_binary
, not the python_library
that has the source code for its entry point.
This will require some changes to your dep inference rule. Right now, you are normalizing the whole entry_points
field to a set of modules, then doing inference from there. That works when the user specified a module explicitly, but that does not work when they had a target address. Instead, you'll need to differentiate between those two formats when doing inference: if it's a target address, use the same Get(Addresses, UnparsedAddressInputs)
used for .with_binaries
, else use the Get(PythonModuleOwners, PythonModule)
stuff.
you'll need to differentiate between those two formats when doing inference
Maybe update ResolvedPythonDistributionEntryPoints
to store two fields: pex_binary_addresses
and explicit_modules
, then have a property that merges the two into all_entry_points
? That allows setup_py.py
to use all_entry_points
because it doesn't care about the nuance, but dep inference to use the two fields.
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.
Nice, thanks so much for iterating on this Andreas! This is shaping up really nicely.
if not entry_point: | ||
raise InvalidEntryPoint( |
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.
FYI to other reviewers: I had identified this code is safe to delete now that we require entry_point
for pex_binary
, and I asked @kaos to delete it.
owners.unambiguous | ||
or ((maybe_disambiguated,) if maybe_disambiguated else Addresses()) | ||
) | ||
entry_point_addresses += unambiguous_owners # type: ignore[assignment] |
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.
I don't think this will work. Addresses
is immutable. Instead, you need to reassign it.
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.
hehe, maybe it is my C background shining through. But this is reassignment. a += b
translates to a = a + b
. ;)
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.
But lets ensure there is a test, that proves it... ah, well it does verify that code path, when there are more than one entry point in the new entry_points field, so this assert does it: https://github.com/pantsbuild/pants/pull/11872/files#diff-a2ccc3f505ec7e33785464002b3c6192b325d97fcdcda65ad11876f2b5d7a500R448-R451
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.
Hm, to avoid confusion, how about using module_owners = OrderedSet()
at the start of this for
loop, then calling .update()
(?) on it each iteration. After the loop, set entry_point_addresses
equal to entry_points.pex_binary_addresses
+ module_owners
.
# ResolvedPexEntryPoint.val is Optional[EntryPoint] | ||
if entry_point is None: | ||
continue |
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.
Interesting, I'm honestly not sure what the right behavior is here. I think probably to error? It doesn't make sense to depend on a pex_binary
with entry_point='<none>'
, as that means there is no entry point. That seems more like an unintentional mistake.
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.
So, perhaps warn? In case it indeed was intentional (even just for testing purposes..)
…up from review feedback # Rust tests and lints will be skipped. Delete if not intended. [ci skip-rust] # Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
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.
Yay! The functionality and tests look great, now only a couple style things
class PythonDistributionPexableEntryPoint: | ||
"""Pexable means that the entry point could be from a pex_binary target.""" |
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.
There's no other type of PythonDistribution
, so imo you can remove Pexable
.
class PythonDistributionPexableEntryPoint: | |
"""Pexable means that the entry point could be from a pex_binary target.""" | |
class PythonDistributionEntryPoint: | |
"""Note that this stores if the entry point comes from an address to a `pex_binary` target.""" |
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.
If you make this rename, you can rename PythonDistributionEntryPoints
(plural) to PythonDistributionEntryPointsField
maybe.
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.
Yeah, I avoided PythonDistributionEntryPoint due to there being a plural form, so a mere s
to distinguish them by is too little imo. Also, I felt that the name PythonDistributionEntryPointsField
got unwieldy long.. and also didn't quite follow the naming pattern for the other fields.. that doesn't have the Field
suffix. Maybe we should start using Field
suffix for all fields, to be consistent.. ? (it helps making it clearer when the type shows up else where, that it is a field it refers to.. which isn't always obvious, in my eyes at least)
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.
Maybe we should start using Field suffix for all fields, to be consistent.. ?
Probably. We do use Field
in a couple names if you ripgrep it, but you're right that not many yet.
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.
But if you prefer that, I'm happy to change it...
owners.unambiguous | ||
or ((maybe_disambiguated,) if maybe_disambiguated else Addresses()) | ||
) | ||
entry_point_addresses += unambiguous_owners # type: ignore[assignment] |
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.
Hm, to avoid confusion, how about using module_owners = OrderedSet()
at the start of this for
loop, then calling .update()
(?) on it each iteration. After the loop, set entry_point_addresses
equal to entry_points.pex_binary_addresses
+ module_owners
.
Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>
Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>
Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>
# Rust tests and lints will be skipped. Delete if not intended. [ci skip-rust] # Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended. [ci skip-rust] # Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
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.
Excellent contribution, @kaos 🥳
This is a tricky part of the codebase, and you dove right in :) I'm really excited with how this turned out.
One small followup if you're willing, but I'm going to merge this because that followup doesn't block and this is an excellent change as is.
} | ||
}, | ||
) | ||
|
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.
(In a followup) Could you please add a test for dep inference of entry points defined in the provides=setup_py()
?
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.
Sure thing. But trying to remember what's changed since: #11872 (comment)
[...] you can still use the old setup_py() way of doing it, only you'll miss out a) dependency inference
Hmm... looking at the inject_python_distribution_dependencies
I don't think that we infer dependencies on entry_points from setup_py()
at all.. so that test should not work ;)
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.
But then again, that was the point of #11807 which supposedly was incorporated into this PR... eeh.. a little too much water under the bridge from start to finnish, I'd say..
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.
So, question becomes, do we want to spend time fixing that dep inference, or simply leave be waiting for #12410
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.
Ah, okay. Makes sense.
Totally depends on what you have the time and interest to do: #12410 is more of a blocker b/c right now we have two Pants-provided ways of doing something, and we want to get rid of the .with_binaries()
tech debt.
It would also be great to add dep inference for entry points defined inside a setup_py()
, but that isn't a blocker. It's a new feature. If you have the time and interest, that'd be great - okay if not. Either way, maybe create a issue to track this so we don't forget it's a feature request?
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.
I'll post a PR deprecating .with_binaries()
tomorrow.
Can also look into the dep inference on setup_py entry_points, shouldn't be too difficult, now :)
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.
Deprecation PR: #12413
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.
Dep inference for setup_py()
entry points PR: #12414
entry_points
field for thepython_distribution()
target.entry_points
.pex_binary
targets in entry points, which will use theentry_point
from thepex_binary()
target.The
entry_points
field ofpython_distribution
is adict[str, dict[str, str]]
value (just as forsetuptools.setup()
), where thestr
value is either on the form of a regular setuptools entry_point or a pants target address. Any value that either starts with a:
or that contains a/
is considered a target address (for apex_binary
) and resolves to the binary's entry_point.The reason for not requiring a leading
//
for target addresses on the entry_point str value, is to support the same syntax 1:1 from the entry_point value on.with_binaries()
, to ease migration.Example
BUILD
(from this repo)Example
BUILD
, before this change:fixes #11807.
fixes #11808.
closes #11880
Signed-off-by: Andreas Stenius andreas.stenius@svenskaspel.se
[ci skip-rust]
[ci skip-build-wheels]