[New-bugs-announce] [issue32054] Creating RPM on Python 2 works, but Python 3 fails because of sys.implementation.cache_tag
Pedro
report at bugs.python.org
Thu Nov 16 17:07:02 EST 2017
New submission from Pedro <pgacv2+pythonbugs at gmail.com>:
I am trying to create an RPM on SLES12 SP2. (I think that corresponds to OpenSUSE 42.2.) This is my setup.py file, nothing special:
import setuptools
setuptools.setup(name='MyApp',
version='1.2.3',
options={'bdist_rpm': {'post_install': 'post_install.sh',
'post_uninstall': 'post_uninstall.sh'}})
Running `python setup.py bdist_rpm` with Python 2 works. However, running `python3 setup.py bdist_rpm` outputs the following:
running bdist_rpm
running egg_info
writing top-level names to MyApp.egg-info/top_level.txt
...
byte-compiling /home/pedro/MyApp/build/bdist.linux-x86_64/rpm/BUILDROOT/MyApp-1.2.3-1.x86_64/usr/lib/python3.4/site-packages/MyApp/my_file.py to my_file.cpython-34.pyc
...
Processing files: MyApp-1.2.3-1.noarch
error: File not found: /home/pedro/MyApp/build/bdist.linux-x86_64/rpm/BUILDROOT/MyApp-1.2.3-1.x86_64/usr/lib/python3.4/site-packages/MyApp/my_file.py
RPM build errors:
File not found: /home/pedro/MyApp/build/bdist.linux-x86_64/rpm/BUILDROOT/MyApp-1.2.3-1.x86_64/usr/lib/python3.4/site-packages/MyApp/my_file.py
error: command 'rpmbuild' failed with exit status 1
The problem appears to be that setuptools is generating a file that ends in `.cpython-34.pyc`, and later looks for a file without the `.cpython-34` but can't find it.
The RPM generation process on Python 3 goes through `distutils.util.byte_compile()`, which in turn calls `importlib.util.cache_from_source(path)`, where `path` is the file to be byte-compiled. `cache_from_source()` injects the value of `sys.implementation.cache_tag` (which is equal to 'cpython-34' on SLES12 SP2) into the filename of the compiled file. This attribute of `sys` does not exist in Python 2. So it looks like `setuptools` alters the filename with that tag during byte compilation, but later forgets that it modified the filename and fails because it's looking for the original name.
I ended up working around this by patching `distutils.file_util.write_file` to eliminate the .pyc entries from INSTALLED_FILES:
orig_bytecode_var = os.environ.get('PYTHONDONTWRITEBYTECODE', '')
os.environ['PYTHONDONTWRITEBYTECODE'] = '1'
orig_write_file = distutils.file_util.write_file
def my_patch(*args, **kwargs):
new_args = list(args)
if args[0] == 'INSTALLED_FILES':
new_args[1] = [fname for fname in args[1] if fname[-4:] not in ('.pyc', '.pyo')]
orig_write_file(*new_args, **kwargs)
distutils.file_util.write_file = my_patch
setuptools.setup(name='MyApp',
version='1.2.3',
options={'bdist_rpm': {'post_install': 'post_install.sh',
'post_uninstall': 'post_uninstall.sh'}})
os.environ['PYTHONDONTWRITEBYTECODE'] = orig_bytecode_var
distutils.file_util.write_file = orig_write_file
But I don't think I should have to do anything special to build an RPM on Python 3 vs. Python 2. Is this expected behavior?
----------
components: Distutils
messages: 306400
nosy: dstufft, eric.araujo, pgacv2
priority: normal
severity: normal
status: open
title: Creating RPM on Python 2 works, but Python 3 fails because of sys.implementation.cache_tag
type: behavior
versions: Python 3.4
_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue32054>
_______________________________________
More information about the New-bugs-announce
mailing list