Reorganized setup.py code

Added "deb" setup command
This commit is contained in:
Luke Campagnola 2014-01-12 10:35:31 -05:00
parent 33e4a9e213
commit 7a45b9a0e2
4 changed files with 304 additions and 165 deletions

3
.gitignore vendored
View File

@ -2,3 +2,6 @@ __pycache__
build build
*.pyc *.pyc
*.swp *.swp
MANIFEST
deb_build
dist

230
setup.py
View File

@ -1,105 +1,4 @@
from distutils.core import setup DESCRIPTION = """\
import distutils.dir_util
import os, sys, re
from subprocess import check_output
## generate list of all sub-packages
path = os.path.abspath(os.path.dirname(__file__))
n = len(path.split(os.path.sep))
subdirs = [i[0].split(os.path.sep)[n:] for i in os.walk(os.path.join(path, 'pyqtgraph')) if '__init__.py' in i[2]]
all_packages = ['.'.join(p) for p in subdirs] + ['pyqtgraph.examples']
## Make sure build directory is clean before installing
buildPath = os.path.join(path, 'build')
if os.path.isdir(buildPath):
distutils.dir_util.remove_tree(buildPath)
## Determine current version string
initfile = os.path.join(path, 'pyqtgraph', '__init__.py')
init = open(initfile).read()
m = re.search(r'__version__ = (\S+)\n', init)
if m is None or len(m.groups()) != 1:
raise Exception("Cannot determine __version__ from init file: '%s'!" % initfile)
version = m.group(1).strip('\'\"')
initVersion = version
# If this is a git checkout, try to generate a more decriptive version string
try:
if os.path.isdir(os.path.join(path, '.git')):
def gitCommit(name):
commit = check_output(['git', 'show', name], universal_newlines=True).split('\n')[0]
assert commit[:7] == 'commit '
return commit[7:]
# Find last tag matching "pyqtgraph-.*"
tagNames = check_output(['git', 'tag'], universal_newlines=True).strip().split('\n')
while True:
if len(tagNames) == 0:
raise Exception("Could not determine last tagged version.")
lastTagName = tagNames.pop()
if re.match(r'pyqtgraph-.*', lastTagName):
break
# is this commit an unchanged checkout of the last tagged version?
lastTag = gitCommit(lastTagName)
head = gitCommit('HEAD')
if head != lastTag:
branch = re.search(r'\* (.*)', check_output(['git', 'branch'], universal_newlines=True)).group(1)
version = version + "-%s-%s" % (branch, head[:10])
# any uncommitted modifications?
modified = False
status = check_output(['git', 'status', '-s'], universal_newlines=True).strip().split('\n')
for line in status:
if line[:2] != '??':
modified = True
break
if modified:
version = version + '+'
sys.stderr.write("Detected git commit; will use version string: '%s'\n" % version)
except:
version = initVersion
sys.stderr.write("This appears to be a git checkout, but an error occurred "
"while attempting to determine a version string for the "
"current commit.\nUsing the unmodified version string "
"instead: '%s'\n" % version)
sys.excepthook(*sys.exc_info())
import distutils.command.build
class Build(distutils.command.build.build):
def run(self):
ret = distutils.command.build.build.run(self)
# If the version in __init__ is different from the automatically-generated
# version string, then we will update __init__ in the build directory
global path, version, initVersion
if initVersion == version:
return ret
initfile = os.path.join(path, self.build_lib, 'pyqtgraph', '__init__.py')
if not os.path.isfile(initfile):
sys.stderr.write("Warning: setup detected a git install and attempted "
"to generate a descriptive version string; however, "
"the expected build file at %s was not found. "
"Installation will use the original version string "
"%s instead.\n" % (initfile, initVersion)
)
else:
data = open(initfile, 'r').read()
open(initfile, 'w').write(re.sub(r"__version__ = .*", "__version__ = '%s'" % version, data))
return ret
setup(name='pyqtgraph',
version=version,
cmdclass={'build': Build},
description='Scientific Graphics and GUI Library for Python',
long_description="""\
PyQtGraph is a pure-python graphics and GUI library built on PyQt4/PySide and PyQtGraph is a pure-python graphics and GUI library built on PyQt4/PySide and
numpy. numpy.
@ -107,14 +6,16 @@ It is intended for use in mathematics / scientific / engineering applications.
Despite being written entirely in python, the library is very fast due to its Despite being written entirely in python, the library is very fast due to its
heavy leverage of numpy for number crunching, Qt's GraphicsView framework for heavy leverage of numpy for number crunching, Qt's GraphicsView framework for
2D display, and OpenGL for 3D display. 2D display, and OpenGL for 3D display.
""", """
setupOpts = dict(
name='pyqtgraph',
description='Scientific Graphics and GUI Library for Python',
long_description=DESCRIPTION,
license='MIT', license='MIT',
url='http://www.pyqtgraph.org', url='http://www.pyqtgraph.org',
author='Luke Campagnola', author='Luke Campagnola',
author_email='luke.campagnola@gmail.com', author_email='luke.campagnola@gmail.com',
packages=all_packages,
package_dir={'pyqtgraph.examples': 'examples'}, ## install examples along with the rest of the source
#package_data={'pyqtgraph': ['graphicsItems/PlotItem/*.png']},
classifiers = [ classifiers = [
"Programming Language :: Python", "Programming Language :: Python",
"Programming Language :: Python :: 2", "Programming Language :: Python :: 2",
@ -130,9 +31,126 @@ heavy leverage of numpy for number crunching, Qt's GraphicsView framework for
"Topic :: Scientific/Engineering :: Visualization", "Topic :: Scientific/Engineering :: Visualization",
"Topic :: Software Development :: User Interfaces", "Topic :: Software Development :: User Interfaces",
], ],
)
from distutils.core import setup
import distutils.dir_util
import os, sys, re
path = os.path.split(__file__)[0]
sys.path.insert(0, os.path.join(path, 'tools'))
import setupHelpers as helpers
## generate list of all sub-packages
allPackages = helpers.listAllPackages(pkgroot='pyqtgraph') + ['pyqtgraph.examples']
## Decide what version string to use in the build
version, forcedVersion, gitVersion, initVersion = helpers.getVersionStrings(pkg='pyqtgraph')
import distutils.command.build
class Build(distutils.command.build.build):
"""
* Clear build path before building
* Set version string in __init__ after building
"""
def run(self):
global path, version, initVersion, forcedVersion
global buildVersion
## Make sure build directory is clean
buildPath = os.path.join(path, self.build_lib)
if os.path.isdir(buildPath):
distutils.dir_util.remove_tree(buildPath)
ret = distutils.command.build.build.run(self)
# If the version in __init__ is different from the automatically-generated
# version string, then we will update __init__ in the build directory
if initVersion == version:
return ret
try:
initfile = os.path.join(buildPath, 'pyqtgraph', '__init__.py')
data = open(initfile, 'r').read()
open(initfile, 'w').write(re.sub(r"__version__ = .*", "__version__ = '%s'" % version, data))
buildVersion = version
except:
if forcedVersion:
raise
buildVersion = initVersion
sys.stderr.write("Warning: Error occurred while setting version string in build path. "
"Installation will use the original version string "
"%s instead.\n" % (initVersion)
)
sys.excepthook(*sys.exc_info())
return ret
from distutils.core import Command
import shutil, subprocess
class DebCommand(Command):
description = "build .deb package"
user_options = []
def initialize_options(self):
self.cwd = None
def finalize_options(self):
self.cwd = os.getcwd()
def run(self):
assert os.getcwd() == self.cwd, 'Must be in package root: %s' % self.cwd
global version
pkgName = "python-pyqtgraph-" + version
debDir = "deb_build"
if os.path.isdir(debDir):
raise Exception('DEB build dir already exists: "%s"' % debDir)
sdist = "dist/pyqtgraph-%s.tar.gz" % version
if not os.path.isfile(sdist):
raise Exception("No source distribution; run `setup.py sdist` first.")
# copy sdist to build directory and extract
os.mkdir(debDir)
renamedSdist = 'python-pyqtgraph_%s.orig.tar.gz' % version
shutil.copy(sdist, os.path.join(debDir, renamedSdist))
if os.system("cd %s; tar -xzf %s" % (debDir, renamedSdist)) != 0:
raise Exception("Error extracting source distribution.")
buildDir = '%s/pyqtgraph-%s' % (debDir, version)
# copy debian control structure
shutil.copytree('tools/debian', buildDir+'/debian')
# Write changelog
#chlog = subprocess.check_output([sys.executable, 'tools/generateChangelog.py', 'CHANGELOG'])
#open('%s/pyqtgraph-%s/debian/changelog', 'w').write(chlog)
if os.system('python tools/generateChangelog.py CHANGELOG %s > %s/debian/changelog' % (version, buildDir)) != 0:
raise Exception("Error writing debian/changelog")
# build package
if os.system('cd %s; debuild -us -uc' % buildDir) != 0:
raise Exception("Error during debuild.")
class TestCommand(Command):
description = ""
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
global cmd
cmd = self
setup(
version=version,
cmdclass={'build': Build, 'deb': DebCommand, 'test': TestCommand},
packages=allPackages,
package_dir={'pyqtgraph.examples': 'examples'}, ## install examples along with the rest of the source
#package_data={'pyqtgraph': ['graphicsItems/PlotItem/*.png']},
install_requires = [ install_requires = [
'numpy', 'numpy',
'scipy', 'scipy',
], ],
**setupOpts
) )

View File

@ -1,66 +1,70 @@
from subprocess import check_output import re, time, sys
import re, time if len(sys.argv) < 3:
sys.stderr.write("Must specify changelog file and latest release!\n")
sys.exit(-1)
def run(cmd): ### Convert CHANGELOG format like:
return check_output(cmd, shell=True) """
pyqtgraph-0.9.1 2012-12-29
tags = run('bzr tags') - change
versions = [] - change
for tag in tags.split('\n'): """
if tag.strip() == '':
continue
ver, rev = re.split(r'\s+', tag)
if ver.startswith('pyqtgraph-'):
versions.append(ver)
for i in range(len(versions)-1)[::-1]: ### to debian changelog format:
log = run('bzr log -r tag:%s..tag:%s' % (versions[i], versions[i+1])) """
changes = [] python-pyqtgraph (0.9.1-1) UNRELEASED; urgency=low
times = []
inmsg = False
for line in log.split('\n'):
if line.startswith('message:'):
inmsg = True
continue
elif line.startswith('-----------------------'):
inmsg = False
continue
if inmsg:
changes.append(line)
else:
m = re.match(r'timestamp:\s+(.*)$', line)
if m is not None:
times.append(m.groups()[0])
citime = time.strptime(times[0][:-6], '%a %Y-%m-%d %H:%M:%S')
print "python-pyqtgraph (%s-1) UNRELEASED; urgency=low" % versions[i+1].split('-')[1]
print ""
for line in changes:
for n in range(len(line)):
if line[n] != ' ':
n += 1
break
words = line.split(' ')
nextline = ''
for w in words:
if len(w) + len(nextline) > 79:
print nextline
nextline = (' '*n) + w
else:
nextline += ' ' + w
print nextline
#print '\n'.join(changes)
print ""
print " -- Luke <luke.campagnola@gmail.com> %s -0%d00" % (time.strftime('%a, %d %b %Y %H:%M:%S', citime), time.timezone/3600)
#print " -- Luke <luke.campagnola@gmail.com> %s -0%d00" % (times[0], time.timezone/3600)
print ""
print """python-pyqtgraph (0.9.0-1) UNRELEASED; urgency=low
* Initial release. * Initial release.
-- Luke <luke.campagnola@gmail.com> Thu, 27 Dec 2012 02:46:26 -0500""" -- Luke <luke.campagnola@gmail.com> Sat, 29 Dec 2012 01:07:23 -0500
"""
releases = []
current_version = None
current_log = None
current_date = None
for line in open(sys.argv[1]).readlines():
match = re.match(r'pyqtgraph-(\d+\.\d+\.\d+(\.\d+)?)\s*(\d+-\d+-\d+)\s*$', line)
if match is None:
if current_log is not None:
current_log.append(line)
else:
if current_log is not None:
releases.append((current_version, current_log, current_date))
current_version, current_date = match.groups()[0], match.groups()[2]
#sys.stderr.write("Found release %s\n" % current_version)
current_log = []
if releases[0][0] != sys.argv[2]:
sys.stderr.write("Latest release in changelog (%s) does not match current release (%s)\n" % (releases[0][0], sys.argv[2]))
sys.exit(-1)
for release, changes, date in releases:
date = time.strptime(date, '%Y-%m-%d')
changeset = [
"python-pyqtgraph (%s-1) UNRELEASED; urgency=low\n" % release,
"\n"] + changes + [
" -- Luke <luke.campagnola@gmail.com> %s -0%d00\n" % (time.strftime('%a, %d %b %Y %H:%M:%S', date), time.timezone/3600),
"\n" ]
# remove consecutive blank lines except between releases
clean = ""
lastBlank = True
for line in changeset:
if line.strip() == '':
if lastBlank:
continue
else:
clean += line
lastBlank = True
else:
clean += line
lastBlank = False
print clean
print ""

114
tools/setupHelpers.py Normal file
View File

@ -0,0 +1,114 @@
import os, sys, re
from subprocess import check_output
def listAllPackages(pkgroot):
path = os.getcwd()
n = len(path.split(os.path.sep))
subdirs = [i[0].split(os.path.sep)[n:] for i in os.walk(os.path.join(path, pkgroot)) if '__init__.py' in i[2]]
return ['.'.join(p) for p in subdirs]
def getInitVersion(pkgroot):
"""Return the version string defined in __init__.py"""
path = os.getcwd()
initfile = os.path.join(path, pkgroot, '__init__.py')
init = open(initfile).read()
m = re.search(r'__version__ = (\S+)\n', init)
if m is None or len(m.groups()) != 1:
raise Exception("Cannot determine __version__ from init file: '%s'!" % initfile)
version = m.group(1).strip('\'\"')
return version
def gitCommit(name):
"""Return the commit ID for the given name."""
commit = check_output(['git', 'show', name], universal_newlines=True).split('\n')[0]
assert commit[:7] == 'commit '
return commit[7:]
def getGitVersion(tagPrefix):
"""Return a version string with information about this git checkout.
If the checkout is an unmodified, tagged commit, then return the tag version.
If this is not a tagged commit, return version-branch_name-commit_id.
If this checkout has been modified, append "+" to the version.
"""
path = os.getcwd()
if not os.path.isdir(os.path.join(path, '.git')):
return None
# Find last tag matching "tagPrefix.*"
tagNames = check_output(['git', 'tag'], universal_newlines=True).strip().split('\n')
while True:
if len(tagNames) == 0:
raise Exception("Could not determine last tagged version.")
lastTagName = tagNames.pop()
if re.match(tagPrefix+r'\d+\.\d+.*', lastTagName):
break
gitVersion = lastTagName.replace(tagPrefix, '')
# is this commit an unchanged checkout of the last tagged version?
lastTag = gitCommit(lastTagName)
head = gitCommit('HEAD')
if head != lastTag:
branch = re.search(r'\* (.*)', check_output(['git', 'branch'], universal_newlines=True)).group(1)
gitVersion = gitVersion + "-%s-%s" % (branch, head[:10])
# any uncommitted modifications?
modified = False
status = check_output(['git', 'status', '-s'], universal_newlines=True).strip().split('\n')
for line in status:
if line[:2] != '??':
modified = True
break
if modified:
gitVersion = gitVersion + '+'
return gitVersion
def getVersionStrings(pkg):
"""
Returns 4 version strings:
* the version string to use for this build,
* version string requested with --force-version (or None)
* version string that describes the current git checkout (or None).
* version string in the pkg/__init__.py,
The first return value is (forceVersion or gitVersion or initVersion).
"""
## Determine current version string from __init__.py
initVersion = getInitVersion(pkgroot='pyqtgraph')
## If this is a git checkout, try to generate a more descriptive version string
try:
gitVersion = getGitVersion(tagPrefix='pyqtgraph-')
except:
gitVersion = None
sys.stderr.write("This appears to be a git checkout, but an error occurred "
"while attempting to determine a version string for the "
"current commit.\n")
sys.excepthook(*sys.exc_info())
# See whether a --force-version flag was given
forcedVersion = None
for i,arg in enumerate(sys.argv):
if arg.startswith('--force-version'):
if arg == '--force-version':
forcedVersion = sys.argv[i+1]
sys.argv.pop(i)
sys.argv.pop(i)
elif arg.startswith('--force-version='):
forcedVersion = sys.argv[i].replace('--force-version=', '')
sys.argv.pop(i)
## Finally decide on a version string to use:
if forcedVersion is not None:
version = forcedVersion
elif gitVersion is not None:
version = gitVersion
sys.stderr.write("Detected git commit; will use version string: '%s'\n" % version)
else:
version = initVersion
return version, forcedVersion, gitVersion, initVersion