Skip to content

Instantly share code, notes, and snippets.

@ophers
Created January 22, 2020 12:51
Show Gist options
  • Save ophers/093c31bce28f1356b7bf149a99e58326 to your computer and use it in GitHub Desktop.
Save ophers/093c31bce28f1356b7bf149a99e58326 to your computer and use it in GitHub Desktop.
Produce a Python Wheel without sources with CLI option --exclude-source-files
import os
from distutils import log
from setuptools import setup, find_packages
from setuptools.command.build_py import build_py as _build_py
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
from wheel.pep425tags import get_impl_ver
class build_py(_build_py):
def initialize_options(self):
_build_py.initialize_options(self)
wc = self.get_finalized_command("bdist_wheel", 0)
self.exclude_source_files = wc and wc.exclude_source_files
def finalize_options(self):
if self.exclude_source_files:
self.force = 1
self.compile = 1
_build_py.finalize_options(self)
def byte_compile(self, files):
_build_py.byte_compile(self, files)
if self.exclude_source_files:
for file in files:
if file.endswith('.py'):
os.unlink(file)
log.info('removing source file %s', file)
class bdist_wheel(_bdist_wheel):
_bdist_wheel.user_options.append(('exclude-source-files', None, "remove all .py files from the generated wheel"))
def initialize_options(self):
_bdist_wheel.initialize_options(self)
self.python_tag = None
self.exclude_source_files = False
def finalize_options(self):
if self.python_tag is None:
if self.exclude_source_files:
self.python_tag = 'py' + get_impl_ver()
else:
self.python_tag = 'py' + get_impl_ver()[0]
_bdist_wheel.finalize_options(self)
setup(
name='package name',
# ...,
setup_requires=['wheel>=0.30;python_version>="2.7"', 'wheel==0.29;python_version<"2.7"'],
cmdclass={"build_py": build_py, "bdist_wheel": bdist_wheel}
)
@by2coffee
Copy link

I found this useful, thank you 👍

@ophers
Copy link
Author

ophers commented Jan 29, 2020

Hey @by2coffee

I found this useful, thank you 👍

I'm happy to hear,
Cheers.

@xray1111
Copy link

xray1111 commented Jun 4, 2020

@ophers
great work, it's really helpful! But what if I want to exclude all the python source file except the __init__.py files at the root of packages? Your solution seems remove all the python source file include __init__.py. Thank you!

@xray1111
Copy link

xray1111 commented Jun 4, 2020

@ophers
I know how to modify the code to meet my needs though I'm not really understand the detail logic, change line 25 to:
if file.endswith('.py') and not file.endswith('__init__.py'):

Thank you very much!

@ophers
Copy link
Author

ophers commented Jun 4, 2020

@xray1111

great work, it's really helpful!

Happy to have helped.
BTW, how did you arrive at this page?

I know how to modify the code to meet my needs though I'm not really understand the detail logic, change line 25 to:
if file.endswith('.py') and not file.endswith('__init__.py'):

Why would you need to do this?

@spokeydokeys
Copy link

Thanks for the code. This is just what I need. However, when I run this, all the pyc files are placed in the pycache directory and not discovered when importing (as per this flow chart).

From this, it looks like the version tag needs to be removed and the files need to end up in the source directory, rather than the pycache directory.

Is there a way to overload that functionality?

@spokeydokeys
Copy link

As a work around, I have started using pyc_wheel. It makes the build a two-step process, but results in the desired outcome.

@ophers
Copy link
Author

ophers commented Jul 30, 2020

@sethgilchrist I developed and tested only with Python2.7.
What version are you using?

@spokeydokeys
Copy link

Dug a bit deeper and it appears that moving the compiled files into the distribution directory would require overloading cache_from_source in importlib\_bootstrap_external.py and is likely to be more of a hassle than just executing pyc_wheel.

@spokeydokeys
Copy link

@ophers I'm running 3.7.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment