From a2094b1b6fe9f93af3a044cfb34a53c82a2ca330 Mon Sep 17 00:00:00 2001 From: Philip Jenvey Date: Wed, 13 Apr 2011 18:32:15 -0700 Subject: [PATCH] enable the cextension by default, falling back to pure python when the extension fails to compile fixes #2129 --- CHANGES | 5 + README | 11 -- setup.py | 373 +++++++++++++++++++++++++++++++------------------------ 3 files changed, 216 insertions(+), 173 deletions(-) diff --git a/CHANGES b/CHANGES index 34704e27fc..16cd316c66 100644 --- a/CHANGES +++ b/CHANGES @@ -91,6 +91,11 @@ CHANGES will be coerced to integer. [ticket:2116] (also in 0.6.7) +- engine + - The C extension is now enabled by default with a + fallback to pure python if it fails to compile. + [ticket:2129] + - schema - The 'useexisting' flag on Table has been superceded by a new pair of flags 'keep_existing' and diff --git a/README b/README index 0c888c60db..f3d67529ae 100644 --- a/README +++ b/README @@ -35,17 +35,6 @@ To install:: To use without installation, include the ``lib`` directory in your Python path. -Installing the C extension --------------------------- - -If installing with Setuptools or Distribute, the C extensions are built -and installed using the --with-cextensions flag: - - python setup.py --with-cextensions install - -If using plain Distutils, change the BUILD_CEXTENSIONS flag in setup.py -to "True". - Running Tests ------------- diff --git a/setup.py b/setup.py index 69231d6278..f21b21454e 100644 --- a/setup.py +++ b/setup.py @@ -4,15 +4,12 @@ Please see README for basic installation instructions. """ -# If using distutils (not distribute/setuptools), -# set this flag to True to compile C extensions. -# Otherwise use --with-cextensions -BUILD_CEXTENSIONS = False - import os import re import sys - +from distutils.command.build_ext import build_ext +from distutils.errors import (CCompilerError, DistutilsExecError, + DistutilsPlatformError) try: from setuptools import setup, Extension, Feature except ImportError: @@ -32,6 +29,7 @@ elif sys.version_info >= (3, 0): extra.update( use_2to3=True, ) +IS_PYPY = hasattr(sys, 'pypy_translation_info') ext_modules = [ Extension('sqlalchemy.cprocessors', @@ -39,16 +37,34 @@ ext_modules = [ Extension('sqlalchemy.cresultproxy', sources=['lib/sqlalchemy/cextension/resultproxy.c']) ] -if Feature: - extra.update( - features={'cextensions': Feature( - "optional C speed-enhancements", - standard=False, - ext_modules=ext_modules - )} - ) -elif BUILD_CEXTENSIONS: - extra['ext_modules'] = ext_modules + +if sys.platform == 'win32' and sys.version_info > (2, 6): + # 2.6's distutils.msvc9compiler can raise an IOError when failing to + # find the compiler + ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, + IOError) +else: + ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError) + +class BuildFailed(Exception): + + def __init__(self, cause): + self.cause = cause + +class ve_build_ext(build_ext): + # This class allows C extension building to fail. + + def run(self): + try: + build_ext.run(self) + except DistutilsPlatformError, exc: + raise BuildFailed(exc) + + def build_extension(self, ext): + try: + build_ext.build_extension(self, ext) + except ext_errors, exc: + raise BuildFailed(exc) def find_packages(dir_): packages = [] @@ -65,149 +81,182 @@ VERSION = re.compile(r".*__version__ = '(.*?)'", re.S).match(v.read()).group(1) v.close() -setup(name="SQLAlchemy", - version=VERSION, - description="Database Abstraction Library", - author="Mike Bayer", - author_email="mike_mp@zzzcomputing.com", - url="http://www.sqlalchemy.org", - packages=find_packages('lib'), - package_dir={'': 'lib'}, - license="MIT License", - - tests_require=['nose >= 0.11'], - test_suite="sqla_nose", - - long_description="""\ -SQLAlchemy is: - - * The Python SQL toolkit and Object Relational Mapper - that gives application developers the full power and - flexibility of SQL. SQLAlchemy provides a full suite - of well known enterprise-level persistence patterns, - designed for efficient and high-performing database - access, adapted into a simple and Pythonic domain - language. - * extremely easy to use for all the basic tasks, such - as: accessing pooled connections, constructing SQL - from Python expressions, finding object instances, and - commiting object modifications back to the database. - * powerful enough for complicated tasks, such as: eager - load a graph of objects and their dependencies via - joins; map recursive adjacency structures - automatically; map objects to not just tables but to - any arbitrary join or select statement; combine - multiple tables together to load whole sets of - otherwise unrelated objects from a single result set; - commit entire graphs of object changes in one step. - * built to conform to what DBAs demand, including the - ability to swap out generated SQL with hand-optimized - statements, full usage of bind parameters for all - literal values, fully transactionalized and consistent - updates using Unit of Work. - * modular. Different parts of SQLAlchemy can be used - independently of the rest, including the connection - pool, SQL construction, and ORM. SQLAlchemy is - constructed in an open style that allows plenty of - customization, with an architecture that supports - custom datatypes, custom SQL extensions, and ORM - plugins which can augment or extend mapping - functionality. - -SQLAlchemy's Philosophy: - - * SQL databases behave less and less like object - collections the more size and performance start to - matter; object collections behave less and less like - tables and rows the more abstraction starts to matter. - SQLAlchemy aims to accomodate both of these - principles. - * Your classes aren't tables, and your objects aren't - rows. Databases aren't just collections of tables; - they're relational algebra engines. You don't have to - select from just tables, you can select from joins, - subqueries, and unions. Database and domain concepts - should be visibly decoupled from the beginning, - allowing both sides to develop to their full - potential. - * For example, table metadata (objects that describe - tables) are declared distinctly from the classes - theyre designed to store. That way database - relationship concepts don't interfere with your object - design concepts, and vice-versa; the transition from - table-mapping to selectable-mapping is seamless; a - class can be mapped against the database in more than - one way. SQLAlchemy provides a powerful mapping layer - that can work as automatically or as manually as you - choose, determining relationships based on foreign - keys or letting you define the join conditions - explicitly, to bridge the gap between database and - domain. - -SQLAlchemy's Advantages: - - * The Unit Of Work system organizes pending CRUD - operations into queues and commits them all in one - batch. It then performs a topological "dependency - sort" of all items to be committed and deleted and - groups redundant statements together. This produces - the maxiumum efficiency and transaction safety, and - minimizes chances of deadlocks. Modeled after Fowler's - "Unit of Work" pattern as well as Java Hibernate. - * Function-based query construction allows boolean - expressions, operators, functions, table aliases, - selectable subqueries, create/update/insert/delete - queries, correlated updates, correlated EXISTS - clauses, UNION clauses, inner and outer joins, bind - parameters, free mixing of literal text within - expressions, as little or as much as desired. - Query-compilation is vendor-specific; the same query - object can be compiled into any number of resulting - SQL strings depending on its compilation algorithm. - * Database mapping and class design are totally - separate. Persisted objects have no subclassing - requirement (other than 'object') and are POPO's : - plain old Python objects. They retain serializability - (pickling) for usage in various caching systems and - session objects. SQLAlchemy "decorates" classes with - non-intrusive property accessors to automatically log - object creates and modifications with the UnitOfWork - engine, to lazyload related data, as well as to track - attribute change histories. - * Custom list classes can be used with eagerly or lazily - loaded child object lists, allowing rich relationships - to be created on the fly as SQLAlchemy appends child - objects to an object attribute. - * Composite (multiple-column) primary keys are - supported, as are "association" objects that represent - the middle of a "many-to-many" relationship. - * Self-referential tables and mappers are supported. - Adjacency list structures can be created, saved, and - deleted with proper cascading, with no extra - programming. - * Data mapping can be used in a row-based manner. Any - bizarre hyper-optimized query that you or your DBA can - cook up, you can run in SQLAlchemy, and as long as it - returns the expected columns within a rowset, you can - get your objects from it. For a rowset that contains - more than one kind of object per row, multiple mappers - can be chained together to return multiple object - instance lists from a single database round trip. - * The type system allows pre- and post- processing of - data, both at the bind parameter and the result set - level. User-defined types can be freely mixed with - built-in types. Generic types as well as SQL-specific - types are available. - -""", - classifiers=[ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Topic :: Database :: Front-Ends", - "Operating System :: OS Independent", - ], - **extra - ) +def run_setup(with_cext): + kwargs = extra.copy() + if with_cext: + if Feature: + kwargs['features'] = {'cextensions': Feature( + "optional C speed-enhancements", + standard=True, + ext_modules=ext_modules + )} + else: + kwargs['ext_modules'] = ext_modules + + setup(name="SQLAlchemy", + version=VERSION, + description="Database Abstraction Library", + author="Mike Bayer", + author_email="mike_mp@zzzcomputing.com", + url="http://www.sqlalchemy.org", + packages=find_packages('lib'), + package_dir={'': 'lib'}, + license="MIT License", + cmdclass={'build_ext': ve_build_ext}, + + tests_require=['nose >= 0.11'], + test_suite="sqla_nose", + + long_description="""\ + SQLAlchemy is: + + * The Python SQL toolkit and Object Relational Mapper + that gives application developers the full power and + flexibility of SQL. SQLAlchemy provides a full suite + of well known enterprise-level persistence patterns, + designed for efficient and high-performing database + access, adapted into a simple and Pythonic domain + language. + * extremely easy to use for all the basic tasks, such + as: accessing pooled connections, constructing SQL + from Python expressions, finding object instances, and + commiting object modifications back to the database. + * powerful enough for complicated tasks, such as: eager + load a graph of objects and their dependencies via + joins; map recursive adjacency structures + automatically; map objects to not just tables but to + any arbitrary join or select statement; combine + multiple tables together to load whole sets of + otherwise unrelated objects from a single result set; + commit entire graphs of object changes in one step. + * built to conform to what DBAs demand, including the + ability to swap out generated SQL with hand-optimized + statements, full usage of bind parameters for all + literal values, fully transactionalized and consistent + updates using Unit of Work. + * modular. Different parts of SQLAlchemy can be used + independently of the rest, including the connection + pool, SQL construction, and ORM. SQLAlchemy is + constructed in an open style that allows plenty of + customization, with an architecture that supports + custom datatypes, custom SQL extensions, and ORM + plugins which can augment or extend mapping + functionality. + + SQLAlchemy's Philosophy: + + * SQL databases behave less and less like object + collections the more size and performance start to + matter; object collections behave less and less like + tables and rows the more abstraction starts to matter. + SQLAlchemy aims to accomodate both of these + principles. + * Your classes aren't tables, and your objects aren't + rows. Databases aren't just collections of tables; + they're relational algebra engines. You don't have to + select from just tables, you can select from joins, + subqueries, and unions. Database and domain concepts + should be visibly decoupled from the beginning, + allowing both sides to develop to their full + potential. + * For example, table metadata (objects that describe + tables) are declared distinctly from the classes + theyre designed to store. That way database + relationship concepts don't interfere with your object + design concepts, and vice-versa; the transition from + table-mapping to selectable-mapping is seamless; a + class can be mapped against the database in more than + one way. SQLAlchemy provides a powerful mapping layer + that can work as automatically or as manually as you + choose, determining relationships based on foreign + keys or letting you define the join conditions + explicitly, to bridge the gap between database and + domain. + + SQLAlchemy's Advantages: + + * The Unit Of Work system organizes pending CRUD + operations into queues and commits them all in one + batch. It then performs a topological "dependency + sort" of all items to be committed and deleted and + groups redundant statements together. This produces + the maxiumum efficiency and transaction safety, and + minimizes chances of deadlocks. Modeled after Fowler's + "Unit of Work" pattern as well as Java Hibernate. + * Function-based query construction allows boolean + expressions, operators, functions, table aliases, + selectable subqueries, create/update/insert/delete + queries, correlated updates, correlated EXISTS + clauses, UNION clauses, inner and outer joins, bind + parameters, free mixing of literal text within + expressions, as little or as much as desired. + Query-compilation is vendor-specific; the same query + object can be compiled into any number of resulting + SQL strings depending on its compilation algorithm. + * Database mapping and class design are totally + separate. Persisted objects have no subclassing + requirement (other than 'object') and are POPO's : + plain old Python objects. They retain serializability + (pickling) for usage in various caching systems and + session objects. SQLAlchemy "decorates" classes with + non-intrusive property accessors to automatically log + object creates and modifications with the UnitOfWork + engine, to lazyload related data, as well as to track + attribute change histories. + * Custom list classes can be used with eagerly or lazily + loaded child object lists, allowing rich relationships + to be created on the fly as SQLAlchemy appends child + objects to an object attribute. + * Composite (multiple-column) primary keys are + supported, as are "association" objects that represent + the middle of a "many-to-many" relationship. + * Self-referential tables and mappers are supported. + Adjacency list structures can be created, saved, and + deleted with proper cascading, with no extra + programming. + * Data mapping can be used in a row-based manner. Any + bizarre hyper-optimized query that you or your DBA can + cook up, you can run in SQLAlchemy, and as long as it + returns the expected columns within a rowset, you can + get your objects from it. For a rowset that contains + more than one kind of object per row, multiple mappers + can be chained together to return multiple object + instance lists from a single database round trip. + * The type system allows pre- and post- processing of + data, both at the bind parameter and the result set + level. User-defined types can be freely mixed with + built-in types. Generic types as well as SQL-specific + types are available. + + """, + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Topic :: Database :: Front-Ends", + "Operating System :: OS Independent", + ], + **kwargs + ) + +try: + # Likely don't want the cextension built on PyPy+CPyExt + run_setup(not IS_PYPY) +except BuildFailed, exc: + print '*' * 75 + print exc.cause + BUILD_EXT_WARNING = "WARNING: The C extension could not be compiled, speedups are not enabled." + print '*' * 75 + print BUILD_EXT_WARNING + print "Failure information, if any, is above." + print "Retrying the build without the C extension now." + print '*' * 75 + + run_setup(False) + + print '*' * 75 + print BUILD_EXT_WARNING + print "Plain-Python installation succeeded." + print '*' * 75 -- 2.39.5