r"""
Logbook
-------

An awesome logging implementation that is fun to use.

Quickstart
``````````

::

    from logbook import Logger
    log = Logger('A Fancy Name')

    log.warn('Logbook is too awesome for most applications')
    log.error("Can't touch this")

Works for web apps too
``````````````````````

::

    from logbook import MailHandler, Processor

    mailhandler = MailHandler(from_addr='servererror@example.com',
                              recipients=['admin@example.com'],
                              level='ERROR', format_string=u'''\
    Subject: Application Error for {record.extra[path]} [{record.extra[method]}]

    Message type:       {record.level_name}
    Location:           {record.filename}:{record.lineno}
    Module:             {record.module}
    Function:           {record.func_name}
    Time:               {record.time:%Y-%m-%d %H:%M:%S}
    Remote IP:          {record.extra[ip]}
    Request:            {record.extra[path]} [{record.extra[method]}]

    Message:

    {record.message}
    ''')

    def handle_request(request):
        def inject_extra(record, handler):
            record.extra['ip'] = request.remote_addr
            record.extra['method'] = request.method
            record.extra['path'] = request.path

        with Processor(inject_extra):
            with mailhandler:
                # execute code that might fail in the context of the
                # request.
"""

import os
import platform
import sys
from itertools import chain

from distutils.command.build_ext import build_ext
from distutils.errors import (
    CCompilerError, DistutilsExecError, DistutilsPlatformError)
from setuptools import Distribution as _Distribution, Extension, setup
from setuptools.command.test import test as TestCommand

cmdclass = {}
if sys.version_info < (2, 6):
    raise Exception('Logbook requires Python 2.6 or higher.')

cpython = platform.python_implementation() == 'CPython'

ext_modules = [Extension('logbook._speedups', sources=['logbook/_speedups.c'])]

ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
if sys.platform == 'win32':
    # 2.6's distutils.msvc9compiler can raise an IOError when failing to
    # find the compiler
    ext_errors += (IOError,)


class BuildFailed(Exception):
    def __init__(self):
        self.cause = sys.exc_info()[1]  # work around py 2/3 different syntax


class ve_build_ext(build_ext):
    """This class allows C extension building to fail."""

    def run(self):
        try:
            build_ext.run(self)
        except DistutilsPlatformError:
            raise BuildFailed()

    def build_extension(self, ext):
        try:
            build_ext.build_extension(self, ext)
        except ext_errors:
            raise BuildFailed()
        except ValueError:
            # this can happen on Windows 64 bit, see Python issue 7511
            if "'path'" in str(sys.exc_info()[1]):  # works with both py 2/3
                raise BuildFailed()
            raise

cmdclass['build_ext'] = ve_build_ext


class Distribution(_Distribution):

    def has_ext_modules(self):
        # We want to always claim that we have ext_modules. This will be fine
        # if we don't actually have them (such as on PyPy) because nothing
        # will get built, however we don't want to provide an overally broad
        # Wheel package when building a wheel without C support. This will
        # ensure that Wheel knows to treat us as if the build output is
        # platform specific.
        return True


class PyTest(TestCommand):
    # from https://pytest.org/latest/goodpractises.html\
    # #integration-with-setuptools-test-commands
    user_options = [('pytest-args=', 'a', 'Arguments to pass to py.test')]

    default_options = ['tests']

    def initialize_options(self):
        TestCommand.initialize_options(self)
        self.pytest_args = ''

    def finalize_options(self):
        TestCommand.finalize_options(self)
        self.test_args = []
        self.test_suite = True

    def run_tests(self):
        # import here, cause outside the eggs aren't loaded
        import pytest
        errno = pytest.main(
            ' '.join(self.default_options) + ' ' + self.pytest_args)
        sys.exit(errno)

cmdclass['test'] = PyTest


def status_msgs(*msgs):
    print('*' * 75)
    for msg in msgs:
        print(msg)
    print('*' * 75)

version_file_path = os.path.join(
    os.path.dirname(__file__), 'logbook', '__version__.py')

with open(version_file_path) as version_file:
    exec(version_file.read())  # pylint: disable=W0122

extras_require = dict()
if sys.version_info[:2] < (3, 0):
    extras_require['test'] = set(['pytest', 'pytest-cov<2.6'])
else:
    extras_require['test'] = set(['pytest>4.0', 'pytest-cov>=2.6'])

if sys.version_info[:2] < (3, 3):
    extras_require['test'] |= set(['mock'])

extras_require['dev'] = set(['cython']) | extras_require['test']

extras_require['execnet'] = set(['execnet>=1.0.9'])
extras_require['sqlalchemy'] = set(['sqlalchemy'])
extras_require['redis'] = set(['redis'])
extras_require['zmq'] = set(['pyzmq'])
extras_require['jinja'] = set(['Jinja2'])
extras_require['compression'] = set(['brotli'])

extras_require['all'] = set(chain.from_iterable(extras_require.values()))


def run_setup(with_cext):
    kwargs = {}
    if with_cext:
        kwargs['ext_modules'] = ext_modules
    else:
        kwargs['ext_modules'] = []

    setup(
        name='Logbook',
        version=__version__,
        license='BSD',
        url='http://logbook.pocoo.org/',
        author='Armin Ronacher, Georg Brandl',
        author_email='armin.ronacher@active-4.com',
        description='A logging replacement for Python',
        long_description=__doc__,
        packages=['logbook'],
        zip_safe=False,
        platforms='any',
        cmdclass=cmdclass,
        tests_require=['pytest'],
        classifiers=[
            'Programming Language :: Python :: 2.7',
            'Programming Language :: Python :: 3.4',
            'Programming Language :: Python :: 3.5',
            'Programming Language :: Python :: 3.6',

        ],
        extras_require=extras_require,
        distclass=Distribution,
        **kwargs
    )

if not cpython:
    run_setup(False)
    status_msgs(
        'WARNING: C extensions are not supported on ' +
        'this Python platform, speedups are not enabled.',
        'Plain-Python build succeeded.'
    )
elif os.environ.get('DISABLE_LOGBOOK_CEXT'):
    run_setup(False)
    status_msgs(
        'DISABLE_LOGBOOK_CEXT is set; ' +
        'not attempting to build C extensions.',
        'Plain-Python build succeeded.'
    )
else:
    try:
        run_setup(True)
    except BuildFailed as exc:
        status_msgs(
            exc.cause,
            'WARNING: The C extension could not be compiled, ' +
            'speedups are not enabled.',
            'Failure information, if any, is above.',
            'Retrying the build without the C extension now.'
        )

        run_setup(False)

        status_msgs(
            'WARNING: The C extension could not be compiled, ' +
            'speedups are not enabled.',
            'Plain-Python build succeeded.'
        )
