I’m trying to debug an issue I’m having with `pant...
# general
a
I’m trying to debug an issue I’m having with
pants run
. If I try to run the
pex
using
execution_mode="venv"
I’m getting an import error for
google-auth
EDIT: I’m running
pants==2.19.1
Pants is detecting
google-auth
as a transitive dependency
Copy code
> pants dependencies --transitive src/python/apps/ava:ava_app | grep 'google-auth'
3rdparty/python:google-auth
I’ve declared
google.oauth2
as a module of
google-auth
Copy code
> cat 3rdparty/python/BUILD | grep 'google-auth'
python_requirement(name="google-auth", requirements=["google-auth"], modules=["google.auth", "google.oauth2"], dependencies=[":setuptools"])
I’ve validated that it’s included in the lockfile and checked that that version does indeed have the
google.oauth2
module
Copy code
> cat 3rdparty/python/python-default.lock | grep 'google-auth=='
//     "google-auth==2.16.2",
    "google-auth==2.16.2",
Here’s the build file
Copy code
> cat src/python/apps/ava/BUILD
python_sources(name="run_sanic", sources=["run_sanic.py"])

pex_binary(
  name="ava_app",
  dependencies=[":run_sanic"],
  entry_point="run_sanic.py:main",
  execution_mode="venv",
)
And here’s what happens when I run it:
Copy code
> pants run src/python/apps/ava:ava_app
Traceback (most recent call last):
  File "/Users/josha/.pex/venvs/f5ad7fc6f9308a9164792203bf58aaf22a09c919/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/pex", line 282, in <module>
    module = importlib.import_module(module_name)
  File "/Users/josha/.pyenv/versions/3.9.16/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/Users/josha/.pex/venvs/f5ad7fc6f9308a9164792203bf58aaf22a09c919/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/run_sanic.py", line 8, in <module>
    from ava.server import app
  File "/Users/josha/.pex/venvs/f5ad7fc6f9308a9164792203bf58aaf22a09c919/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/ava/server.py", line 21, in <module>
    from ava.worker.bootstrap import create_app  # noqa: E402
  File "/Users/josha/.pex/venvs/f5ad7fc6f9308a9164792203bf58aaf22a09c919/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/ava/worker/bootstrap.py", line 9, in <module>
    from ava.worker.audit import init_auditing
  File "/Users/josha/.pex/venvs/f5ad7fc6f9308a9164792203bf58aaf22a09c919/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/ava/worker/audit.py", line 1, in <module>
    from pf.sanic.extras.audit.setup import setup_audit
  File "/Users/josha/.pex/venvs/f5ad7fc6f9308a9164792203bf58aaf22a09c919/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/pf/sanic/extras/audit/setup.py", line 6, in <module>
    from google.oauth2.service_account import Credentials
ModuleNotFoundError: No module named 'google.oauth2'
It does this even if I add
“3rdparty/python:google-auth”
as an explicit dependency to the
pex_binary
def. Given I’ve done
pants export --py-resolve-format=symlinked_immutable_virtualenv --resolve=python-default
when I try running the
run_sanic.py
directly it works fine
Copy code
/Users/josha/pf/c3/dist/export/python/virtualenvs/python-default/3.9.16/bin/python src/python/apps/ava/run_sanic.py
<expected output>
But if I remove
execution_mode="venv"
I get a different error:
Copy code
pants run src/python/apps/ava:ava_app
/Users/josha/.pyenv/versions/3.9.16/bin/python3.9: Error while finding module specification for '__main__' (ValueError: __main__.__spec__ is None)
And for clarity at the bottom of
run_sanic.py
is just
Copy code
if __name__ == "__main__":
    main()
I’m clearly doing something wrong, and any ideas would be greatly appreciated!
Also looking through the debug logs from running
pants --level=debug run src/python/apps/ava:ava_app
I can see that the dependency resolver is certainly hitting the node
Copy code
11:11:02.96 [DEBUG] Completed: Determine Python dependencies for "pf/sanic/extras/audit/setup.py"
11:11:02.96 [DEBUG] Completed: pants.backend.python.dependency_inference.parse_python_dependencies.parse_python_dependencies
And there’s nothing particuarly special about the import statement of interest
Copy code
from google.oauth2.service_account import Credentials
s
I've haven't tried things like
Copy code
python_requirement(name="google-auth", requirements=["google-auth"], modules=["google.auth", "google.oauth2"], dependencies=[":setuptools"])
before but I've had luck with mapping modules to packages via
Copy code
python_requirements(
    ...
    module_mapping={
        "google-auth": ["google.oauth2"],
    }
)
From the docs it seems like what you have should work though.
a
Yeah my read from the docs is that
python_requirements
is just a convenience function to generate
python_requirement
nodes from a
requirement.txt
file. I could be wrong though
The
module_mapping
and
overrides
are there to allow adding the extra fields that are missing from
requirements.txt
And to be fair, all my tests run happily
Even the ones that test this specific file
It just seems to be the pex file
s
Have you tried adding (excuse the formatting)
Copy code
overrides={
    "...": {
        "the sanic audit package name": [
           "//3rdparty/python:reqs#google-auth",
        ]
     },
  }
note I have requirements in
3rdparty/python:reqs
*
a
Hmm good idea! Let me try that
No love 😞 Even adding the dependency specifically in the
BUILD
file adjacent to the guilty file doesn’t help
🤔 … I wonder if it doesn’t like the fact that the file is named `setup.py`…
Nope, that wasn’t it
s
Have you tried
--keep-sandboxes=always
?
a
Good idea. Let me try that
The
__run.sh
file seems to have baked in all my local environment variables. Is that expected?
s
I'm not sure what the answer to that is. If you include
include_tools=True
in your pex you can run something like
PEX_TOOLS=1 python item-rank/cli.pex/ venv --compile ./foo
You can then run
Copy code
./foo/bin/python3
and try to import
google.oauth2
in the interpreter.*
That might reveal if there's some exception that's getting swallowed
a
Oh nice one. I’ll try that
Copy code
>>> import pkgutil
>>> import google
>>> def list_modules(package):
...     return [modname for _, modname, _ in pkgutil.walk_packages(path=package.__path__)]
... 
>>> modules = list_modules(google)
>>> for module in modules:
...     print(module)
... 
api_core
Looks like
api_core
is overwriting the namespce?
There should be a bunch of modules in there
👀
Looks like ol’ googs has switched to implicit namespacing recently
So this might just be a versioning issue
s
Does
lib/python3.10/site-packages/
look like its supposed to?
I'm using a bunch of google client libraries and if I introspect a pex I converted to a venv I see
google_auth_(version)_...
in that directory
a
Hmm actually, the version of google-api-core we’re running does use the old style also… https://github.com/googleapis/python-api-core/tree/v1.34.0/google
Ill take a peek
It does in the venv generated by
pants export --py-resolve-format=symlinked_immutable_virtualenv --resolve=python-default
Just going to try and compare the pex venv
s
fwiw
Copy code
>>> import pkgutil
>>> import google
>>> def list_modules(package):
...     return [modname for _, modname, _ in pkgutil.walk_packages(path=package.__path__)]
... 
>>> modules = list_modules(google)
>>> for module in modules:
...     print(module)
... 
auth
oauth2
a
Any chance you can try with this set?
Copy code
python_requirement(name="google-api-core", requirements=["google-api-core==1.34.0"], modules=["google.api_core"], dependencies=[":setuptools"])
python_requirement(name="google-api-python-client", requirements=["google-api-python-client==1.12.8"], modules=["googleapiclient"], dependencies=[":setuptools"])
python_requirement(name="google-auth", requirements=["google-auth"], modules=["google.auth", "google.oauth2"], dependencies=[":setuptools"])
python_requirement(name="google-cloud-compute", requirements=["google-cloud-compute==1.10.0"], modules=["google.cloud.compute", "google.cloud.compute_v1"], dependencies=[":setuptools"])
python_requirement(name="google-cloud-error-reporting", requirements=["google-cloud-error-reporting<2.0.0,>=1.8.2"], modules=["google.cloud.error_reporting"], dependencies=[":setuptools"])
python_requirement(name="google-cloud-profiler", requirements=["google-cloud-profiler<5.0.0,>=4.0.0"], modules=["googlecloudprofiler"], dependencies=[":setuptools"])
python_requirement(name="google-cloud-secret-manager", requirements=["google-cloud-secret-manager==2.12.6"], modules=["google.cloud.secretmanager"], dependencies=[":setuptools"])
python_requirement(name="google-cloud-sqlcommenter", requirements=["google-cloud-sqlcommenter<3.0.0,>=2.0.0"], modules=["google.cloud.sqlcommenter"], dependencies=[":setuptools"])
python_requirement(name="google-cloud-trace", requirements=["google-cloud-trace<2.0.0,>=1.11.0"], modules=["google.cloud.trace", "google.cloud.trace_v1", "google.cloud.trace_v2"], dependencies=[":setuptools"])
Constraints are
Copy code
google-api-core==1.34.0
google-api-python-client==1.12.8
google-auth-httplib2==0.1.0
google-auth==2.16.2
google-cloud-appengine-logging==1.3.0
google-cloud-audit-log==0.2.5
google-cloud-compute==1.10.0
google-cloud-core==2.3.2
google-cloud-error-reporting==1.9.1
google-cloud-logging==3.5.0
google-cloud-profiler==4.0.0
google-cloud-secret-manager==2.12.6
google-cloud-sqlcommenter==2.0.0
google-cloud-trace==1.11.1
s
How are you mapping that the package that installs pf.sanic.extras.audit.setup depends on google-auth?
a
pf.sanic.extras
is an internal lib in the same monorepo. So it’s just getting mapped by pants
Copy code
$ pants dependencies src/python/libs/python-sanic-extras/src/pf/sanic/extras/audit/setup_audit.py | grep 'google'
3rdparty/python:google-auth
s
I take it that's returning nothing?
nvm can't read lol
a
🙂
Copy code
$ pants dependencies --transitive src/python/apps/ava:ava_app | grep 'setup_audit.py'
src/python/libs/python-sanic-extras/src/pf/sanic/extras/audit/setup_audit.py
So pants seems to have the dependency graph right
There’s just something funky going on with the pex
s
In my experience Pex has been pretty solid
Can you list the dependency chain from the entrypoint to pf/sanic/extras/audit/setup_audit ?
a
Yeah the traceback gets us there
Copy code
File "/Users/josha/.pex/venvs/b8e2aec83f24690d9d16e74d79fc645c385ad07c/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/run_sanic.py", line 8, in <module>
    from ava.server import app
  File "/Users/josha/.pex/venvs/b8e2aec83f24690d9d16e74d79fc645c385ad07c/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/ava/server.py", line 21, in <module>
    from ava.worker.bootstrap import create_app  # noqa: E402
  File "/Users/josha/.pex/venvs/b8e2aec83f24690d9d16e74d79fc645c385ad07c/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/ava/worker/bootstrap.py", line 9, in <module>
    from ava.worker.audit import init_auditing
  File "/Users/josha/.pex/venvs/b8e2aec83f24690d9d16e74d79fc645c385ad07c/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/ava/worker/audit.py", line 1, in <module>
    from pf.sanic.extras.audit.setup_audit import setup_audit
  File "/Users/josha/.pex/venvs/b8e2aec83f24690d9d16e74d79fc645c385ad07c/779eb2cc0ca9e2fdd204774cbc41848e4e7c5055/lib/python3.9/site-packages/pf/sanic/extras/audit/setup_audit.py", line 6, in <module>
    from google.oauth2.service_account import Credentials
ModuleNotFoundError: No module named 'google.oauth2'
so:
Copy code
- run_sanic.py
  - ava/server.py
    - ava/worker/bootstrap.py
      - ava/worker/audit.py
        - pf/sanic/extras/audit/setup_audit.py
None of those files have any weird or dynamic imports
s
And just as a sanity check you can
pants run
each of those without getting import errors (well I guess run_sanic.py gives an error)?
a
👀
pants run src/python/apps/ava/run_sanic.py
pants run src/python/apps/ava/ava/server.py
pants run src/python/apps/ava/ava/worker/bootstrap.py
pants run src/python/apps/ava/ava/worker/audit.py
pants run src/python/libs/python-sanic-extras/src/pf/sanic/extras/audit/setup_audit.py
Yup all of those run happily if I run them directly via pants
Which is funny, as I can see it’s builds a
pex
for each of those runs
s
dang. It might be worth trying to make a minimal reproduction of the code base.
a
Yeah I think you’re right. I really appreciate your time/help with this
s
Maybe a dumb question. But why do you have
dependencies=[":run_sanic"],
in the pex?
the entrypoint should be sufficient right?
a
I’ll go and see if I can build a minimal reproduction
dependencies=[":run_sanic"]
this was just me throwing things at the wall to see what would stick
Wasn’t there initially
s
got it