I'm trying to use the <python + docker strategy de...
# general
p
I'm trying to use the python + docker strategy defined here with an app that cannot use a
pex_binary
entry_point
and must use a
script
instead (because it runs
streamlit
, which calls my
main.py
.) However, I can't figure out how to get
pex_binary
to treat my
main.py
as a "source script" from the perspective of the
pex
tool, that is, a script that will be included in the call to
"RUN PEX_TOOLS=1 /usr/local/bin/python3.10 /binary-srcs.pex venv --scope=srcs --compile /bin/app"
(as opposed to
--scope=deps
.) How does
pex_binary
determine which assets are "source" assets and which are "requirements"? That is, what determines which assets are included when you pass
include_sources=True, include_requirements=False
and its inverse? And how can I convince
pex_binary
to treat an asset as a source rather than a requirement?
👀 1
s
Sources are
python_sources
and requirements are
python_requirements
. But what is not working exactly? Could you share a reproducible example?
p
Sorry, took me a minute. Repro here: https://github.com/jake-normal/streamlit-repro
pants run //:dev
launches streamlit with
main.py
.
pants run //:image
should behave the same way except wrapped in a container, but it does not:
Copy code
jake@Jakes-MacBook-Pro streamlit-demo % pants run //:image
10:31:44.93 [INFO] Initializing scheduler...
10:31:47.19 [INFO] Scheduler initialized.
10:31:50.88 [INFO] Completed: Building docker image image:latest
Usage: pex run [OPTIONS] TARGET [ARGS]...
Try 'pex run --help' for help.

Error: Invalid value: File does not exist: main.py
My hunch is that the pex tool --compile isn't behaving the way I expect.
when I inspect the filesystem of the container, there is indeed no
main.py
anywhere in
/usr/bin/app
s
I'm not sure what are you trying to achieve
why do you need args on pex_binary?
p
Streamlit is a 3rd party dependency that runs a 1st party script, and the name of that 1st party script is passed as an argument. This is similar to the pattern that e.g. uvicorn uses. (Unlike uvicorn, however, there is no option that I am aware of to run a streamlit app programmatically, that is, by importing streamlit as a library.) My goal is to run a streamlit app from within a docker container. In an ideal world, I would be able to take advantage of the multi-layer docker strategy described here, but that would be icing on the cake at this point.
s
pex packages all the code into single zipapp, so there is no main.py when you run your pex. uvicorn supports entrypoint specified as a module, this will work
does streamlit support modules?
if you only need it in docker, you could just add main.py to your container and that's it, you don't even need pants 🙂
p
so there is no main.py when you run your pex
Interesting. Do you know why
pants run :dev
works (that is, the app starts) and
pants run :py-bin
works (if I temporarily comment out my
complete_platforms
line) but
pants run :image
does not? Thanks for talking through this with me, BTW
does streamlit support modules?
Not in the same way that uvicorn does as I understand
s
Do you know why
pants run :dev
works (that is, the app starts) and
pants run :py-bin
works (if I temporarily comment out my
complete_platforms
line) but
pants run :image
does not?
because run executes in your current directory. Try this
pants package :dev
, this will build the pex, then do
./dist/dev.pex
- this is essentially what happens when you run
pants run
then try something like
cd ~
and try running the same pex again - it will not work because you don't have main.py in your ~
p
lemme give that a quick go
yeah that behaved as you've explained. What I'm confused by is that
py-bin.pex
does contain
main.py
:
Copy code
jake@Jakes-MacBook-Pro Desktop % cd py-bin.pex
jake@Jakes-MacBook-Pro py-bin.pex % ls
PEX-INFO	__main__.py	__pex__		__pycache__	hello.py	main.py
jake@Jakes-MacBook-Pro py-bin.pex %
s
yes, but that's inside the pex
that doesn't count 😄
try removing execution_mode="venv", it might become more clear
p
hahaha my mind is spinning, let me try that
s
originally pex is a magical self running zip archive, it's a single file, you can't just read main.py from inside with
cat main.py
or smth
p
That part makes sense to me.
Just to summarize my understanding, the issue is basically this line:
Copy code
args=["run", "main.py"],
This reference to
main.py
is basically "out of context" – it isn't understood by Pants to be a dependency of any kind. And though the
args
do seem to be baked into the pex (as arguments,)
main.py
itself is not available outside the pex when the pex is moved away from my pants repo. Is that correct?
And the reason that uvicorn works is because pants does have some way of understanding when args are referencing a module? (this part I'm less clear on?)
s
yep, that's right
uvicorn with module works because imports inside pex work, you could do
import main
in your pex, and it should find the main.py inside the pex
p
you could do
import main
in your pex
this feels close to my solution 🤣. What do you mean by "in your pex?"
s
I mean if you have
pex_binary(entry_point="my_entrypoint:main")
and then
my_entrypoint.py
Copy code
from main import main
then it should be able to import main.py from my_entrypoint.py
p
I'll give that a try
s
I think you should check out the pex docs https://docs.pex-tool.org/ pants only exposes the pex interface here
p
Thanks! I'll go over them in more depth. Again, hugely appreciative of your time.
👍 1
t
@flat-sunset-36133 this thread may be helpful as in figuring out how to integrate streamlit?
👀 1
f
Thanks @thousands-hair-85964 I am trying to emulate this strategy for dev deployment but running into issues with the dependencies outline here https://pantsbuild.slack.com/archives/C046T6T9U/p1722435892739929