Trying to make a single executable file with PEX

1,459 views
Skip to first unread message

Matias Lang

unread,
Jan 28, 2015, 9:48:34 AM1/28/15
to pants...@googlegroups.com
Hi, i read about pex and i want to use it to distribute my app in a single executable file, but I don't know how to do it well, I tried a lot of ways and still getting errors.
The app is a few lines of code with some PyPI dependencies and has this structure:
├── appname
│   ├── __init__.py
│   ├── __main__.py
│   └── settings.py

__init__ is empty, __main__ is the script I want to run and settings' variables are imported by __main__ the following way:
from .settings import SOME_SETTING, OTHER_SETTING

I am in the parent directory of the app (where is the appname directory). I can run the app with python -m appname, but when I run:
pex --no-wheel -r dependency1 -r dependency2 -e appname
I get an ImportError: No module named appname. I use --no-wheel because some depencences don't install with wheel activated.
What am I doing wrong?

John Sirois

unread,
Jan 28, 2015, 10:59:43 AM1/28/15
to Matias Lang, pants-devel
You're just missing a switch and a setup.py:

$ pex --version
pex 0.8.3
$ pex -h
...
  -s DIR, --source-dir=DIR
                        Source to be packaged; This <DIR> should be a pip-
                        installable project with a setup.py.
  -v                    Turn on logging verbosity, may be specified multiple
                        times.

So if you add a proper setup.py and add -s <dir containing setup.py> to the command line, you should be good to go.

Matias Lang

unread,
Jan 28, 2015, 4:42:02 PM1/28/15
to pants...@googlegroups.com, matia...@vixionar.com
Hi John, thanks for replying. I made a setup.py in my current working dir and it works well in a normal virtualenv, but when i run pex with the same options before + -vvv and -s . I get this:

pex: Resolving distributions :: Fetching file:.../appname-0.1.tar.gz
Packaging appname :: **** Failed to install appname. stdout:

**** Failed to install appname-0.1. stderr:
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'setup.py'

pex: Failed to install package at /tmp/tmp8sdew89_/appname-0.1:
Traceback (most recent call last):
  File "/usr/bin/pex", line 11, in <module>
    sys.exit(main())
  File "/usr/lib/python3.4/site-
packages/pex/bin/pex.py", line 325, in main
    pex_builder = build_pex(args, options)
  File "/usr/lib/python3.4/site-packages/pex/bin/pex.py", line 303, in build_pex
    cache_ttl=options.cache_ttl)
  File "/usr/lib/python3.4/site-packages/pex/resolver.py", line 229, in resolve
    new_requirements.update(requires(highest_package, requirement))
  File "/usr/lib/python3.4/site-packages/pex/resolver.py", line 201, in requires
    raise Untranslateable('Package %s is not translateable.' % package)
pex.resolver.Untranslateable: Package SourcePackage('file:///.../appname-0.1.tar.gz') is not translateable.

It happens with and without --no-wheel

John Sirois

unread,
Jan 28, 2015, 6:20:30 PM1/28/15
to Matias Lang, pants-devel
I repro.  It appears pex using -s needs a MANIFEST where pip does not.  In particular, pex does not pick up the setup.py itself and include it in the -s sdist it generates leading to the error you see.  This full example works:

# my virtualenv
$ pip list
pex (0.8.3)
pip (1.5.6)
setuptools (7.0)

# the example
$ tree example/
example/
├── MANIFEST.in
├── appname
│   ├── __init__.py
│   └── __main__.py
└── setup.py

1 directory, 4 files

$ cat example/appname/__main__.py 
import redis

if __name__ == '__main__':
  print('redis symbols:\n\t{0}'.format('\n\t'.join(map(str, dir(redis)))))

$ cat example/MANIFEST.in 
include *.py

$ cat example/setup.py 
from setuptools import setup

setup(
  name='appname',
  packages=['appname'],
  install_requires=['redis'],
)

# the pex creation command
$ pex -r redis --no-wheel -s example/ -e appname -o appname.pex

# running the generated pex
$ ./appname.pex 
redis symbols:
AuthenticationError
BlockingConnectionPool
BusyLoadingError
Connection
ConnectionError
ConnectionPool
DataError
InvalidResponse
PubSubError
ReadOnlyError
Redis
RedisError
ResponseError
SSLConnection
StrictRedis
TimeoutError
UnixDomainSocketConnection
VERSION
WatchError
__all__
__builtins__
__doc__
__file__
__loader__
__name__
__package__
__path__
__version__
_compat
client
connection
exceptions
from_url
lock
utils

Matias Lang

unread,
Jan 28, 2015, 8:41:27 PM1/28/15
to pants...@googlegroups.com
It worked, thanks you! the problem was that I didn't have the manifest and the cache dir was building the .pex with an old version. I set it to a temporary directory and it work properly. Thanks you, very much!
Reply all
Reply to author
Forward
0 new messages