Merge branch 'setup-cleanup' into devel

This commit is contained in:
Daniele Varrazzo 2011-06-07 23:58:58 +01:00
commit 178698f9e8
2 changed files with 190 additions and 175 deletions

2
NEWS
View File

@ -18,6 +18,8 @@ What's new in psycopg 2.4.2
- Trying to execute concurrent operations on the same connection
through concurrent green thread results in an error instead of a
deadlock.
- Fixed detection of pg_config on Window. Report and fix, plus some
long needed setup.py cleanup by Steve Lacy: thanks!
What's new in psycopg 2.4.1

363
setup.py
View File

@ -45,21 +45,15 @@ Operating System :: Unix
# Note: The setup.py must be compatible with both Python 2 and 3
import os
import os.path
import sys
import re
import subprocess
from distutils.core import setup, Extension
from distutils.errors import DistutilsFileError
from distutils.command.build_ext import build_ext
from distutils.sysconfig import get_python_inc
from distutils.ccompiler import get_default_compiler
from distutils.dep_util import newer_group
from distutils.util import get_platform
try:
from distutils.msvc9compiler import MSVCCompiler
except ImportError:
MSVCCompiler = None
try:
from distutils.command.build_py import build_py_2to3 as build_py
except ImportError:
@ -85,21 +79,129 @@ version_flags = ['dt', 'dec']
PLATFORM_IS_WINDOWS = sys.platform.lower().startswith('win')
def get_pg_config(kind, pg_config):
try:
p = subprocess.Popen([pg_config, "--" + kind],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
except OSError:
raise Warning("Unable to find 'pg_config' file in '%s'" % pg_config)
p.stdin.close()
r = p.stdout.readline().strip()
if not r:
raise Warning(p.stderr.readline())
if not isinstance(r, str):
r = r.decode('ascii')
return r
class PostgresConfig:
def __init__(self, build_ext):
self.build_ext = build_ext
self.pg_config_exe = self.build_ext.pg_config
if not self.pg_config_exe:
self.pg_config_exe = self.autodetect_pg_config_path()
if self.pg_config_exe is None:
sys.stderr.write("""\
Error: pg_config executable not found.
Please add the directory containing pg_config to the PATH
or specify the full executable path with the option:
python setup.py build_ext --pg-config /path/to/pg_config build ...
or with the pg_config option in 'setup.cfg'.
""")
sys.exit(1)
def query(self, attr_name):
"""Spawn the pg_config executable, querying for the given config
name, and return the printed value, sanitized. """
try:
pg_config_process = subprocess.Popen(
[self.pg_config_exe, "--" + attr_name],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
except OSError:
raise Warning("Unable to find 'pg_config' file in '%s'" %
self.pg_config_exe)
pg_config_process.stdin.close()
result = pg_config_process.stdout.readline().strip()
if not result:
raise Warning(pg_config_process.stderr.readline())
if not isinstance(result, str):
result = result.decode('ascii')
return result
def find_on_path(self, exename, path_directories=None):
if not path_directories:
path_directories = os.environ['PATH'].split(os.pathsep)
for dir_name in path_directories:
fullpath = os.path.join(dir_name, exename)
if os.path.isfile(fullpath):
return fullpath
return None
def autodetect_pg_config_path(self):
"""Find and return the path to the pg_config executable."""
if PLATFORM_IS_WINDOWS:
return self.autodetect_pg_config_path_windows()
else:
return self.find_on_path('pg_config')
def autodetect_pg_config_path_windows(self):
"""Attempt several different ways of finding the pg_config
executable on Windows, and return its full path, if found."""
# This code only runs if they have not specified a pg_config option
# in the config file or via the commandline.
# First, check for pg_config.exe on the PATH, and use that if found.
pg_config_exe = self.find_on_path('pg_config.exe')
if pg_config_exe:
return pg_config_exe
# Now, try looking in the Windows Registry to find a PostgreSQL
# installation, and infer the path from that.
pg_config_exe = self._get_pg_config_from_registry()
if pg_config_exe:
return pg_config_exe
return None
def _get_pg_config_from_registry(self):
try:
import winreg
except ImportError:
import _winreg as winreg
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
try:
pg_inst_list_key = winreg.OpenKey(reg,
'SOFTWARE\\PostgreSQL\\Installations')
except EnvironmentError:
# No PostgreSQL installation, as best as we can tell.
return None
try:
# Determine the name of the first subkey, if any:
try:
first_sub_key_name = winreg.EnumKey(pg_inst_list_key, 0)
except EnvironmentError:
return None
pg_first_inst_key = winreg.OpenKey(reg,
'SOFTWARE\\PostgreSQL\\Installations\\'
+ first_sub_key_name)
try:
pg_inst_base_dir = winreg.QueryValueEx(
pg_first_inst_key, 'Base Directory')[0]
finally:
winreg.CloseKey(pg_first_inst_key)
finally:
winreg.CloseKey(pg_inst_list_key)
pg_config_path = os.path.join(
pg_inst_base_dir, 'bin', 'pg_config.exe')
if not os.path.exists(pg_config_path):
return None
# Support unicode paths, if this version of Python provides the
# necessary infrastructure:
if sys.version_info[0] < 3 \
and hasattr(sys, 'getfilesystemencoding'):
pg_config_path = pg_config_path.encode(
sys.getfilesystemencoding())
return pg_config_path
class psycopg_build_ext(build_ext):
"""Conditionally complement the setup.cfg options file.
@ -126,6 +228,9 @@ class psycopg_build_ext(build_ext):
boolean_options = build_ext.boolean_options[:]
boolean_options.extend(('use-pydatetime', 'have-ssl', 'static-libpq'))
def __init__(self, *args, **kwargs):
build_ext.__init__(self, *args, **kwargs)
def initialize_options(self):
build_ext.initialize_options(self)
self.use_pg_dll = 1
@ -136,7 +241,13 @@ class psycopg_build_ext(build_ext):
self.static_libpq = static_libpq
self.pg_config = None
def get_compiler(self):
def compiler_is_msvc(self):
return self.get_compiler_name().lower().startswith('msvc')
def compiler_is_mingw(self):
return self.get_compiler_name().lower().startswith('mingw')
def get_compiler_name(self):
"""Return the name of the C compiler used to compile extensions.
If a compiler was not explicitly set (on the command line, for
@ -153,43 +264,39 @@ class psycopg_build_ext(build_ext):
name = get_default_compiler()
return name
def get_pg_config(self, kind):
return get_pg_config(kind, self.pg_config)
def get_export_symbols(self, ext):
def get_export_symbols(self, extension):
# Fix MSVC seeing two of the same export symbols.
if self.get_compiler().lower().startswith('msvc'):
if self.compiler_is_msvc():
return []
else:
return build_ext.get_export_symbols(self, ext)
return build_ext.get_export_symbols(self, extension)
def build_extension(self, ext):
build_ext.build_extension(self, ext)
def build_extension(self, extension):
build_ext.build_extension(self, extension)
# For Python versions that use MSVC compiler 2008, re-insert the
# manifest into the resulting .pyd file.
if MSVCCompiler and isinstance(self.compiler, MSVCCompiler):
# manifest into the resulting .pyd file.
if self.compiler_is_msvc():
platform = get_platform()
# Default to the x86 manifest
manifest = '_psycopg.vc9.x86.manifest'
if platform == 'win-amd64':
manifest = '_psycopg.vc9.amd64.manifest'
self.compiler.spawn(['mt.exe', '-nologo', '-manifest',
os.path.join('psycopg', manifest),
'-outputresource:%s;2' % (os.path.join(self.build_lib, 'psycopg2', '_psycopg.pyd'))])
self.compiler.spawn(
['mt.exe', '-nologo', '-manifest',
os.path.join('psycopg', manifest),
'-outputresource:%s;2' % (
os.path.join(self.build_lib,
'psycopg2', '_psycopg.pyd'))])
def finalize_win32(self):
"""Finalize build system configuration on win32 platform."""
import struct
sysVer = sys.version_info[:2]
# Add compiler-specific arguments:
extra_compiler_args = []
compiler_name = self.get_compiler().lower()
compiler_is_msvc = compiler_name.startswith('msvc')
compiler_is_mingw = compiler_name.startswith('mingw')
if compiler_is_mingw:
if self.compiler_is_mingw():
# Default MinGW compilation of Python extensions on Windows uses
# only -O:
extra_compiler_args.append('-O3')
@ -201,23 +308,23 @@ class psycopg_build_ext(build_ext):
extra_compiler_args.append('-fno-strict-aliasing')
# Force correct C runtime library linkage:
if sysVer <= (2,3):
if sysVer <= (2, 3):
# Yes: 'msvcr60', rather than 'msvcrt', is the correct value
# on the line below:
self.libraries.append('msvcr60')
elif sysVer in ((2,4), (2,5)):
elif sysVer in ((2, 4), (2, 5)):
self.libraries.append('msvcr71')
# Beyond Python 2.5, we take our chances on the default C runtime
# library, because we don't know what compiler those future
# versions of Python will use.
for exten in ext: # ext is a global list of Extension objects
exten.extra_compile_args.extend(extra_compiler_args)
for extension in ext: # ext is a global list of Extension objects
extension.extra_compile_args.extend(extra_compiler_args)
# End of add-compiler-specific arguments section.
self.libraries.append("ws2_32")
self.libraries.append("advapi32")
if compiler_is_msvc:
if self.compiler_is_msvc():
# MSVC requires an explicit "libpq"
self.libraries.remove("pq")
self.libraries.append("secur32")
@ -242,48 +349,39 @@ class psycopg_build_ext(build_ext):
def finalize_linux2(self):
"""Finalize build system configuration on GNU/Linux platform."""
# tell piro that GCC is fine and dandy, but not so MS compilers
for ext in self.extensions:
ext.extra_compile_args.append('-Wdeclaration-after-statement')
for extension in self.extensions:
extension.extra_compile_args.append(
'-Wdeclaration-after-statement')
def finalize_options(self):
"""Complete the build system configuation."""
build_ext.finalize_options(self)
if self.pg_config is None:
self.pg_config = self.autodetect_pg_config_path()
if self.pg_config is None:
sys.stderr.write("""\
Error: pg_config executable not found.
Please add the directory containing pg_config to the PATH
or specify the full executable path with the option:
python setup.py build_ext --pg-config /path/to/pg_config build ...
or with the pg_config option in 'setup.cfg'.
""")
sys.exit(1)
pg_config_helper = PostgresConfig(self)
self.include_dirs.append(".")
if self.static_libpq:
if not self.link_objects: self.link_objects = []
if not hasattr(self, 'link_objects'):
self.link_objects = []
self.link_objects.append(
os.path.join(self.get_pg_config("libdir"), "libpq.a"))
os.path.join(pg_config_helper.query("libdir"), "libpq.a"))
else:
self.libraries.append("pq")
try:
self.library_dirs.append(self.get_pg_config("libdir"))
self.include_dirs.append(self.get_pg_config("includedir"))
self.include_dirs.append(self.get_pg_config("includedir-server"))
self.library_dirs.append(pg_config_helper.query("libdir"))
self.include_dirs.append(pg_config_helper.query("includedir"))
self.include_dirs.append(pg_config_helper.query("includedir-server"))
try:
# Here we take a conservative approach: we suppose that
# *at least* PostgreSQL 7.4 is available (this is the only
# 7.x series supported by psycopg 2)
pgversion = self.get_pg_config("version").split()[1]
pgversion = pg_config_helper.query("version").split()[1]
except:
pgversion = "7.4.0"
verre = re.compile(r"(\d+)\.(\d+)(?:(?:\.(\d+))|(devel|(alpha|beta|rc)\d+))")
verre = re.compile(
r"(\d+)\.(\d+)(?:(?:\.(\d+))|(devel|(alpha|beta|rc)\d+))")
m = verre.match(pgversion)
if m:
pgmajor, pgminor, pgpatch = m.group(1, 2, 3)
@ -298,108 +396,21 @@ or with the pg_config option in 'setup.cfg'.
define_macros.append(("PG_VERSION_HEX", "0x%02X%02X%02X" %
(int(pgmajor), int(pgminor), int(pgpatch))))
except Warning:
w = sys.exc_info()[1] # work around py 2/3 different syntax
w = sys.exc_info()[1] # work around py 2/3 different syntax
sys.stderr.write("Error: %s\n" % w)
sys.exit(1)
if hasattr(self, "finalize_" + sys.platform):
getattr(self, "finalize_" + sys.platform)()
def autodetect_pg_config_path(self):
if PLATFORM_IS_WINDOWS:
return self.autodetect_pg_config_path_windows()
else:
return self.autodetect_pg_config_path_posix()
def autodetect_pg_config_path_posix(self):
exename = 'pg_config'
for dir in os.environ['PATH'].split(os.pathsep):
fn = os.path.join(dir, exename)
if os.path.isfile(fn):
return fn
def autodetect_pg_config_path_windows(self):
# Find the first PostgreSQL installation listed in the registry and
# return the full path to its pg_config utility.
#
# This autodetection is performed *only* if the following conditions
# hold:
#
# 1) The pg_config utility is not already available on the PATH:
if os.popen('pg_config').close() is None: # .close()->None == success
return None
# 2) The user has not specified any of the following settings in
# setup.cfg:
# - pg_config
# - include_dirs
# - library_dirs
for settingName in ('pg_config', 'include_dirs', 'library_dirs'):
try:
val = parser.get('build_ext', settingName)
except configparser.NoOptionError:
pass
else:
if val.strip() != '':
return None
# end of guard conditions
try:
import winreg
except ImportError:
import _winreg as winreg
pg_inst_base_dir = None
pg_config_path = None
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
try:
pg_inst_list_key = winreg.OpenKey(reg,
'SOFTWARE\\PostgreSQL\\Installations'
)
except EnvironmentError:
pg_inst_list_key = None
if pg_inst_list_key is not None:
try:
# Determine the name of the first subkey, if any:
try:
first_sub_key_name = winreg.EnumKey(pg_inst_list_key, 0)
except EnvironmentError:
first_sub_key_name = None
if first_sub_key_name is not None:
pg_first_inst_key = winreg.OpenKey(reg,
'SOFTWARE\\PostgreSQL\\Installations\\'
+ first_sub_key_name
)
try:
pg_inst_base_dir = winreg.QueryValueEx(
pg_first_inst_key, 'Base Directory'
)[0]
finally:
winreg.CloseKey(pg_first_inst_key)
finally:
winreg.CloseKey(pg_inst_list_key)
if pg_inst_base_dir and os.path.exists(pg_inst_base_dir):
pg_config_path = os.path.join(pg_inst_base_dir, 'bin',
'pg_config.exe'
)
# Support unicode paths, if this version of Python provides the
# necessary infrastructure:
if sys.version_info[0] < 3 \
and hasattr(sys, 'getfilesystemencoding'):
pg_config_path = pg_config_path.encode(
sys.getfilesystemencoding())
return pg_config_path
# let's start with macro definitions (the ones not already in setup.cfg)
define_macros = []
include_dirs = []
# gather information to build the extension module
ext = [] ; data_files = []
ext = []
data_files = []
# sources
@ -452,7 +463,7 @@ else:
if os.path.exists(mxincludedir):
# Build the support for mx: we will check at runtime if it can be imported
include_dirs.append(mxincludedir)
define_macros.append(('HAVE_MXDATETIME','1'))
define_macros.append(('HAVE_MXDATETIME', '1'))
sources.append('adapter_mxdatetime.c')
depends.extend(['adapter_mxdatetime.h', 'typecast_mxdatetime.c'])
have_mxdatetime = True
@ -460,18 +471,21 @@ if os.path.exists(mxincludedir):
# now decide which package will be the default for date/time typecasts
if have_pydatetime and (use_pydatetime or not have_mxdatetime):
define_macros.append(('PSYCOPG_DEFAULT_PYDATETIME','1'))
define_macros.append(('PSYCOPG_DEFAULT_PYDATETIME', '1'))
elif have_mxdatetime:
define_macros.append(('PSYCOPG_DEFAULT_MXDATETIME','1'))
define_macros.append(('PSYCOPG_DEFAULT_MXDATETIME', '1'))
else:
def e(msg):
sys.stderr.write("error: " + msg + "\n")
e("psycopg requires a datetime module:")
e(" mx.DateTime module not found")
e(" python datetime module not found")
e("Note that psycopg needs the module headers and not just the module")
e("itself. If you installed Python or mx.DateTime from a binary package")
e("you probably need to install its companion -dev or -devel package.")
error_message = """\
psycopg requires a datetime module:
mx.DateTime module not found
python datetime module not found
Note that psycopg needs the module headers and not just the module
itself. If you installed Python or mx.DateTime from a binary package
you probably need to install its companion -dev or -devel package."""
for line in error_message.split("\n"):
sys.stderr.write("error: " + line)
sys.exit(1)
# generate a nice version string to avoid confusion when users report bugs
@ -485,9 +499,9 @@ else:
PSYCOPG_VERSION_EX = PSYCOPG_VERSION
if not PLATFORM_IS_WINDOWS:
define_macros.append(('PSYCOPG_VERSION', '"'+PSYCOPG_VERSION_EX+'"'))
define_macros.append(('PSYCOPG_VERSION', '"' + PSYCOPG_VERSION_EX + '"'))
else:
define_macros.append(('PSYCOPG_VERSION', '\\"'+PSYCOPG_VERSION_EX+'\\"'))
define_macros.append(('PSYCOPG_VERSION', '\\"' + PSYCOPG_VERSION_EX + '\\"'))
if parser.has_option('build_ext', 'have_ssl'):
have_ssl = int(parser.get('build_ext', 'have_ssl'))
@ -525,17 +539,16 @@ setup(name="psycopg2",
author="Federico Di Gregorio",
author_email="fog@initd.org",
url="http://initd.org/psycopg/",
download_url = download_url,
download_url=download_url,
license="GPL with exceptions or ZPL",
platforms = ["any"],
platforms=["any"],
description=__doc__.split("\n")[0],
long_description="\n".join(__doc__.split("\n")[2:]),
classifiers=[x for x in classifiers.split("\n") if x],
data_files=data_files,
package_dir={'psycopg2':'lib', 'psycopg2.tests': 'tests'},
package_dir={'psycopg2': 'lib', 'psycopg2.tests': 'tests'},
packages=['psycopg2', 'psycopg2.tests'],
cmdclass={
'build_ext': psycopg_build_ext,
'build_py': build_py, },
ext_modules=ext)