Skip to content
Browse files

Initial checkin of setuptools 0.0.1.

branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4040869
  • Loading branch information...
PJ Eby
PJ Eby committed Mar 19, 2004
0 parents commit 8423e1ed14ac1691c2863c6e8cac9230cf558d7b
@@ -0,0 +1,58 @@

* Automatic download and installation of dependencies

* install_deps command (install runtime dependencies)

* compute child command line, abort if user specified incompatible options

* OPEN ISSUE: should parent install command include child install's files?

* Dependency class

* Check for presence/version via file existence, regular expression match,
version comparison (using 'distutils.version' classes), installed on
sys.path, or require just installation directory

* Find appropriate release, or explain why not

* Base URL(s) and distribution name

* Release class

* Distro type - source v. binary (determine via extension?)

* Platform requirements, whether compiler needed (how can we check?)

* Download URL, default from extension + dependency

* Download + extract to target dir

* run child install

* build_deps command (install build-time dependencies)

* Build and install documentation sets

* Installation database similar to PEP 262

* Needs to write file *before* installing anything, so an aborted install
can be uninstalled. Possibly should use 'unknown' for all metadata, then
replace with real metadata once it's known.

* REQUIRES should probably just be list of dependencies

* Bootstrap module

The idea here is that you include the "bootstrap module" in your
distribution, and it downloads the right version of setuptools automatically
if a good-enough version isn't on sys.path. This would let you use
setuptools for your installer, without having to distribute the full
setuptools package. This would might look something like::

from boot_setuptools import require_version
require_version("0.6", "http://somewhere/setuptools-0.6.tar.gz")

from setuptools import setup, Feature, findPackages
# ...etc

@@ -0,0 +1,21 @@
#!/usr/bin/env python

"""Distutils setup file, used to install or test 'setuptools'"""

from setuptools import setup, find_packages, Require


description="Distutils enhancements",
author="Phillip J. Eby",
license="PSF or ZPL",

test_suite = 'setuptools.tests.test_suite',
requires = [Require('Distutils','1.0.3','distutils')],
packages = find_packages(),
py_modules = ['setuptools_boot'],

@@ -0,0 +1,82 @@
"""Extensions to the 'distutils' for large or complex distributions"""

import distutils.core, setuptools.command
from setuptools.dist import Distribution, Feature
from setuptools.extension import Extension
from setuptools.depends import Require
from distutils.core import Command
from distutils.util import convert_path
import os.path

__version__ = '0.0.1'

__all__ = [
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',

def find_packages(where='.'):
"""Return a list all Python packages found within directory 'where'
'where' should be supplied as a "cross-platform" (i.e. URL-style) path; it
will be converted to the appropriate local path syntax.

out = []
stack=[(convert_path(where), '')]

while stack:
where,prefix = stack.pop(0)
for name in os.listdir(where):
fn = os.path.join(where,name)
if (os.path.isdir(fn) and
out.append(prefix+name); stack.append((fn,prefix+name+'.'))
return out

def setup(**attrs):
"""Do package setup
This function takes the same arguments as 'distutils.core.setup()', except
that the default distribution class is 'setuptools.dist.Distribution'. See
that class' documentation for details on the new keyword arguments that it
makes available via this function.
return distutils.core.setup(**attrs)

@@ -0,0 +1,11 @@
import distutils.command

__all__ = ['test', 'depends']

# Make our commands available as though they were part of the distutils

[cmd for cmd in __all__ if cmd not in distutils.command.__all__]
@@ -0,0 +1,7 @@
# Attempt to use Pyrex for building extensions, if available

from Pyrex.Distutils.build_ext import build_ext
except ImportError:
from distutils.command.build_ext import build_ext

@@ -0,0 +1,123 @@
from distutils.command.build_py import build_py as _build_py
from distutils.util import convert_path
from glob import glob
import os.path

class build_py(_build_py):

"""Enhanced 'build_py' command that includes data files with packages
The data files are specified via a 'package_data' argument to 'setup()'.
See 'setuptools.dist.Distribution' for more details.
Also, this version of the 'build_py' command allows you to specify both
'py_modules' and 'packages' in the same setup operation.

def finalize_options(self):
self.package_data = self.distribution.package_data
self.data_files = self.get_data_files()

def run(self):

"""Build modules, packages, and copy data files to build directory"""

if not self.py_modules and not self.packages:

if self.py_modules:

if self.packages:

# Only compile actual .py files, using our base class' idea of what our
# output files are.

def get_data_files(self):

"""Generate list of '(package,src_dir,build_dir,filenames)' tuples"""

data = []

for package in self.packages:
# Locate package source directory
src_dir = self.get_package_dir(package)

# Compute package build directory
build_dir = os.path.join(*([self.build_lib]+package.split('.')))

# Length of path to strip from found files
plen = len(src_dir)+1

# Strip directory from globbed filenames
filenames = [
file[plen:] for file in self.find_data_files(package, src_dir)

data.append( (package, src_dir, build_dir, filenames) )

return data

def find_data_files(self, package, src_dir):

"""Return filenames for package's data files in 'src_dir'"""

globs = self.package_data.get('',[])+self.package_data.get(package,[])
files = []

for pattern in globs:
# Each pattern has to be converted to a platform-specific path
files.extend(glob(os.path.join(src_dir, convert_path(pattern))))

return files

def build_package_data(self):

"""Copy data files into build directory"""

lastdir = None

for package, src_dir, build_dir, filenames in self.data_files:

for filename in filenames:
target = os.path.join(build_dir,filename)
self.copy_file(os.path.join(src_dir,filename), target)

def get_outputs(self, include_bytecode=1):

"""Return complete list of files copied to the build directory
This includes both '.py' files and data files, as well as '.pyc' and
'.pyo' files if 'include_bytecode' is true. (This method is needed for
the 'install_lib' command to do its job properly, and to generate a
correct installation manifest.)

return _build_py.get_outputs(self,include_bytecode) + [
for package,src_dir,build_dir,filenames in self.data_files
for filename in filenames

@@ -0,0 +1,27 @@
from distutils.cmd import Command
import os

class depends(Command):
"""Download and install dependencies, if needed"""

description = "download and install dependencies, if needed"

user_options = [
('temp=', 't',
"directory where dependencies will be downloaded and built"),
('ignore-extra-args', 'i',
"ignore options that won't be passed to child setup scripts"),

def initialize_options(self):
self.temp = None
self.install_purelib = self.install_platlib = None
self.install_lib = self.install_libbase = None
self.install_scripts = self.install_data = self.install_headers = None
self.compiler = self.debug = self.force = None

def finalize_options(self):
self.set_undefined_options('build',('build_temp', 'temp'))

def run(self):
self.announce("downloading and building here")
@@ -0,0 +1,11 @@
from distutils.command.install import install as _install

class install(_install):
"""Build dependencies before installation"""

def has_dependencies(self):
return self.distribution.has_dependencies()

sub_commands = [('depends',has_dependencies)] + _install.sub_commands

@@ -0,0 +1,17 @@
from distutils.command.install_lib import install_lib as _install_lib

class install_lib(_install_lib):
"""Don't add compiled flags to filenames of non-Python files"""

def _bytecode_filenames (self, py_filenames):
bytecode_files = []
for py_file in py_filenames:
if not py_file.endswith('.py'):
if self.compile:
bytecode_files.append(py_file + "c")
if self.optimize > 0:
bytecode_files.append(py_file + "o")

return bytecode_files

0 comments on commit 8423e1e

Please sign in to comment.
You can’t perform that action at this time.