Skip to content

Commit

Permalink
Add workaround for building on macOS High Sierra beta. Fix lint in se…
Browse files Browse the repository at this point in the history
…tup.

High Sierra betas no longer put /usr/lib and /usr/local/lib in the linker settings, so I've
added them manually.

While there I cleaned up a bunch of flake8 complaints.  (Yes, I'm now using Spacemacs and have
automatic checking on.)
  • Loading branch information
mkleehammer committed Jun 21, 2017
1 parent 412598b commit 908c811
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 62 deletions.
7 changes: 7 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[flake8]
max_line_length: 95
ignore =
E221,
# multi spaces before op - I line up assignments often
E401,
# multiple imports on one line
135 changes: 73 additions & 62 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python

import sys, os, re, platform
import sys, os, re
from os.path import exists, abspath, dirname, join, isdir, relpath

try:
Expand All @@ -12,17 +12,14 @@
from distutils.extension import Extension
from distutils.errors import *

if sys.hexversion >= 0x03000000:
from configparser import ConfigParser
else:
from ConfigParser import ConfigParser

OFFICIAL_BUILD = 9999


def _print(s):
# Python 2/3 compatibility
sys.stdout.write(s + '\n')


class VersionCommand(Command):

description = "prints the pyodbc version, determined from git"
Expand Down Expand Up @@ -53,21 +50,19 @@ def finalize_options(self):
pass

def run(self):
# Windows versions of etag do not seem to expand wildcards (which Unix shells normally do for Unix utilities),
# so find all of the files ourselves.
files = [ join('src', f) for f in os.listdir('src') if f.endswith(('.h', '.cpp')) ]
# Windows versions of etag do not seem to expand wildcards (which Unix shells normally
# do for Unix utilities), so find all of the files ourselves.
files = [join('src', f) for f in os.listdir('src') if f.endswith(('.h', '.cpp'))]
cmd = 'etags %s' % ' '.join(files)
return os.system(cmd)



def main():

version_str, version = get_version()

settings = get_compiler_settings(version_str)

files = [ relpath(join('src', f)) for f in os.listdir('src') if f.endswith('.cpp') ]
files = [relpath(join('src', f)) for f in os.listdir('src') if f.endswith('.cpp')]

if exists('MANIFEST'):
os.remove('MANIFEST')
Expand All @@ -78,51 +73,51 @@ def main():
'description': "DB API Module for ODBC",

'long_description': ('A Python DB API 2 module for ODBC. This project provides an up-to-date, '
'convenient interface to ODBC using native data types like datetime and decimal.'),
'convenient interface to ODBC using native data types like datetime and decimal.'),

'maintainer': "Michael Kleehammer",
'maintainer': "Michael Kleehammer",
'maintainer_email': "michael@kleehammer.com",

'ext_modules': [Extension('pyodbc', files, **settings)],

'license': 'MIT',

'classifiers': ['Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: MIT License',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Topic :: Database',
],
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: MIT License',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Topic :: Database'],

'url': 'https://github.com/mkleehammer/pyodbc',
'cmdclass': { 'version' : VersionCommand,
'tags' : TagsCommand }
}
'cmdclass': {'version': VersionCommand,
'tags': TagsCommand}
}

if sys.hexversion >= 0x02060000:
kwargs['options'] = {
'bdist_wininst': {'user_access_control' : 'auto'}
}
'bdist_wininst': {'user_access_control': 'auto'}
}

setup(**kwargs)


def get_compiler_settings(version_str):

settings = {
'extra_compile_args' : [],
'extra_compile_args': [],
'libraries': [],
'include_dirs': [],
'define_macros' : [ ('PYODBC_VERSION', version_str) ]
'library_dirs': [],
'define_macros': [('PYODBC_VERSION', version_str)]
}

# This isn't the best or right way to do this, but I don't see how someone is supposed to sanely subclass the build
# command.
# This isn't the best or right way to do this, but I don't see how someone is supposed to
# sanely subclass the build command.
for option in ['assert', 'trace', 'leak-check']:
try:
sys.argv.remove('--%s' % option)
Expand All @@ -133,13 +128,13 @@ def get_compiler_settings(version_str):
if os.name == 'nt':
settings['extra_compile_args'].extend([
'/Wall',
'/wd4514', # unreference inline function removed
'/wd4820', # padding after struct member
'/wd4668', # is not defined as a preprocessor macro
'/wd4711', # function selected for automatic inline expansion
'/wd4100', # unreferenced formal parameter
'/wd4127', # "conditional expression is constant" testing compilation constants
'/wd4191', # casts to PYCFunction which doesn't have the keywords parameter
'/wd4514', # unreference inline function removed
'/wd4820', # padding after struct member
'/wd4668', # is not defined as a preprocessor macro
'/wd4711', # function selected for automatic inline expansion
'/wd4100', # unreferenced formal parameter
'/wd4127', # "conditional expression is constant" testing compilation constants
'/wd4191', # casts to PYCFunction which doesn't have the keywords parameter
])

if '--debug' in sys.argv:
Expand All @@ -159,31 +154,42 @@ def get_compiler_settings(version_str):
# unixODBC for now.
settings['libraries'].append('odbc')

# Python functions take a lot of 'char *' that really should be const. gcc complains about this *a lot*
# Python functions take a lot of 'char *' that really should be const. gcc complains
# about this *a lot*
settings['extra_compile_args'].extend([
'-Wno-write-strings',
'-Wno-deprecated-declarations'
])

# Apple has decided they won't maintain the iODBC system in OS/X and has added deprecation warnings in 10.8.
# For now target 10.7 to eliminate the warnings.
settings['define_macros'].append( ('MAC_OS_X_VERSION_10_7',) )
# Apple has decided they won't maintain the iODBC system in OS/X and has added
# deprecation warnings in 10.8. For now target 10.7 to eliminate the warnings.
settings['define_macros'].append(('MAC_OS_X_VERSION_10_7',))

# Add directories for MacPorts and Homebrew.
dirs = ['/usr/local/include', '/opt/local/include','~/homebrew/include']
dirs = ['/usr/local/include', '/opt/local/include', '~/homebrew/include']
settings['include_dirs'].extend(dir for dir in dirs if isdir(dir))

# macOS High Sierra removed these directories. It is not clear if that is going to be
# permanent or not. Since I unwisely installed the beta on my only macOS test box,
# I'll add these manually. If they are already supplied by previous versions, I don't
# think it would cause problems.
#
# https://github.com/Homebrew/homebrew-core/issues/14418

settings['library_dirs'] += ['/usr/lib', '/usr/local/lib']

else:
# Other posix-like: Linux, Solaris, etc.

# Python functions take a lot of 'char *' that really should be const. gcc complains about this *a lot*
# Python functions take a lot of 'char *' that really should be const. gcc complains
# about this *a lot*
settings['extra_compile_args'].append('-Wno-write-strings')

from array import array
UNICODE_WIDTH = array('u').itemsize
if UNICODE_WIDTH == 4:
# This makes UnixODBC use UCS-4 instead of UCS-2, which works better with sizeof(wchar_t)==4.
# Thanks to Marc-Antoine Parent
# This makes UnixODBC use UCS-4 instead of UCS-2, which works better with
# sizeof(wchar_t)==4. Thanks to Marc-Antoine Parent
settings['define_macros'].append(('SQL_WCHART_CONVERT', '1'))

# What is the proper way to detect iODBC, MyODBC, unixODBC, etc.?
Expand All @@ -203,23 +209,26 @@ def get_version():
read the version from the PKG-INFO file.
3. Use 4.0.0.0 and complain a lot.
"""
# My goal is to (1) provide accurate tags for official releases but (2) not have to manage tags for every test
# release.
# My goal is to (1) provide accurate tags for official releases but (2) not have to manage
# tags for every test release.
#
# Official versions are tagged using 3 numbers: major, minor, micro. A build of a tagged version should produce
# the version using just these pieces, such as 2.1.4.
# Official versions are tagged using 3 numbers: major, minor, micro. A build of a tagged
# version should produce the version using just these pieces, such as 2.1.4.
#
# Unofficial versions are "working towards" the next version. So the next unofficial build after 2.1.4 would be a
# beta for 2.1.5. Using 'git describe' we can find out how many changes have been made after 2.1.4 and we'll use
# this count as the beta id (beta1, beta2, etc.)
# Unofficial versions are "working towards" the next version. So the next unofficial build
# after 2.1.4 would be a beta for 2.1.5. Using 'git describe' we can find out how many
# changes have been made after 2.1.4 and we'll use this count as the beta id (beta1, beta2,
# etc.)
#
# Since the 4 numbers are put into the Windows DLL, we want to make sure the beta versions sort *before* the
# official, so we set the official build number to 9999, but we don't show it.
# Since the 4 numbers are put into the Windows DLL, we want to make sure the beta versions
# sort *before* the official, so we set the official build number to 9999, but we don't
# show it.

name = None # branch/feature name. Should be None for official builds.
numbers = None # The 4 integers that make up the version.

# If this is a source release the version will have already been assigned and be in the PKG-INFO file.
# If this is a source release the version will have already been assigned and be in the
# PKG-INFO file.

name, numbers = _get_version_pkginfo()

Expand All @@ -230,7 +239,7 @@ def get_version():

if not numbers:
_print('WARNING: Unable to determine version. Using 4.0.0.0')
name, numbers = '4.0.0-unsupported', [4,0,0,0]
name, numbers = '4.0.0-unsupported', [4, 0, 0, 0]

return name, numbers

Expand All @@ -244,7 +253,8 @@ def _get_version_pkginfo():
if match:
name = line.split(':', 1)[1].strip()
numbers = [int(n or 0) for n in match.groups()[:3]]
numbers.append(int(match.group(4) or OFFICIAL_BUILD)) # don't use 0 as a default for build
# don't use 0 as a default for build
numbers.append(int(match.group(4) or OFFICIAL_BUILD))
return name, numbers

return None, None
Expand All @@ -264,7 +274,8 @@ def _get_version_git():
if numbers[-1] == OFFICIAL_BUILD:
name = '%s.%s.%s' % tuple(numbers[:3])
if numbers[-1] != OFFICIAL_BUILD:
# This is a beta of the next micro release, so increment the micro number to reflect this.
# This is a beta of the next micro release, so increment the micro number to reflect
# this.
numbers[-2] += 1
name = '%s.%s.%sb%d' % tuple(numbers)

Expand All @@ -281,12 +292,12 @@ def _get_version_git():
return name, numbers



def getoutput(cmd):
pipe = os.popen(cmd, 'r')
text = pipe.read().rstrip('\n')
status = pipe.close() or 0
return status, text


if __name__ == '__main__':
main()

0 comments on commit 908c811

Please sign in to comment.