I'm trying to create a pex for a python CLI script...
# general
b
I'm trying to create a pex for a python CLI script in pants 2.15 (upgrading from 1.30), and if I use the
script
tag in my build file for the pex binary then pants complains that it cannot find the file that's in the same directory as the build file. If I use the
entry_point
tag I get an import error saying there was no module main found. I'l curious to see what I could be doing wrong
If it's helpful, the cli uses an async main method as well
e
The
script
field is for console scripts - those are generally only defined in a packaged wheel via entry_points.txt metadata. Like so for the
cowsay
wheel:
Copy code
$ cat /home/jsirois/.pex/installed_wheels/0b005324b3bd9c50d9214dfd38a39e4bf4522635e32bec351d7dfcd4c9e3e6e2/cowsay-5.0-py2.py3-none-any.whl/cows
ay-5.0.dist-info/entry_points.txt
[console_scripts]
cowsay = cowsay.main:cli
That is likely not what you mean.
For the
entry_point
field, please dump your BUILD here if possible.
And - wow! I'm not sure I'm aware of anyone tackling that big an upgrade.
b
Yeah, we're more or less forced to do it because I couldn't figure out how to get 1.30 to play nicely with python 3.11. I'll upload the build momentarily
e
Gotcha. Yeah - its tough to stay on a mix of unmaintained software and latest greatest.
b
This is a test of the build file I'm trying to make a CLI out of. I used the same format for a micro-service and no matter if it's inside of a docker container or in a local virtual env running python 3.11.2, I get
ImportError: No module named main
e
Ok, the issue is no target owns main.py. You'd need to add a
python_source(name="main",  source="main.py")
and then add a dep on that in the
pex_binary
target.
Note that a big change in Pants v2 is you can leave off every explicit dependency that is resolvable by parsing Python import statements.
So you can probably ditch all those 3rdparty deps.
At the very least.
b
Oh, I'll add a source like that. Let me give that a shot locally and see if I can get things working
e
So, idiomatically now you'd have:
Copy code
python_sources()
pex_binary(name="shorts", entry_point="main.py:runner")
And all the rest would be done for you assuming main.py tranisitively imported all the rest and all the rest had BUILD files with python_source(s) targets owning them.
If you haven't seen
pants tailor
, that's new and deals with populating these ~empty BUILD targets. Pants can infer most things now, but it still - weirdly - needs empty targets at least to own files. Pure legacy weirdness. + https://www.pantsbuild.org/docs/reference-tailor + https://www.pantsbuild.org/docs/initial-configuration#generate-build-files
Using tailor is not as impactful with pre-existing BUILD files. You'd basically have to delete some BUILD files, then run
pants tailor ::
, then adjust.
But that might be one way to trim the fat during or after the upgrade.
b
Yeah, I'm at a weird spot where I'm cutting code over to pants 2.15 while also maintaining the 1.30 pipeline. Not wanting to do all or nothing changes
I now have this but am getting redirected to python terminal instead of executing the CLI script
e
Can you add a very early
print(...)
to main.py and then provide full output for
pants run ...
assuming that's the goal you are running here. If not and it's
pants package ... && ./dist/shorts.pex
- then same.
If it's helpful, the cli uses an async main method as well
You'll have to excuse my ignorance. I thought you needed a normal main entry point that started an event loop to then get into async-land. Perhaps revealing as much of the main.py as you can would be helpful.
b
I don't think the async part matters. I ran the run command and got an import error from a first party module that makes sense to me. So I think I'm good to go
e
Ok - great.
b
Just to close the loop here. I was able to get the menu I expected from my CLI when I did a pants run command. Thanks for the help this morning!
e
Excellent. And thanks for closing the loop.