title: Package only binary compiled .so files of a python library compiled with Cython
body: <p>I have a package named <code>mypack</code> which inside has a module <code>mymod.py</code>, and 
  the <code>__init__.py</code>.
  For some reason that is not in debate, I need to package this module compiled 
  (nor .py or .pyc files are allowed). That is, the <code>__init__.py</code> is the only
  source file allowed in the distributed compressed file.</p>
  
  <p>The folder structure is:</p>
  
  <pre><code>. 
  │  
  ├── mypack
  │   ├── __init__.py
  │   └── mymod.py
  ├── setup.py
  </code></pre>
  
  <p>I find that Cython is able to do this, by converting each .py file in a .so library
  that can be directly imported with python. </p>
  
  <p>The question is: how the <code>setup.py</code> file must be in order to allow an easy packaging and installation?</p>
  
  <p>The target system has a virtualenv where the package must be installed with 
  whatever method that allows easy install and uninstall (easy_install, pip, etc are all
  welcome).  </p>
  
  <p>I tried all that was at my reach. I read <code>setuptools</code> and <code>distutils</code> documentation, 
  all stackoverflow related questions,
  and tried with  all kind of commands (sdist, bdist, bdist_egg, etc), with lots 
  of combinations of setup.cfg and MANIFEST.in file entries.</p>
  
  <p>The closest I got was with the below setup file, that would subclass the bdist_egg 
  command in order to remove also .pyc files, but that is breaking the installation.</p>
  
  <p>A solution that  installs "manually" the files in the venv is 
  also good, provided that all ancillary files that are included in a proper
  installation are covered (I need to run <code>pip freeze</code> in the venv and see
  <code>mymod==0.0.1</code>).</p>
  
  <p>Run it with:</p>
  
  <pre><code>python setup.py bdist_egg --exclude-source-files
  </code></pre>
  
  <p>and (try to) install it with </p>
  
  <pre><code>easy_install mymod-0.0.1-py2.7-linux-x86_64.egg
  </code></pre>
  
  <p>As you may notice, the target is linux 64 bits with python 2.7.</p>
  
  <pre><code>from Cython.Distutils import build_ext
  from setuptools import setup, find_packages
  from setuptools.extension import Extension
  from setuptools.command import bdist_egg
  from setuptools.command.bdist_egg import  walk_egg, log 
  import os
  
  class my_bdist_egg(bdist_egg.bdist_egg):
  
      def zap_pyfiles(self):
          log.info("Removing .py files from temporary directory")
          for base, dirs, files in walk_egg(self.bdist_dir):
              for name in files:
                  if not name.endswith('__init__.py'):
                      if name.endswith('.py') or name.endswith('.pyc'):
                          # original 'if' only has name.endswith('.py')
                          path = os.path.join(base, name)
                          log.info("Deleting %s",path)
                          os.unlink(path)
  
  ext_modules=[
      Extension("mypack.mymod", ["mypack/mymod.py"]),
  ]
  
  setup(
    name = 'mypack',
    cmdclass = {'build_ext': build_ext, 
                'bdist_egg': my_bdist_egg },
    ext_modules = ext_modules,
    version='0.0.1',
    description='This is mypack compiled lib',
    author='Myself',
    packages=['mypack'],
  )
  </code></pre>
  
  <p>UPDATE.
  Following @Teyras answer, it was possible to build a wheel as requested in the answer. The <code>setup.py</code> file contents are:</p>
  
  <pre><code>import os
  import shutil
  from setuptools.extension import Extension
  from setuptools import setup
  from Cython.Build import cythonize
  from Cython.Distutils import build_ext
  
  class MyBuildExt(build_ext):
      def run(self):
          build_ext.run(self)
          build_dir = os.path.realpath(self.build_lib)
          root_dir = os.path.dirname(os.path.realpath(__file__))
          target_dir = build_dir if not self.inplace else root_dir
          self.copy_file('mypack/__init__.py', root_dir, target_dir)
  
      def copy_file(self, path, source_dir, destination_dir):
          if os.path.exists(os.path.join(source_dir, path)):
              shutil.copyfile(os.path.join(source_dir, path), 
                              os.path.join(destination_dir, path))
  
  
  setup(
    name = 'mypack',
    cmdclass = {'build_ext': MyBuildExt},
    ext_modules = cythonize([Extension("mypack.*", ["mypack/*.py"])]),
    version='0.0.1',
    description='This is mypack compiled lib',
    author='Myself',
    packages=[],
    include_package_data=True )
  </code></pre>
  
  <p>The key point was to set <code>packages=[],</code>. The overwriting of the <code>build_ext</code> class <code>run</code> method was needed to get the <code>__init__.py</code> file inside the wheel.</p>