unbit / uwsgi

uWSGI application server container
http://projects.unbit.it/uwsgi
Other
3.45k stars 687 forks source link

Incorrect stdlib path for relocated Python installs, resulting in `ModuleNotFoundError: No module named 'encodings'` #2525

Open edmorley opened 1 year ago

edmorley commented 1 year ago

Summary

uWSGI calculates the Python stdlib location incorrectly for Python installs that have been relocated, resulting in the server failing to start due to:

Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'

This appears to be because uWSGI is using the wrong sysconfig APIs to calculate Python home and the location of the standard library - and so uWSGI attempts to use them from the hardcoded compilation time paths, rather than the new Python location reported by sys.prefix and other sysconfig APIs.

Steps to reproduce

  1. mkdir uwsgi-testcase && cd $_
  2. touch Dockerfile app.py
  3. Edit Dockerfile and app.py to have the contents listed below
  4. docker build -t uwsgi-test .
  5. docker run --rm -it uwsgi-test
  6. docker run --rm -it uwsgi-test python -c 'import pprint, sys, sysconfig; print("sys.prefix:", sys.prefix); print("sys.path:", pprint.pformat(sys.path)); print("sysconfig.get_paths():", pprint.pformat(sysconfig.get_paths()))'
# Dockerfile

FROM heroku/heroku:22-build

RUN mkdir -p /foo/python \
  && curl -f https://heroku-buildpack-python.s3.us-east-1.amazonaws.com/heroku-22/runtimes/python-3.11.2.tar.gz \
  | tar -zxC /foo/python

ENV PATH="/foo/python/bin:/root/.local/bin:${PATH}"
ENV CPATH="/foo/python/include/python3.11:${CPATH}"
ENV LD_LIBRARY_PATH="/foo/python/lib:${LD_LIBRARY_PATH}"
ENV LIBRARY_PATH="/foo/python/lib:${LIBRARY_PATH}"

RUN python -m ensurepip --default-pip
RUN pip install --user uwsgi==2.0.21
RUN uwsgi --version

WORKDIR /workspace
COPY app.py .

CMD uwsgi --http :9090 --wsgi-file app.py
# app.py

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"]

Expected

Actual

$ docker run --rm -it uwsgi-test
*** Starting uWSGI 2.0.21 (64bit) on [Tue Mar 21 12:20:13 2023] ***
compiled with version: 11.3.0 on 21 March 2023 12:14:36
os: Linux-5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022
nodename: 25066dc0085b
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 6
current working directory: /workspace
detected binary path: /root/.local/bin/uwsgi
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
*** WARNING: you are running uWSGI without its master process manager ***
your memory page size is 4096 bytes
detected max file descriptor number: 1048576
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uWSGI http bound on :9090 fd 6
spawned uWSGI http 1 (pid: 8)
uwsgi socket 0 bound to TCP address 127.0.0.1:44037 (port auto-assigned) fd 5
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
Python version: 3.11.2 (main, Feb  8 2023, 12:54:20) [GCC 11.3.0]
Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Python path configuration:
  PYTHONHOME = (not set)
  PYTHONPATH = (not set)
  program name = '/root/.local/bin/uwsgi'
  isolated = 0
  environment = 1
  user site = 1
  safe_path = 0
  import site = 1
  is in build tree = 0
  stdlib dir = '/app/.heroku/python/lib/python3.11'
  sys._base_executable = '/root/.local/bin/uwsgi'
  sys.base_prefix = '/app/.heroku/python'
  sys.base_exec_prefix = '/app/.heroku/python'
  sys.platlibdir = 'lib'
  sys.executable = '/root/.local/bin/uwsgi'
  sys.prefix = '/app/.heroku/python'
  sys.exec_prefix = '/app/.heroku/python'
  sys.path = [
    '/app/.heroku/python/lib/python311.zip',
    '/app/.heroku/python/lib/python3.11',
    '/app/.heroku/python/lib/python3.11/lib-dynload',
  ]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'

Current thread 0x00007ffffce99bc0 (most recent call first):
  <no Python frame>

In comparison, Python's stdlib has the correct paths:

$ docker run --rm -it uwsgi-test python -c 'import pprint, sys, sysconfig; print("sys.prefix:", sys.prefix); print("sys.path:", pprint.pformat(sys.path)); print("sysconfig.get_paths():", pprint.pformat(sysconfig.get_paths()))'
sys.prefix: /foo/python
sys.path: ['',
 '/foo/python/lib/python311.zip',
 '/foo/python/lib/python3.11',
 '/foo/python/lib/python3.11/lib-dynload',
 '/root/.local/lib/python3.11/site-packages',
 '/foo/python/lib/python3.11/site-packages']
sysconfig.get_paths(): {'data': '/foo/python',
 'include': '/foo/python/include/python3.11',
 'platinclude': '/foo/python/include/python3.11',
 'platlib': '/foo/python/lib/python3.11/site-packages',
 'platstdlib': '/foo/python/lib/python3.11',
 'purelib': '/foo/python/lib/python3.11/site-packages',
 'scripts': '/foo/python/bin',
 'stdlib': '/foo/python/lib/python3.11'}

Versions

Notes

edmorley commented 1 month ago

Something else I've just discovered - this issue only affects uWSGI when it was installed into the user site-packages using using pip install --user. If uWSGI was installed into the system site-packages or else into a virtualenv's site-packages, then the error doesn't occur.