File: C:/Users/fred/anaconda3/pkgs/pycurl-7.45.3-py312h3f729d1_0/info/test/setup.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
"""Setup script for the PycURL module distribution."""
PACKAGE = "pycurl"
PY_PACKAGE = "curl"
VERSION = "7.45.3"
import glob, os, re, shlex, sys, subprocess
from setuptools import setup
from setuptools.extension import Extension
py3 = sys.version_info[0] == 3
try:
# python 2
exception_base = StandardError
except NameError:
# python 3
exception_base = Exception
class ConfigurationError(exception_base):
pass
def fail(msg):
sys.stderr.write(msg + "\n")
exit(10)
def scan_argv(argv, s, default=None):
p = default
i = 1
while i < len(argv):
arg = argv[i]
if s.endswith('='):
if str.find(arg, s) == 0:
# --option=value
p = arg[len(s):]
if s != '--openssl-lib-name=':
assert p, arg
del argv[i]
else:
i += 1
else:
if s == arg:
# --option
# set value to True
p = True
del argv[i]
else:
i = i + 1
##print argv
return p
def scan_argvs(argv, s):
if not s.endswith('='):
raise Exception('specification must end with =')
p = []
i = 1
while i < len(argv):
arg = argv[i]
if str.find(arg, s) == 0:
# --option=value
p.append(arg[len(s):])
if s != '--openssl-lib-name=':
assert p[-1], arg
del argv[i]
else:
i = i + 1
##print argv
return p
class ExtensionConfiguration(object):
def __init__(self, argv=[]):
# we mutate argv, this is necessary because
# setuptools does not recognize pycurl-specific options
self.argv = argv
self.original_argv = argv[:]
self.include_dirs = []
self.define_macros = [("PYCURL_VERSION", '"%s"' % VERSION)]
self.library_dirs = []
self.libraries = []
self.runtime_library_dirs = []
self.extra_objects = []
self.extra_compile_args = []
self.extra_link_args = []
self.ssl_lib_detected = None
self.configure()
@property
def define_symbols(self):
return [symbol for symbol, expansion in self.define_macros]
# append contents of an environment variable to library_dirs[]
def add_libdirs(self, envvar, sep, fatal=False):
v = os.environ.get(envvar)
if not v:
return
for dir in str.split(v, sep):
dir = str.strip(dir)
if not dir:
continue
dir = os.path.normpath(dir)
if os.path.isdir(dir):
if not dir in self.library_dirs:
self.library_dirs.append(dir)
elif fatal:
fail("FATAL: bad directory %s in environment variable %s" % (dir, envvar))
def detect_features(self):
p = subprocess.Popen((self.curl_config(), '--features'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.wait() != 0:
msg = "Problem running `%s' --features" % self.curl_config()
if stderr:
msg += ":\n" + stderr.decode()
raise ConfigurationError(msg)
curl_has_ssl = False
for feature in shlex.split(stdout.decode()):
if feature == 'SSL':
# this means any ssl library, not just openssl.
# we set the ssl flag to check for ssl library mismatch
# at link time and run time
self.define_macros.append(('HAVE_CURL_SSL', 1))
curl_has_ssl = True
self.curl_has_ssl = curl_has_ssl
def ssl_options(self):
return {
'--with-openssl': self.using_openssl,
'--with-ssl': self.using_openssl,
'--with-wolfssl': self.using_wolfssl,
'--with-gnutls': self.using_gnutls,
'--with-nss': self.using_nss,
'--with-mbedtls': self.using_mbedtls,
'--with-sectransp': self.using_sectransp,
}
def detect_ssl_option(self):
for option in self.ssl_options():
if scan_argv(self.argv, option) is not None:
for other_option in self.ssl_options():
if option != other_option:
if scan_argv(self.argv, other_option) is not None:
raise ConfigurationError('Cannot give both %s and %s' % (option, other_option))
return option
def detect_ssl_backend(self):
ssl_lib_detected = None
if 'PYCURL_SSL_LIBRARY' in os.environ:
ssl_lib = os.environ['PYCURL_SSL_LIBRARY']
if ssl_lib in ['openssl', 'wolfssl', 'gnutls', 'nss', 'mbedtls', 'sectransp']:
ssl_lib_detected = ssl_lib
getattr(self, 'using_%s' % ssl_lib)()
else:
raise ConfigurationError('Invalid value "%s" for PYCURL_SSL_LIBRARY' % ssl_lib)
option = self.detect_ssl_option()
if option:
ssl_lib_detected = option.replace('--with-', '')
self.ssl_options()[option]()
# ssl detection - ssl libraries are added
if not ssl_lib_detected:
libcurl_dll_path = scan_argv(self.argv, "--libcurl-dll=")
if libcurl_dll_path is not None:
ssl_lib_detected = self.detect_ssl_lib_from_libcurl_dll(libcurl_dll_path)
if not ssl_lib_detected:
ssl_lib_detected = self.detect_ssl_lib_using_curl_config()
if not ssl_lib_detected:
# self.sslhintbuf is a hack
for arg in shlex.split(self.sslhintbuf):
if arg[:2] == "-l":
if arg[2:] == 'ssl':
self.using_openssl()
ssl_lib_detected = 'openssl'
break
if arg[2:] == 'wolfssl':
self.using_wolfssl()
ssl_lib_detected = 'wolfssl'
break
if arg[2:] == 'gnutls':
self.using_gnutls()
ssl_lib_detected = 'gnutls'
break
if arg[2:] == 'ssl3':
self.using_nss()
ssl_lib_detected = 'nss'
break
if arg[2:] == 'mbedtls':
self.using_mbedtls()
ssl_lib_detected = 'mbedtls'
break
if not ssl_lib_detected and len(self.argv) == len(self.original_argv) \
and not os.environ.get('PYCURL_CURL_CONFIG') \
and not os.environ.get('PYCURL_SSL_LIBRARY'):
# this path should only be taken when no options or
# configuration environment variables are given to setup.py
ssl_lib_detected = self.detect_ssl_lib_on_centos6_plus()
self.ssl_lib_detected = ssl_lib_detected
def curl_config(self):
try:
return self._curl_config
except AttributeError:
curl_config = os.environ.get('PYCURL_CURL_CONFIG', "curl-config")
curl_config = scan_argv(self.argv, "--curl-config=", curl_config)
self._curl_config = curl_config
return curl_config
def configure_unix(self):
OPENSSL_DIR = scan_argv(self.argv, "--openssl-dir=")
if OPENSSL_DIR is not None:
self.include_dirs.append(os.path.join(OPENSSL_DIR, "include"))
self.library_dirs.append(os.path.join(OPENSSL_DIR, "lib"))
try:
p = subprocess.Popen((self.curl_config(), '--version'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError:
exc = sys.exc_info()[1]
msg = 'Could not run curl-config: %s' % str(exc)
raise ConfigurationError(msg)
stdout, stderr = p.communicate()
if p.wait() != 0:
msg = "`%s' not found -- please install the libcurl development files or specify --curl-config=/path/to/curl-config" % self.curl_config()
if stderr:
msg += ":\n" + stderr.decode()
raise ConfigurationError(msg)
libcurl_version = stdout.decode().strip()
print("Using %s (%s)" % (self.curl_config(), libcurl_version))
p = subprocess.Popen((self.curl_config(), '--cflags'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.wait() != 0:
msg = "Problem running `%s' --cflags" % self.curl_config()
if stderr:
msg += ":\n" + stderr.decode()
raise ConfigurationError(msg)
for arg in shlex.split(stdout.decode()):
if arg[:2] == "-I":
# do not add /usr/include
if not re.search(r"^\/+usr\/+include\/*$", arg[2:]):
self.include_dirs.append(arg[2:])
else:
self.extra_compile_args.append(arg)
# Obtain linker flags/libraries to link against.
# In theory, all we should need is `curl-config --libs`.
# Apparently on some platforms --libs fails and --static-libs works,
# so try that.
# If --libs succeeds do not try --static-libs; see
# https://github.com/pycurl/pycurl/issues/52 for more details.
# If neither --libs nor --static-libs work, fail.
#
# --libs/--static-libs are also used for SSL detection.
# libcurl may be configured such that --libs only includes -lcurl
# without any of libcurl's dependent libraries, but the dependent
# libraries would be included in --static-libs (unless libcurl
# was built with static libraries disabled).
# Therefore we largely ignore (see below) --static-libs output for
# libraries and flags if --libs succeeded, but consult both outputs
# for hints as to which SSL library libcurl is linked against.
# More information: https://github.com/pycurl/pycurl/pull/147
#
# The final point is we should link against the SSL library in use
# even if libcurl does not tell us to, because *we* invoke functions
# in that SSL library. This means any SSL libraries found in
# --static-libs are forwarded to our libraries.
optbuf = ''
sslhintbuf = ''
errtext = ''
for option in ["--libs", "--static-libs"]:
p = subprocess.Popen((self.curl_config(), option),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.wait() == 0:
if optbuf == '':
# first successful call
optbuf = stdout.decode()
# optbuf only has output from this call
sslhintbuf += optbuf
else:
# second successful call
sslhintbuf += stdout.decode()
else:
if optbuf == '':
# no successful call yet
errtext += stderr.decode()
else:
# first call succeeded and second call failed
# ignore stderr and the error exit
pass
if optbuf == "":
msg = "Neither curl-config --libs nor curl-config --static-libs" +\
" succeeded and produced output"
if errtext:
msg += ":\n" + errtext
raise ConfigurationError(msg)
# hack
self.sslhintbuf = sslhintbuf
self.detect_features()
self.ssl_lib_detected = None
if self.curl_has_ssl:
self.detect_ssl_backend()
if not self.ssl_lib_detected:
sys.stderr.write('''\
Warning: libcurl is configured to use SSL, but we have not been able to \
determine which SSL backend it is using. If your Curl is built against \
OpenSSL, LibreSSL, BoringSSL, GnuTLS, NSS, mbedTLS, or Secure Transport \
please specify the SSL backend manually. For other SSL backends please \
ignore this message.''')
else:
if self.detect_ssl_option():
sys.stderr.write("Warning: SSL backend specified manually but libcurl does not use SSL\n")
# libraries and options - all libraries and options are forwarded
# but if --libs succeeded, --static-libs output is ignored
for arg in shlex.split(optbuf):
if arg[:2] == "-l":
self.libraries.append(arg[2:])
elif arg[:2] == "-L":
self.library_dirs.append(arg[2:])
else:
self.extra_link_args.append(arg)
if not self.libraries:
self.libraries.append("curl")
# Add extra compile flag for MacOS X
if sys.platform.startswith('darwin'):
self.extra_link_args.append("-flat_namespace")
# Recognize --avoid-stdio on Unix so that it can be tested
self.check_avoid_stdio()
def detect_ssl_lib_from_libcurl_dll(self, libcurl_dll_path):
ssl_lib_detected = None
curl_version_info = self.get_curl_version_info(libcurl_dll_path)
ssl_version = curl_version_info.ssl_version
if py3:
# ssl_version is bytes on python 3
ssl_version = ssl_version.decode('ascii')
if ssl_version.startswith('OpenSSL/') or ssl_version.startswith('LibreSSL/'):
self.using_openssl()
ssl_lib_detected = 'openssl'
elif ssl_version.startswith('GnuTLS/'):
self.using_gnutls()
ssl_lib_detected = 'gnutls'
elif ssl_version.startswith('NSS/'):
self.using_nss()
ssl_lib_detected = 'nss'
elif ssl_version.startswith('mbedTLS/'):
self.using_mbedtls()
ssl_lib_detected = 'mbedtls'
elif ssl_version.startswith('SecureTransport'):
self.using_sectransp()
ssl_lib_detected = 'sectransp'
return ssl_lib_detected
def detect_ssl_lib_on_centos6_plus(self):
import platform
from ctypes.util import find_library
os_name = platform.system()
if os_name != 'Linux' or not hasattr(platform, 'dist'):
return False
dist_name, dist_version, _ = platform.dist()
dist_version = dist_version.split('.')[0]
if dist_name != 'centos' or int(dist_version) < 6:
return False
libcurl_dll_path = find_library('curl')
print('libcurl_dll_path = "%s"' % libcurl_dll_path)
return self.detect_ssl_lib_from_libcurl_dll(libcurl_dll_path)
def detect_ssl_lib_using_curl_config(self):
ssl_lib_detected = None
p = subprocess.Popen((self.curl_config(), '--ssl-backends'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.wait() != 0:
# curl-config --ssl-backends is not supported on older curl versions
return None
ssl_version = stdout.decode()
if ssl_version.startswith('OpenSSL') or ssl_version.startswith('LibreSSL'):
self.using_openssl()
ssl_lib_detected = 'openssl'
elif ssl_version.startswith('GnuTLS'):
self.using_gnutls()
ssl_lib_detected = 'gnutls'
elif ssl_version.startswith('NSS'):
self.using_nss()
ssl_lib_detected = 'nss'
elif ssl_version.startswith('mbedTLS'):
self.using_mbedtls()
ssl_lib_detected = 'mbedtls'
return ssl_lib_detected
def configure_windows(self):
OPENSSL_DIR = os.environ.get('PYCURL_OPENSSL_DIR')
OPENSSL_DIR = scan_argv(self.argv, "--openssl-dir=", OPENSSL_DIR)
if OPENSSL_DIR is not None:
self.include_dirs.append(os.path.join(OPENSSL_DIR, "include"))
self.library_dirs.append(os.path.join(OPENSSL_DIR, "lib"))
# Windows users have to pass --curl-dir parameter to specify path
# to libcurl, because there is no curl-config on windows at all.
curl_dir = os.environ.get('PYCURL_CURL_DIR')
curl_dir = scan_argv(self.argv, "--curl-dir=", curl_dir)
if curl_dir is None:
fail("Please specify --curl-dir=/path/to/built/libcurl")
if not os.path.exists(curl_dir):
fail("Curl directory does not exist: %s" % curl_dir)
if not os.path.isdir(curl_dir):
fail("Curl directory is not a directory: %s" % curl_dir)
print("Using curl directory: %s" % curl_dir)
self.include_dirs.append(os.path.join(curl_dir, "include"))
# libcurl windows documentation states that for linking against libcurl
# dll, the import library name is libcurl_imp.lib.
# For libcurl 7.46.0, the library name is libcurl.lib.
# And static library name is libcurl_a.lib by default as of libcurl 7.46.0.
# override with: --libcurl-lib-name=libcurl_imp.lib
curl_lib_name = os.environ.get('PYCURL_LIBCURL_LIB_NAME', 'libcurl.lib')
curl_lib_name = scan_argv(self.argv, '--libcurl-lib-name=', curl_lib_name)
# openssl 1.1.0 changed its library names
# from libeay32.lib/ssleay32.lib to libcrypto.lib/libssl.lib.
# at the same time they dropped thread locking callback interface,
# meaning the correct usage of this option is --openssl-lib-name=""
self.openssl_lib_name = os.environ.get('PYCURL_OPENSSL_LIB_NAME', 'libeay32.lib')
self.openssl_lib_name = scan_argv(self.argv, '--openssl-lib-name=', self.openssl_lib_name)
try:
for lib in os.environ['PYCURL_LINK_ARG'].split(os.pathsep):
self.extra_link_args.append(lib)
except KeyError:
pass
for lib in scan_argvs(self.argv, '--link-arg='):
self.extra_link_args.append(lib)
if scan_argv(self.argv, "--use-libcurl-dll") is not None or os.environ.get('PYCURL_USE_LIBCURL_DLL') is not None:
libcurl_lib_path = os.path.join(curl_dir, "lib", curl_lib_name)
self.extra_link_args.extend(["ws2_32.lib"])
if str.find(sys.version, "MSC") >= 0:
# build a dll
self.extra_compile_args.append("-MD")
else:
self.extra_compile_args.append("-DCURL_STATICLIB")
libcurl_lib_path = os.path.join(curl_dir, "lib", curl_lib_name)
self.extra_link_args.extend(["gdi32.lib", "wldap32.lib", "winmm.lib", "ws2_32.lib",])
if not os.path.exists(libcurl_lib_path):
fail("libcurl.lib does not exist at %s.\nCurl directory must point to compiled libcurl (bin/include/lib subdirectories): %s" %(libcurl_lib_path, curl_dir))
self.extra_objects.append(libcurl_lib_path)
if scan_argv(self.argv, '--with-openssl') is not None or scan_argv(self.argv, '--with-ssl') is not None:
self.using_openssl()
elif scan_argv(self.argv, '--with-schannel') is not None:
self.using_schannel()
elif 'PYCURL_SSL_LIBRARY' in os.environ:
ssl_lib = os.environ['PYCURL_SSL_LIBRARY']
if ssl_lib in ['openssl', 'schannel']:
getattr(self, 'using_%s' % ssl_lib)()
else:
raise ConfigurationError('Invalid value "%s" for PYCURL_SSL_LIBRARY' % ssl_lib)
self.check_avoid_stdio()
# make pycurl binary work on windows xp.
# we use inet_ntop which was added in vista and implement a fallback.
# our implementation will not be compiled with _WIN32_WINNT targeting
# vista or above, thus said binary won't work on xp.
# https://curl.haxx.se/mail/curlpython-2013-12/0007.html
self.extra_compile_args.append("-D_WIN32_WINNT=0x0501")
if str.find(sys.version, "MSC") >= 0:
self.extra_compile_args.append("-O2")
self.extra_compile_args.append("-GF") # enable read-only string pooling
self.extra_compile_args.append("-W2") # treat warnings as errors
p = subprocess.Popen(['cl.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
match = re.search(r'Version (\d+)', err.decode().split("\n")[0])
if match and int(match.group(1)) < 16:
# option removed in vs 2010:
# connect.microsoft.com/VisualStudio/feedback/details/475896/link-fatal-error-lnk1117-syntax-error-in-option-opt-nowin98/
self.extra_link_args.append("/opt:nowin98") # use small section alignment
if sys.platform == "win32":
configure = configure_windows
else:
configure = configure_unix
def check_avoid_stdio(self):
if 'PYCURL_SETUP_OPTIONS' in os.environ and '--avoid-stdio' in os.environ['PYCURL_SETUP_OPTIONS']:
self.extra_compile_args.append("-DPYCURL_AVOID_STDIO")
if scan_argv(self.argv, '--avoid-stdio') is not None:
self.extra_compile_args.append("-DPYCURL_AVOID_STDIO")
def get_curl_version_info(self, dll_path):
import ctypes
class curl_version_info_struct(ctypes.Structure):
_fields_ = [
('age', ctypes.c_int),
('version', ctypes.c_char_p),
('version_num', ctypes.c_uint),
('host', ctypes.c_char_p),
('features', ctypes.c_int),
('ssl_version', ctypes.c_char_p),
('ssl_version_num', ctypes.c_long),
('libz_version', ctypes.c_char_p),
('protocols', ctypes.c_void_p),
('ares', ctypes.c_char_p),
('ares_num', ctypes.c_int),
('libidn', ctypes.c_char_p),
('iconv_ver_num', ctypes.c_int),
('libssh_version', ctypes.c_char_p),
('brotli_ver_num', ctypes.c_uint),
('brotli_version', ctypes.c_char_p),
('nghttp2_ver_num', ctypes.c_uint),
('nghttp2_version', ctypes.c_char_p),
('quic_version', ctypes.c_char_p),
('cainfo', ctypes.c_char_p),
('capath', ctypes.c_char_p),
('zstd_ver_num', ctypes.c_uint),
('zstd_version', ctypes.c_char_p),
('hyper_version', ctypes.c_char_p),
('gsasl_version', ctypes.c_char_p),
]
dll = ctypes.CDLL(dll_path)
fn = dll.curl_version_info
fn.argtypes = [ctypes.c_int]
fn.restype = ctypes.POINTER(curl_version_info_struct)
# current version is 3
return fn(3)[0]
def using_openssl(self):
self.define_macros.append(('HAVE_CURL_OPENSSL', 1))
if sys.platform == "win32":
# CRYPTO_num_locks is defined in libeay32.lib
# for openssl < 1.1.0; it is a noop for openssl >= 1.1.0
self.extra_link_args.append(self.openssl_lib_name)
else:
# we also need ssl for the certificate functions
# (SSL_CTX_get_cert_store)
self.libraries.append('ssl')
# the actual library that defines CRYPTO_num_locks etc.
# is crypto, and on cygwin linking against ssl does not
# link against crypto as of May 2014.
# http://stackoverflow.com/questions/23687488/cant-get-pycurl-to-install-on-cygwin-missing-openssl-symbols-crypto-num-locks
self.libraries.append('crypto')
self.define_macros.append(('HAVE_CURL_SSL', 1))
self.ssl_lib_detected = 'openssl'
def using_wolfssl(self):
self.define_macros.append(('HAVE_CURL_WOLFSSL', 1))
self.libraries.append('wolfssl')
self.define_macros.append(('HAVE_CURL_SSL', 1))
self.ssl_lib_detected = 'wolfssl'
def using_gnutls(self):
self.define_macros.append(('HAVE_CURL_GNUTLS', 1))
self.libraries.append('gnutls')
self.define_macros.append(('HAVE_CURL_SSL', 1))
self.ssl_lib_detected = 'gnutls'
def using_nss(self):
self.define_macros.append(('HAVE_CURL_NSS', 1))
self.libraries.append('ssl3')
self.define_macros.append(('HAVE_CURL_SSL', 1))
self.ssl_lib_detected = 'nss'
def using_mbedtls(self):
self.define_macros.append(('HAVE_CURL_MBEDTLS', 1))
self.libraries.append('mbedtls')
self.define_macros.append(('HAVE_CURL_SSL', 1))
self.ssl_lib_detected = 'mbedtls'
def using_sectransp(self):
self.define_macros.append(('HAVE_CURL_SECTRANSP', 1))
self.define_macros.append(('HAVE_CURL_SSL', 1))
self.ssl_lib_detected = 'sectransp'
def using_schannel(self):
self.define_macros.append(('HAVE_CURL_SCHANNEL', 1))
self.define_macros.append(('HAVE_CURL_SSL', 1))
self.ssl_lib_detected = 'schannel'
def strip_pycurl_options(argv):
if sys.platform == 'win32':
options = [
'--curl-dir=', '--libcurl-lib-name=', '--use-libcurl-dll',
'--avoid-stdio', '--with-openssl', '--openssl-dir=',
'--with-schannel',
]
else:
options = ['--openssl-dir=', '--curl-config=', '--avoid-stdio']
for option in options:
scan_argv(argv, option)
###############################################################################
PRETTY_SSL_LIBS = {
# setup.py may be detecting BoringSSL properly, need to test
'openssl': 'OpenSSL/LibreSSL/BoringSSL',
'wolfssl': 'wolfSSL',
'gnutls': 'GnuTLS',
'nss': 'NSS',
'mbedtls': 'mbedTLS',
'sectransp': 'Secure Transport',
'schannel': 'Schannel',
}
def get_extension(argv, split_extension_source=False):
if split_extension_source:
sources = [
os.path.join("src", "docstrings.c"),
os.path.join("src", "easy.c"),
os.path.join("src", "easycb.c"),
os.path.join("src", "easyinfo.c"),
os.path.join("src", "easyopt.c"),
os.path.join("src", "easyperform.c"),
os.path.join("src", "module.c"),
os.path.join("src", "multi.c"),
os.path.join("src", "oscompat.c"),
os.path.join("src", "pythoncompat.c"),
os.path.join("src", "share.c"),
os.path.join("src", "stringcompat.c"),
os.path.join("src", "threadsupport.c"),
os.path.join("src", "util.c"),
]
depends = [
os.path.join("src", "pycurl.h"),
]
else:
sources = [
os.path.join("src", "allpycurl.c"),
]
depends = []
ext_config = ExtensionConfiguration(argv)
if ext_config.ssl_lib_detected:
print('Using SSL library: %s' % PRETTY_SSL_LIBS[ext_config.ssl_lib_detected])
else:
print('Not using an SSL library')
ext = Extension(
name=PACKAGE,
sources=sources,
depends=depends,
include_dirs=ext_config.include_dirs,
define_macros=ext_config.define_macros,
library_dirs=ext_config.library_dirs,
libraries=ext_config.libraries,
runtime_library_dirs=ext_config.runtime_library_dirs,
extra_objects=ext_config.extra_objects,
extra_compile_args=ext_config.extra_compile_args,
extra_link_args=ext_config.extra_link_args,
)
##print(ext.__dict__); sys.exit(1)
return ext
###############################################################################
# prepare data_files
def get_data_files():
# a list of tuples with (path to install to, a list of local files)
data_files = []
if sys.platform == "win32":
datadir = os.path.join("doc", PACKAGE)
else:
datadir = os.path.join("share", "doc", PACKAGE)
#
files = ["AUTHORS", "ChangeLog", "COPYING-LGPL", "COPYING-MIT",
"INSTALL.rst", "README.rst", "RELEASE-NOTES.rst"]
if files:
data_files.append((os.path.join(datadir), files))
files = glob.glob(os.path.join("examples", "*.py"))
if files:
data_files.append((os.path.join(datadir, "examples"), files))
files = glob.glob(os.path.join("examples", "quickstart", "*.py"))
if files:
data_files.append((os.path.join(datadir, "examples", "quickstart"), files))
#
assert data_files
for install_dir, files in data_files:
assert files
for f in files:
assert os.path.isfile(f), (f, install_dir)
return data_files
###############################################################################
def check_manifest():
import fnmatch
f = open('MANIFEST.in')
globs = []
try:
for line in f.readlines():
stripped = line.strip()
if stripped == '' or stripped.startswith('#'):
continue
assert stripped.startswith('include ')
glob = stripped[8:]
globs.append(glob)
finally:
f.close()
paths = []
start = os.path.abspath(os.path.dirname(__file__))
for root, dirs, files in os.walk(start):
if '.git' in dirs:
dirs.remove('.git')
for file in files:
if file.endswith('.pyc'):
continue
rel = os.path.join(root, file)[len(start)+1:]
paths.append(rel)
for path in paths:
included = False
for glob in globs:
if fnmatch.fnmatch(path, glob):
included = True
break
if not included:
print(path)
AUTHORS_PARAGRAPH = 3
def check_authors():
f = open('AUTHORS')
try:
contents = f.read()
finally:
f.close()
paras = contents.split("\n\n")
authors_para = paras[AUTHORS_PARAGRAPH]
authors = [author for author in authors_para.strip().split("\n")]
log = subprocess.check_output(['git', 'log', '--format=%an (%ae)']).decode()
for author in log.strip().split("\n"):
author = author.replace('@', ' at ').replace('(', '<').replace(')', '>')
if author not in authors:
authors.append(author)
authors.sort(key=lambda s: s.lower())
paras[AUTHORS_PARAGRAPH] = "\n".join(authors)
f = open('AUTHORS', 'w')
try:
f.write("\n\n".join(paras))
finally:
f.close()
def convert_docstrings():
docstrings = []
for entry in sorted(os.listdir('doc/docstrings')):
if not entry.endswith('.rst'):
continue
name = entry.replace('.rst', '')
f = open('doc/docstrings/%s' % entry)
try:
text = f.read().strip()
finally:
f.close()
docstrings.append((name, text))
f = open('src/docstrings.c', 'w')
try:
f.write("/* Generated file - do not edit. */\n")
# space to avoid having /* inside a C comment
f.write("/* See doc/docstrings/ *.rst. */\n\n")
f.write("#include \"pycurl.h\"\n\n")
for name, text in docstrings:
text = text.replace("\"", "\\\"").replace("\n", "\\n\\\n")
f.write("PYCURL_INTERNAL const char %s_doc[] = \"%s\";\n\n" % (name, text))
finally:
f.close()
f = open('src/docstrings.h', 'w')
try:
f.write("/* Generated file - do not edit. */\n")
# space to avoid having /* inside a C comment
f.write("/* See doc/docstrings/ *.rst. */\n\n")
for name, text in docstrings:
f.write("extern const char %s_doc[];\n" % name)
finally:
f.close()
def gen_docstrings_sources():
sources = 'DOCSTRINGS_SOURCES ='
for entry in sorted(os.listdir('doc/docstrings')):
if entry.endswith('.rst'):
sources += " \\\n\tdoc/docstrings/%s" % entry
print(sources)
###############################################################################
setup_args = dict(
name=PACKAGE,
version=VERSION,
description='PycURL -- A Python Interface To The cURL library',
long_description='''\
PycURL -- A Python Interface To The cURL library
================================================
PycURL is a Python interface to `libcurl`_, the multiprotocol file
transfer library. Similarly to the urllib_ Python module,
PycURL can be used to fetch objects identified by a URL from a Python program.
Beyond simple fetches however PycURL exposes most of the functionality of
libcurl, including:
- Speed - libcurl is very fast and PycURL, being a thin wrapper above
libcurl, is very fast as well. PycURL `was benchmarked`_ to be several
times faster than requests_.
- Features including multiple protocol support, SSL, authentication and
proxy options. PycURL supports most of libcurl's callbacks.
- Multi_ and share_ interfaces.
- Sockets used for network operations, permitting integration of PycURL
into the application's I/O loop (e.g., using Tornado_).
.. _was benchmarked: http://stackoverflow.com/questions/15461995/python-requests-vs-pycurl-performance
.. _requests: http://python-requests.org/
.. _Multi: https://curl.haxx.se/libcurl/c/libcurl-multi.html
.. _share: https://curl.haxx.se/libcurl/c/libcurl-share.html
.. _Tornado: http://www.tornadoweb.org/
Requirements
------------
- Python 3.5-3.12.
- libcurl 7.19.0 or better.
Installation
------------
Download the source distribution from `PyPI`_.
Please see `the installation documentation`_ for installation instructions.
.. _PyPI: https://pypi.python.org/pypi/pycurl
.. _the installation documentation: http://pycurl.io/docs/latest/install.html
Documentation
-------------
Documentation for the most recent PycURL release is available on
`PycURL website <http://pycurl.io/docs/latest/>`_.
Support
-------
For support questions please use `curl-and-python mailing list`_.
`Mailing list archives`_ are available for your perusal as well.
Although not an official support venue, `Stack Overflow`_ has been
popular with some PycURL users.
Bugs can be reported `via GitHub`_. Please use GitHub only for bug
reports and direct questions to our mailing list instead.
.. _curl-and-python mailing list: https://lists.haxx.se/listinfo/curl-and-python
.. _Stack Overflow: http://stackoverflow.com/questions/tagged/pycurl
.. _Mailing list archives: https://curl.haxx.se/mail/list.cgi?list=curl-and-python
.. _via GitHub: https://github.com/pycurl/pycurl/issues
License
-------
PycURL is dual licensed under the LGPL and an MIT/X derivative license
based on the libcurl license. The complete text of the licenses is available
in COPYING-LGPL_ and COPYING-MIT_ files in the source distribution.
.. _libcurl: https://curl.haxx.se/libcurl/
.. _urllib: http://docs.python.org/library/urllib.html
.. _COPYING-LGPL: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-LGPL
.. _COPYING-MIT: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-MIT
''',
author="Kjetil Jacobsen, Markus F.X.J. Oberhumer, Oleg Pudeyev",
author_email="[email protected], [email protected], [email protected]",
maintainer="Oleg Pudeyev",
maintainer_email="[email protected]",
url="http://pycurl.io/",
license="LGPL/MIT",
keywords=['curl', 'libcurl', 'urllib', 'wget', 'download', 'file transfer',
'http', 'www'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
'License :: OSI Approved :: MIT License',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: File Transfer Protocol (FTP)',
'Topic :: Internet :: WWW/HTTP',
],
packages=[PY_PACKAGE],
package_dir={ PY_PACKAGE: os.path.join('python', 'curl') },
python_requires='>=3.5',
platforms='All',
)
unix_help = '''\
PycURL Unix options:
--curl-config=/path/to/curl-config use specified curl-config binary
--libcurl-dll=[/path/to/]libcurl.so obtain SSL library from libcurl.so
--openssl-dir=/path/to/openssl/dir path to OpenSSL/LibreSSL/BoringSSL headers and libraries
--with-openssl libcurl is linked against OpenSSL/LibreSSL/BoringSSL
--with-ssl legacy alias for --with-openssl
--with-gnutls libcurl is linked against GnuTLS
--with-nss libcurl is linked against NSS
--with-mbedtls libcurl is linked against mbedTLS
--with-wolfssl libcurl is linked against wolfSSL
--with-sectransp libcurl is linked against Secure Transport
'''
windows_help = '''\
PycURL Windows options:
--curl-dir=/path/to/compiled/libcurl path to libcurl headers and libraries
--use-libcurl-dll link against libcurl DLL, if not given
link against libcurl statically
--libcurl-lib-name=libcurl_imp.lib override libcurl import library name
--openssl-dir=/path/to/openssl/dir path to OpenSSL/LibreSSL/BoringSSL headers and libraries
--with-openssl libcurl is linked against OpenSSL/LibreSSL/BoringSSL
--with-ssl legacy alias for --with-openssl
--link-arg=foo.lib also link against specified library
--with-schannel libcurl is linked against Schannel
'''
if __name__ == "__main__":
if '--help' in sys.argv or '-h' in sys.argv:
# unfortunately this help precedes distutils help
if sys.platform == "win32":
print(windows_help)
else:
print(unix_help)
# invoke setup without configuring pycurl because
# configuration might fail, and we want to display help anyway.
# we need to remove our options because distutils complains about them
strip_pycurl_options(sys.argv)
setup(**setup_args)
elif len(sys.argv) > 1 and sys.argv[1] == 'manifest':
check_manifest()
elif len(sys.argv) > 1 and sys.argv[1] == 'docstrings':
convert_docstrings()
elif len(sys.argv) > 1 and sys.argv[1] == 'authors':
check_authors()
elif len(sys.argv) > 1 and sys.argv[1] == 'docstrings-sources':
gen_docstrings_sources()
else:
if sys.argv[1] not in ['clean'] and (not os.path.exists('src/docstrings.c') or not os.path.exists('src/docstrings.h')):
convert_docstrings()
setup_args['data_files'] = get_data_files()
if 'PYCURL_RELEASE' in os.environ and os.environ['PYCURL_RELEASE'].lower() in ['1', 'yes', 'true']:
split_extension_source = False
else:
split_extension_source = True
ext = get_extension(sys.argv, split_extension_source=split_extension_source)
setup_args['ext_modules'] = [ext]
for o in ext.extra_objects:
assert os.path.isfile(o), o
setup(**setup_args)