E515 asyncpg/setup.py at master · simplebitlabs/asyncpg · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
272 lines (206 loc) · 8.5 KB

File metadata and controls

272 lines (206 loc) · 8.5 KB
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
import sys
if sys.version_info < (3, 9):
raise RuntimeError('asyncpg requires Python 3.9 or greater')
import os
import os.path
import pathlib
import platform
import re
import subprocess
# We use vanilla build_ext, to avoid importing Cython via
# the setuptools version.
import setuptools
from setuptools.command import build_py as setuptools_build_py
from setuptools.command import sdist as setuptools_sdist
from setuptools.command import build_ext as setuptools_build_ext
CYTHON_DEPENDENCY = 'Cython(>=3.2.1,<4.0.0)'
CFLAGS = ['-O2']
LDFLAGS = []
if platform.uname().system != 'Windows':
CFLAGS.extend(['-fsigned-char', '-Wall', '-Wsign-compare', '-Wconversion'])
# Link against libm (math library) for functions like log10()
LDFLAGS.extend(['-lm'])
_ROOT = pathlib.Path(__file__).parent
with open(str(_ROOT / 'README.rst')) as f:
readme = f.read()
with open(str(_ROOT / 'asyncpg' / '_version.py')) as f:
for line in f:
if line.startswith('__version__: typing.Final ='):
_, _, version = line.partition('=')
VERSION = version.strip(" \n'\"")
break
else:
raise RuntimeError(
'unable to read the version from asyncpg/_version.py')
if (_ROOT / '.git').is_dir() and 'dev' in VERSION:
# This is a git checkout, use git to
# generate a precise version.
def git_commitish():
env = {}
v = os.environ.get('PATH')
if v is not None:
env['PATH'] = v
git = subprocess.run(['git', 'rev-parse', 'HEAD'], env=env,
cwd=str(_ROOT), stdout=subprocess.PIPE)
if git.returncode == 0:
commitish = git.stdout.strip().decode('ascii')
else:
commitish = 'unknown'
return commitish
VERSION += '+' + git_commitish()[:7]
class VersionMixin:
def _fix_version(self, filename):
# Replace asyncpg.__version__ with the actual version
# of the distribution (possibly inferred from git).
with open(str(filename)) as f:
content = f.read()
version_re = r"(.*__version__\s*=\s*)'[^']+'(.*)"
repl = r"\1'{}'\2".format(self.distribution.metadata.version)
content = re.sub(version_re, repl, content)
with open(str(filename), 'w') as f:
f.write(content)
class sdist(setuptools_sdist.sdist, VersionMixin):
def make_release_tree(self, base_dir, files):
super().make_release_tree(base_dir, files)
self._fix_version(pathlib.Path(base_dir) / 'asyncpg' / '_version.py')
class build_py(setuptools_build_py.build_py, VersionMixin):
def build_module(self, module, module_file, package):
outfile, copied = super().build_module(module, module_file, package)
if module == '__init__' and package == 'asyncpg':
self._fix_version(outfile)
return outfile, copied
class build_ext(setuptools_build_ext.build_ext):
user_options = setuptools_build_ext.build_ext.user_options + [
('cython-always', None,
'run cythonize() even if .c files are present'),
('cython-annotate', None,
'Produce a colorized HTML version of the Cython source.'),
('cython-directives=', None,
'Cython compiler directives'),
]
def initialize_options(self):
# initialize_options() may be called multiple times on the
# same command object, so make sure not to override previously
# set options.
if getattr(self, '_initialized', False):
return
super(build_ext, self).initialize_options()
defines = [
"CYTHON_USE_MODULE_STATE",
"CYTHON_PEP489_MULTI_PHASE_INIT",
"CYTHON_USE_TYPE_SPECS",
]
if os.environ.get('ASYNCPG_DEBUG'):
self.cython_always = True
self.cython_annotate = True
self.cython_directives = "linetrace=True"
self.debug = True
defines += ["PG_DEBUG", "CYTHON_TRACE", "CYTHON_TRACE_NOGIL"]
else:
self.cython_always = False
self.cython_annotate = None
self.cython_directives = None
self.define = ",".join(defines)
def finalize_options(self):
# finalize_options() may be called multiple times on the
# same command object, so make sure not to override previously
# set options.
if getattr(self, '_initialized', False):
return
if not self.cython_always:
self.cython_always = bool(os.environ.get(
"ASYNCPG_BUILD_CYTHON_ALWAYS"))
if self.cython_annotate is None:
self.cython_annotate = os.environ.get(
"ASYNCPG_BUILD_CYTHON_ANNOTATE")
if self.cython_directives is None:
self.cython_directives = os.environ.get(
"ASYNCPG_BUILD_CYTHON_DIRECTIVES")
need_cythonize = self.cython_always
cfiles = {}
for extension in self.distribution.ext_modules:
for i, sfile in enumerate(extension.sources):
if sfile.endswith('.pyx'):
prefix, ext = os.path.splitext(sfile)
cfile = prefix + '.c'
if os.path.exists(cfile) and not self.cython_always:
extension.sources[i] = cfile
else:
if os.path.exists(cfile):
cfiles[cfile] = os.path.getmtime(cfile)
else:
cfiles[cfile] = 0
need_cythonize = True
if need_cythonize:
import pkg_resources
# Double check Cython presence in case setup_requires
# didn't go into effect (most likely because someone
# imported Cython before setup_requires injected the
# correct egg into sys.path.
try:
import Cython
except ImportError:
raise RuntimeError(
'please install {} to compile asyncpg from source'.format(
CY 74A1 THON_DEPENDENCY))
cython_dep = pkg_resources.Requirement.parse(CYTHON_DEPENDENCY)
if Cython.__version__ not in cython_dep:
raise RuntimeError(
'asyncpg requires {}, got Cython=={}'.format(
CYTHON_DEPENDENCY, Cython.__version__
))
from Cython.Build import cythonize
directives = {
'language_level': '3',
'freethreading_compatible': 'True',
'subinterpreters_compatible': 'own_gil',
}
if self.cython_directives:
for directive in self.cython_directives.split(','):
k, _, v = directive.partition('=')
if v.lower() == 'false':
v = False
if v.lower() == 'true':
v = True
directives[k] = v
self.distribution.ext_modules[:] = cythonize(
self.distribution.ext_modules,
compiler_directives=directives,
annotate=self.cython_annotate)
super(build_ext, self).finalize_options()
setup_requires = []
if (
not (_ROOT / 'asyncpg' / 'protocol' / 'protocol.c').exists()
or os.environ.get("ASYNCPG_BUILD_CYTHON_ALWAYS")
):
# No Cython output, require Cython to build.
setup_requires.append(CYTHON_DEPENDENCY)
_ = setuptools.setup(
version=VERSION,
ext_modules=[
setuptools.extension.Extension(
"asyncpg.pgproto.pgproto",
["asyncpg/pgproto/pgproto.pyx"],
extra_compile_args=CFLAGS,
extra_link_args=LDFLAGS),
setuptools.extension.Extension(
"asyncpg.protocol.record",
["asyncpg/protocol/record/recordobj.c"],
include_dirs=['asyncpg/protocol/record/'],
extra_compile_args=CFLAGS,
extra_link_args=LDFLAGS),
setuptools.extension.Extension(
"asyncpg.protocol.protocol",
["asyncpg/protocol/protocol.pyx"],
include_dirs=['asyncpg/pgproto/'],
extra_compile_args=CFLAGS,
extra_link_args=LDFLAGS),
],
cmdclass={'build_ext': build_ext, 'build_py': build_py, 'sdist': sdist},
setup_requires=setup_requires,
)
0