<commit_before>import os

import dbt.exceptions
import dbt.flags
import dbt.include
import dbt.utils
import dbt.hooks
import dbt.clients.jinja
import dbt.context.parser

from dbt.include.global_project import PROJECT_NAME as GLOBAL_PROJECT_NAME
from dbt.utils import coalesce
from dbt.logger import GLOBAL_LOGGER as logger
from dbt.contracts.graph.parsed import ParsedNode
from dbt.parser.source_config import SourceConfig

class BaseParser(object):
    def __init__(self, root_project_config, all_projects):
        self.root_project_config = root_project_config
        self.all_projects = all_projects

    @property
    def default_schema(self):
        return getattr(self.root_project_config.credentials, 'schema',
                       'public')

    @property
    def default_database(self):
        return getattr(self.root_project_config.credentials, 'database', 'dbt')

    def load_and_parse(self, *args, **kwargs):
        raise dbt.exceptions.NotImplementedException("Not implemented")

    @classmethod
    def get_path(cls, resource_type, package_name, resource_name):
        """Returns a unique identifier for a resource"""

        return "{}.{}.{}".format(resource_type, package_name, resource_name)

    @classmethod
    def get_fqn(cls, path, package_project_config, extra=[]):
        parts = dbt.utils.split_path(path)
        name, _ = os.path.splitext(parts[-1])
        fqn = ([package_project_config.project_name] +
               parts[:-1] +
               extra +
               [name])

        return fqn

class MacrosKnownParser(BaseParser):
    def __init__(self, root_project_config, all_projects, macro_manifest):
        super(MacrosKnownParser, self).__init__(
            root_project_config=root_project_config,
            all_projects=all_projects
        )
        self.macro_manifest = macro_manifest
        self._get_schema_func = None
        self._get_alias_func = None

    def get_schema_func(self):
        """The get_schema function is set by a few different things:
            - if there is a 'generate_schema_name' macro in the root project,
                it will be used.
            - if that does not exist but there is a 'generate_schema_name'
                macro in the 'dbt' internal project, that will be used
            - if neither of those exist (unit tests?), a function that returns
                the 'default schema' as set in the root project's 'credentials'
                is used
        """
        if self._get_schema_func is not None:
            return self._get_schema_func

        get_schema_macro = self.macro_manifest.find_macro_by_name(
            'generate_schema_name',
            self.root_project_config.project_name
        )
        if get_schema_macro is None:
            get_schema_macro = self.macro_manifest.find_macro_by_name(
                'generate_schema_name',
                GLOBAL_PROJECT_NAME
            )
        if get_schema_macro is None:
            def get_schema(_):
                return self.default_schema
        else:
            root_context = dbt.context.parser.generate_macro(
                get_schema_macro, self.root_project_config,
                self.macro_manifest
            )
            get_schema = get_schema_macro.generator(root_context)

        self._get_schema_func = get_schema
        return self._get_schema_func

    def get_alias_func(self):
        """The get_alias function is set by a few different things:
            - if there is a 'generate_alias_name' macro in the root project,
                it will be used.
            - if that does not exist but there is a 'generate_alias_name'
                macro in the 'dbt' internal project, that will be used
            - if neither of those exist (unit tests?), a function that returns
                the 'default alias' as set in the model's filename or alias
                configuration.
        """
        if self._get_alias_func is not None:
            return self._get_alias_func

        get_alias_macro = self.macro_manifest.find_macro_by_name(
            'generate_alias_name',
            self.root_project_config.project_name
        )
        if get_alias_macro is None:
            get_alias_macro = self.macro_manifest.find_macro_by_name(
                'generate_alias_name',
                GLOBAL_PROJECT_NAME
            )
        if get_alias_macro is None:
            def get_alias(_):
                return self.default_alias
        else:
            root_context = dbt.context.parser.generate_macro(
                get_alias_macro, self.root_project_config,
                self.macro_manifest, 'generate_alias_name'
            )
            get_alias = get_alias_macro.generator(root_context)

        self._get_alias_func = get_alias
        return self._get_alias_func

    def _build_intermediate_node_dict(self, config, node_dict, node_path,
                                      package_project_config, tags, fqn,
                                      agate_table, archive_config,
                                      column_name):
        """Update the unparsed node dictionary and build the basis for an
        intermediate ParsedNode that will be passed into the renderer
        """
        # because this takes and returns dicts, subclasses can safely override
        # this and mutate its results using super() both before and after.
        if agate_table is not None:
            node_dict['agate_table'] = agate_table

        # Set this temporarily. Not the full config yet (as config() hasn't
        # been called from jinja yet). But the Var() call below needs info
        # about project level configs b/c they might contain refs.
        # TODO: Restructure this?
        config_dict = coalesce(archive_config, {})
        config_dict.update(config.config)

        empty = (
            'raw_sql' in node_dict and len(node_dict['raw_sql'].strip()) == 0
        )

        node_dict.update({
            'refs': [],
            'sources': [],
            'depends_on': {
                'nodes': [],
                'macros': [],
            },
            'unique_id': node_path,
            'empty': empty,
            'fqn': fqn,
            'tags': tags,
            'config': config_dict,
            # Set these temporarily so get_rendered() has access to a schema,
            # database, and alias.
            'schema': self.default_schema,
            'database': self.default_database,
            'alias': node_dict.get('name'),
        })

        # if there's a column, it should end up part of the ParsedNode
        if column_name is not None:
            node_dict['column_name'] = column_name

        return node_dict

    def _render_with_context(self, parsed_node, config):
        """Given the parsed node and a SourceConfig to use during parsing,
        render the node's sql wtih macro capture enabled.

        Note: this mutates the config object when config() calls are rendered.
        """
        context = dbt.context.parser.generate(
            parsed_node,
            self.root_project_config,
            self.macro_manifest,
            config)

        dbt.clients.jinja.get_rendered(
            parsed_node.raw_sql, context, parsed_node.to_shallow_dict(),
            capture_macros=True)

    def _update_parsed_node_info(self, parsed_node, config):
        """Given the SourceConfig used for parsing and the parsed node,
        generate and set the true values to use, overriding the temporary parse
        values set in _build_intermediate_parsed_node.
        """
        # Special macro defined in the global project. Use the root project's
        # definition, not the current package
        schema_override = config.config.get('schema')
        get_schema = self.get_schema_func()
        parsed_node.schema = get_schema(schema_override).strip()

        alias_override = config.config.get('alias')
        get_alias = self.get_alias_func()
        temp_node = config.config.get('alias', parsed_node.get('name'))
        parsed_node.alias = get_alias(temp_node, alias_override).strip()

        parsed_node.database = config.config.get(
            'database', self.default_database
        ).strip()

        # Set tags on node provided in config blocks
        model_tags = config.config.get('tags', [])
        parsed_node.tags.extend(model_tags)

        # Overwrite node config
        config_dict = parsed_node.get('config', {})
        config_dict.update(config.config)
        parsed_node.config = config_dict

        for hook_type in dbt.hooks.ModelHookType.Both:
            parsed_node.config[hook_type] = dbt.hooks.get_hooks(parsed_node,
                                                                hook_type)

    def parse_node(self, node, node_path, package_project_config, tags=None,
                   fqn_extra=None, fqn=None, agate_table=None,
                   archive_config=None, column_name=None):
        """Parse a node, given an UnparsedNode and any other required information.

        agate_table should be set if the node came from a seed file.
        archive_config should be set if the node is an Archive node.
        column_name should be set if the node is a Test node associated with a
        particular column.
        """
        logger.debug("Parsing {}".format(node_path))

        tags = coalesce(tags, [])
        fqn_extra = coalesce(fqn_extra, [])

        if fqn is None:
            fqn = self.get_fqn(node.path, package_project_config, fqn_extra)

        config = SourceConfig(
            self.root_project_config,
            package_project_config,
            fqn,
            node.resource_type)

        parsed_dict = self._build_intermediate_node_dict(
            config, node.serialize(), node_path, config, tags, fqn,
            agate_table, archive_config, column_name
        )
        parsed_node = ParsedNode(**parsed_dict)

        self._render_with_context(parsed_node, config)
        self._update_parsed_node_info(parsed_node, config)

        parsed_node.validate()

        return parsed_node
<commit_msg>Get unit testing working<commit_after>import os

import dbt.exceptions
import dbt.flags
import dbt.include
import dbt.utils
import dbt.hooks
import dbt.clients.jinja
import dbt.context.parser

from dbt.include.global_project import PROJECT_NAME as GLOBAL_PROJECT_NAME
from dbt.utils import coalesce
from dbt.logger import GLOBAL_LOGGER as logger
from dbt.contracts.graph.parsed import ParsedNode
from dbt.parser.source_config import SourceConfig

class BaseParser(object):
    def __init__(self, root_project_config, all_projects):
        self.root_project_config = root_project_config
        self.all_projects = all_projects

    @property
    def default_schema(self):
        return getattr(self.root_project_config.credentials, 'schema',
                       'public')

    @property
    def default_database(self):
        return getattr(self.root_project_config.credentials, 'database', 'dbt')

    def load_and_parse(self, *args, **kwargs):
        raise dbt.exceptions.NotImplementedException("Not implemented")

    @classmethod
    def get_path(cls, resource_type, package_name, resource_name):
        """Returns a unique identifier for a resource"""

        return "{}.{}.{}".format(resource_type, package_name, resource_name)

    @classmethod
    def get_fqn(cls, path, package_project_config, extra=[]):
        parts = dbt.utils.split_path(path)
        name, _ = os.path.splitext(parts[-1])
        fqn = ([package_project_config.project_name] +
               parts[:-1] +
               extra +
               [name])

        return fqn

class MacrosKnownParser(BaseParser):
    def __init__(self, root_project_config, all_projects, macro_manifest):
        super(MacrosKnownParser, self).__init__(
            root_project_config=root_project_config,
            all_projects=all_projects
        )
        self.macro_manifest = macro_manifest
        self._get_schema_func = None
        self._get_alias_func = None

    def get_schema_func(self):
        """The get_schema function is set by a few different things:
            - if there is a 'generate_schema_name' macro in the root project,
                it will be used.
            - if that does not exist but there is a 'generate_schema_name'
                macro in the 'dbt' internal project, that will be used
            - if neither of those exist (unit tests?), a function that returns
                the 'default schema' as set in the root project's 'credentials'
                is used
        """
        if self._get_schema_func is not None:
            return self._get_schema_func

        get_schema_macro = self.macro_manifest.find_macro_by_name(
            'generate_schema_name',
            self.root_project_config.project_name
        )
        if get_schema_macro is None:
            get_schema_macro = self.macro_manifest.find_macro_by_name(
                'generate_schema_name',
                GLOBAL_PROJECT_NAME
            )
        if get_schema_macro is None:
            def get_schema(_):
                return self.default_schema
        else:
            root_context = dbt.context.parser.generate_macro(
                get_schema_macro, self.root_project_config,
                self.macro_manifest
            )
            get_schema = get_schema_macro.generator(root_context)

        self._get_schema_func = get_schema
        return self._get_schema_func

    def get_alias_func(self):
        """The get_alias function is set by a few different things:
            - if there is a 'generate_alias_name' macro in the root project,
                it will be used.
            - if that does not exist but there is a 'generate_alias_name'
                macro in the 'dbt' internal project, that will be used
            - if neither of those exist (unit tests?), a function that returns
                the 'default alias' as set in the model's filename or alias
                configuration.
        """
        if self._get_alias_func is not None:
            return self._get_alias_func

        get_alias_macro = self.macro_manifest.find_macro_by_name(
            'generate_alias_name',
            self.root_project_config.project_name
        )
        if get_alias_macro is None:
            get_alias_macro = self.macro_manifest.find_macro_by_name(
                'generate_alias_name',
                GLOBAL_PROJECT_NAME
            )
        if get_alias_macro is None:
            def get_alias(node, _):
                return node
        else:
            root_context = dbt.context.parser.generate_macro(
                get_alias_macro, self.root_project_config,
                self.macro_manifest, 'generate_alias_name'
            )
            get_alias = get_alias_macro.generator(root_context)

        self._get_alias_func = get_alias
        return self._get_alias_func

    def _build_intermediate_node_dict(self, config, node_dict, node_path,
                                      package_project_config, tags, fqn,
                                      agate_table, archive_config,
                                      column_name):
        """Update the unparsed node dictionary and build the basis for an
        intermediate ParsedNode that will be passed into the renderer
        """
        # because this takes and returns dicts, subclasses can safely override
        # this and mutate its results using super() both before and after.
        if agate_table is not None:
            node_dict['agate_table'] = agate_table

        # Set this temporarily. Not the full config yet (as config() hasn't
        # been called from jinja yet). But the Var() call below needs info
        # about project level configs b/c they might contain refs.
        # TODO: Restructure this?
        config_dict = coalesce(archive_config, {})
        config_dict.update(config.config)

        empty = (
            'raw_sql' in node_dict and len(node_dict['raw_sql'].strip()) == 0
        )

        node_dict.update({
            'refs': [],
            'sources': [],
            'depends_on': {
                'nodes': [],
                'macros': [],
            },
            'unique_id': node_path,
            'empty': empty,
            'fqn': fqn,
            'tags': tags,
            'config': config_dict,
            # Set these temporarily so get_rendered() has access to a schema,
            # database, and alias.
            'schema': self.default_schema,
            'database': self.default_database,
            'alias': node_dict.get('name'),
        })

        # if there's a column, it should end up part of the ParsedNode
        if column_name is not None:
            node_dict['column_name'] = column_name

        return node_dict

    def _render_with_context(self, parsed_node, config):
        """Given the parsed node and a SourceConfig to use during parsing,
        render the node's sql wtih macro capture enabled.

        Note: this mutates the config object when config() calls are rendered.
        """
        context = dbt.context.parser.generate(
            parsed_node,
            self.root_project_config,
            self.macro_manifest,
            config)

        dbt.clients.jinja.get_rendered(
            parsed_node.raw_sql, context, parsed_node.to_shallow_dict(),
            capture_macros=True)

    def _update_parsed_node_info(self, parsed_node, config):
        """Given the SourceConfig used for parsing and the parsed node,
        generate and set the true values to use, overriding the temporary parse
        values set in _build_intermediate_parsed_node.
        """
        # Special macro defined in the global project. Use the root project's
        # definition, not the current package
        schema_override = config.config.get('schema')
        get_schema = self.get_schema_func()
        parsed_node.schema = get_schema(schema_override).strip()

        alias_override = config.config.get('alias')
        get_alias = self.get_alias_func()
        temp_node = config.config.get('alias', parsed_node.get('name'))
        parsed_node.alias = get_alias(temp_node, alias_override).strip()

        parsed_node.database = config.config.get(
            'database', self.default_database
        ).strip()

        # Set tags on node provided in config blocks
        model_tags = config.config.get('tags', [])
        parsed_node.tags.extend(model_tags)

        # Overwrite node config
        config_dict = parsed_node.get('config', {})
        config_dict.update(config.config)
        parsed_node.config = config_dict

        for hook_type in dbt.hooks.ModelHookType.Both:
            parsed_node.config[hook_type] = dbt.hooks.get_hooks(parsed_node,
                                                                hook_type)

    def parse_node(self, node, node_path, package_project_config, tags=None,
                   fqn_extra=None, fqn=None, agate_table=None,
                   archive_config=None, column_name=None):
        """Parse a node, given an UnparsedNode and any other required information.

        agate_table should be set if the node came from a seed file.
        archive_config should be set if the node is an Archive node.
        column_name should be set if the node is a Test node associated with a
        particular column.
        """
        logger.debug("Parsing {}".format(node_path))

        tags = coalesce(tags, [])
        fqn_extra = coalesce(fqn_extra, [])

        if fqn is None:
            fqn = self.get_fqn(node.path, package_project_config, fqn_extra)

        config = SourceConfig(
            self.root_project_config,
            package_project_config,
            fqn,
            node.resource_type)

        parsed_dict = self._build_intermediate_node_dict(
            config, node.serialize(), node_path, config, tags, fqn,
            agate_table, archive_config, column_name
        )
        parsed_node = ParsedNode(**parsed_dict)

        self._render_with_context(parsed_node, config)
        self._update_parsed_node_info(parsed_node, config)

        parsed_node.validate()

        return parsed_node
<|endoftext|>


<commit_before>"""A setuptools based setup module, template copied from https://github.com/pypa/sampleproject

See also:
https://packaging.python.org/en/latest/distributing.html
"""

from setuptools import setup, find_packages
from codecs import open
from os import path
from wc_utils.util.install import parse_requirements, install_dependencies
import re
import os
import wc_utils

here = path.abspath(path.dirname(__file__))

# Get the long description from the README file
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
    long_description = f.read()

# parse dependencies and links from requirements.txt files
with open('requirements.txt', 'r') as file:
    install_requires, dependency_links_install = parse_requirements(file.readlines())
with open('tests/requirements.txt', 'r') as file:
    tests_require, dependency_links_tests = parse_requirements(file.readlines())
dependency_links = list(set(dependency_links_install + dependency_links_tests))

# find needed pygit2 version
libgit2_path = os.getenv("LIBGIT2")
if not libgit2_path:
    if os.name == 'nt':
        libgit2_path = os.path.join(os.getenv("ProgramFiles"), 'libgit2')
    else:
        libgit2_path = '/usr/local'
version_filename = os.path.join(libgit2_path, 'include', 'git2', 'version.h')

libgit2_version = None
with open(version_filename, 'r') as file:
    for line in file:
        match = re.findall('define *LIBGIT2_VERSION *"(.*?)"', line.strip())
        if match:
            libgit2_version = match[0]
            break

if not libgit2_version:
    raise Exception(('wc_utils requires libgit2. Please install libgit2 and then retry installing '
                     'wc_utils. Please see https://libgit2.github.com for installation instructions.'))

i_pygit2 = install_requires.index('pygit2')
install_requires[i_pygit2] = 'pygit2<={}'.format(libgit2_version)

# install non-PyPI dependencies
install_dependencies(dependency_links)

# install package
setup(
    name='wc_utils',
    version=wc_utils.__version__,

    description='Utilities for whole-cell modeling',
    long_description=long_description,

    # The project's main homepage.
    url='https://github.com/KarrLab/wc_utils',

    author='Arthur Goldberg',
    author_email='Arthur.Goldberg@mssm.edu',

    license='MIT',

    # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
    classifiers=[
        'Development Status :: 3 - Alpha',

        # Indicate who your project is intended for
        'Intended Audience :: Developers',
        'Topic :: Software Development :: Whole-cell Models',

        # Pick your license as you wish (should match "license" above)
        'License :: OSI Approved :: MIT License',

        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
    ],

    keywords='whole-cell modeling',

    # packages not prepared yet
    packages=find_packages(exclude=['tests', 'tests.*']),
    package_data={
        'wc_utils': [
            'debug_logs/config.default.cfg',
            'debug_logs/config.schema.cfg',
        ],
    },

    install_requires=install_requires,
    tests_require=tests_require,
    dependency_links=dependency_links,
)
<commit_msg>issuing warning instead of failing if libgit not installed; this behavior is particularly useful for read the docs<commit_after>"""A setuptools based setup module, template copied from https://github.com/pypa/sampleproject

See also:
https://packaging.python.org/en/latest/distributing.html
"""

from setuptools import setup, find_packages
from codecs import open
from os import path
from wc_utils.util.install import parse_requirements, install_dependencies
import re
import os
import warnings
import wc_utils

here = path.abspath(path.dirname(__file__))

# Get the long description from the README file
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
    long_description = f.read()

# parse dependencies and links from requirements.txt files
with open('requirements.txt', 'r') as file:
    install_requires, dependency_links_install = parse_requirements(file.readlines())
with open('tests/requirements.txt', 'r') as file:
    tests_require, dependency_links_tests = parse_requirements(file.readlines())
dependency_links = list(set(dependency_links_install + dependency_links_tests))

# find needed pygit2 version
libgit2_path = os.getenv("LIBGIT2")
if not libgit2_path:
    if os.name == 'nt':
        libgit2_path = os.path.join(os.getenv("ProgramFiles"), 'libgit2')
    else:
        libgit2_path = '/usr/local'
version_filename = os.path.join(libgit2_path, 'include', 'git2', 'version.h')

libgit2_version = None
with open(version_filename, 'r') as file:
    for line in file:
        match = re.findall('define *LIBGIT2_VERSION *"(.*?)"', line.strip())
        if match:
            libgit2_version = match[0]
            break

i_pygit2 = install_requires.index('pygit2')
if libgit2_version:
    install_requires[i_pygit2] = 'pygit2<={}'.format(libgit2_version)
else:
    install_requires.pop(i_pygit2)
    warnings.warn(('wc_utils requires libgit2. Please install libgit2 and then retry installing '
                   'wc_utils. Please see https://libgit2.github.com for installation instructions.'))

# install non-PyPI dependencies
install_dependencies(dependency_links)

# install package
setup(
    name='wc_utils',
    version=wc_utils.__version__,

    description='Utilities for whole-cell modeling',
    long_description=long_description,

    # The project's main homepage.
    url='https://github.com/KarrLab/wc_utils',

    author='Arthur Goldberg',
    author_email='Arthur.Goldberg@mssm.edu',

    license='MIT',

    # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
    classifiers=[
        'Development Status :: 3 - Alpha',

        # Indicate who your project is intended for
        'Intended Audience :: Developers',
        'Topic :: Software Development :: Whole-cell Models',

        # Pick your license as you wish (should match "license" above)
        'License :: OSI Approved :: MIT License',

        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
    ],

    keywords='whole-cell modeling',

    # packages not prepared yet
    packages=find_packages(exclude=['tests', 'tests.*']),
    package_data={
        'wc_utils': [
            'debug_logs/config.default.cfg',
            'debug_logs/config.schema.cfg',
        ],
    },

    install_requires=install_requires,
    tests_require=tests_require,
    dependency_links=dependency_links,
)
<|endoftext|>


<commit_before>#!/usr/bin/python
# encoding=UTF-8

# Copyright © 2016 Jakub Wilk <jwilk@jwilk.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the “Software”), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from __future__ import print_function

import functools
import io
import re
import sys

import distutils.core
from distutils.command.build import build as cmd_build
from distutils.command.sdist import sdist as cmd_sdist

try:
    import configparser
except ImportError:
    import ConfigParser as configparser

def uopen(*args):
    if str == bytes:
        return open(*args)
    else:
        return open(*args, encoding='UTF-8')

def get_version():
    with uopen('doc/changelog') as file:
        line = file.readline()
    return line.split()[1].strip('()')

class cmd_build_doc(cmd_build):

    description = 'build documentation'

    def make_tags_rst(self, data_path, rst_path):
        cp = configparser.RawConfigParser()
        cp.read(data_path)
        with uopen(rst_path, 'w') as rst_file:
            self._make_tags_rst(cp, print=functools.partial(print, file=rst_file))

    def _make_tags_rst(self, data, print):
        _strip_leading_dot = functools.partial(
            re.compile('^[.]', re.MULTILINE).sub,
            ''
        )
        def _parse_multiline(value):
            for s in value.splitlines():
                if not s or s.isspace():
                    continue
                yield _strip_leading_dot(s)
        def parse_multiline(tag, key):
            value = tag.get(key, '')
            return _parse_multiline(value)
        for tagname in data.sections():
            tag = dict(data.items(tagname))
            print(tagname)
            print('~' * len(tagname))
            description = '\n'.join(
                parse_multiline(tag, 'description')
            )
            if not description.strip():
                raise ValueError('missing description for {0}'.format(tagname))
            print(description)
            print()
            references = list(parse_multiline(tag, 'references'))
            if references:
                print('References:', end='\n\n')
                for ref in references:
                    match = re.match(r'\A(?P<name>[\w-]+)[(](?P<section>[0-9])[)]\Z', ref)
                    if match is not None:
                        ref = r'**{name}**\ ({section})'.format(**match.groupdict())
                    print(' |', ref)
                print()
            print('Severity, certainty:', end='\n\n')
            print(' {0}, {1}'.format(tag['severity'], tag['certainty']))
            print()

    def make_man(self, rst_path, man_path):
        import docutils.core
        import docutils.writers.manpage
        if str == bytes:
            tmp_file = io.BytesIO()
        else:
            tmp_file = io.StringIO()
        tmp_file.close = object  # prevent docutils from closing the file
        docutils.core.publish_file(
            source_path=rst_path,
            destination=tmp_file,
            writer=docutils.writers.manpage.Writer(),
            settings_overrides=dict(input_encoding='UTF-8', halt_level=1),
        )
        tmp_file.seek(0)
        with uopen(man_path, 'w') as man_file:
            for line in tmp_file:
                if line.startswith('.BI'):
                    # work-around for <https://bugs.debian.org/806601>:
                    line = line.replace(r'\fP', r'\fR')
                man_file.write(line)

    def run(self):
        data_path = 'data/tags'
        tags_rst_path = 'doc/tags.rst'
        man_rst_path = 'doc/manpage.rst'
        man_path = 'doc/pydiatra.1'
        self.make_file([data_path], tags_rst_path, self.make_tags_rst, [data_path, tags_rst_path])
        self.make_file([tags_rst_path, man_rst_path], man_path, self.make_man, [man_rst_path, man_path])

for cmd in [cmd_build, cmd_sdist]:
    cmd.sub_commands[:0] = [('build_doc', None)]
del cmd

classifiers = '''
Development Status :: 4 - Beta
Environment :: Console
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 3
Topic :: Software Development :: Quality Assurance
'''.strip().splitlines()

setup_options = dict(
    name='pydiatra',
    version=get_version(),
    license='MIT',
    description='yet another static checker for Python code',
    classifiers=classifiers,
    url='http://jwilk.net/software/pydiatra',
    author='Jakub Wilk',
    author_email='jwilk@jwilk.net',
    packages=['pydiatra'],
    package_data=dict(pydiatra=['data/*']),
    scripts=['py{0}diatra'.format(*sys.version_info)],
    data_files = [('share/man/man1', ['doc/pydiatra.1', 'doc/py{0}diatra.1'.format(*sys.version_info)])],
    cmdclass=dict(build_doc=cmd_build_doc),
)

if __name__ == '__main__':
    distutils.core.setup(**setup_options)

# vim:ts=4 sts=4 sw=4 et
<commit_msg>setup: make the “data” symlink in sdist.<commit_after>#!/usr/bin/python
# encoding=UTF-8

# Copyright © 2016 Jakub Wilk <jwilk@jwilk.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the “Software”), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from __future__ import print_function

import functools
import io
import os
import re
import sys

import distutils.core
from distutils.command.build import build as distutils_build
from distutils.command.sdist import sdist as distutils_sdist

try:
    import configparser
except ImportError:
    import ConfigParser as configparser

def uopen(*args):
    if str == bytes:
        return open(*args)
    else:
        return open(*args, encoding='UTF-8')

def get_version():
    with uopen('doc/changelog') as file:
        line = file.readline()
    return line.split()[1].strip('()')

class cmd_build_doc(distutils_build):

    description = 'build documentation'

    def make_tags_rst(self, data_path, rst_path):
        cp = configparser.RawConfigParser()
        cp.read(data_path)
        with uopen(rst_path, 'w') as rst_file:
            self._make_tags_rst(cp, print=functools.partial(print, file=rst_file))

    def _make_tags_rst(self, data, print):
        _strip_leading_dot = functools.partial(
            re.compile('^[.]', re.MULTILINE).sub,
            ''
        )
        def _parse_multiline(value):
            for s in value.splitlines():
                if not s or s.isspace():
                    continue
                yield _strip_leading_dot(s)
        def parse_multiline(tag, key):
            value = tag.get(key, '')
            return _parse_multiline(value)
        for tagname in data.sections():
            tag = dict(data.items(tagname))
            print(tagname)
            print('~' * len(tagname))
            description = '\n'.join(
                parse_multiline(tag, 'description')
            )
            if not description.strip():
                raise ValueError('missing description for {0}'.format(tagname))
            print(description)
            print()
            references = list(parse_multiline(tag, 'references'))
            if references:
                print('References:', end='\n\n')
                for ref in references:
                    match = re.match(r'\A(?P<name>[\w-]+)[(](?P<section>[0-9])[)]\Z', ref)
                    if match is not None:
                        ref = r'**{name}**\ ({section})'.format(**match.groupdict())
                    print(' |', ref)
                print()
            print('Severity, certainty:', end='\n\n')
            print(' {0}, {1}'.format(tag['severity'], tag['certainty']))
            print()

    def make_man(self, rst_path, man_path):
        import docutils.core
        import docutils.writers.manpage
        if str == bytes:
            tmp_file = io.BytesIO()
        else:
            tmp_file = io.StringIO()
        tmp_file.close = object  # prevent docutils from closing the file
        docutils.core.publish_file(
            source_path=rst_path,
            destination=tmp_file,
            writer=docutils.writers.manpage.Writer(),
            settings_overrides=dict(input_encoding='UTF-8', halt_level=1),
        )
        tmp_file.seek(0)
        with uopen(man_path, 'w') as man_file:
            for line in tmp_file:
                if line.startswith('.BI'):
                    # work-around for <https://bugs.debian.org/806601>:
                    line = line.replace(r'\fP', r'\fR')
                man_file.write(line)

    def run(self):
        data_path = 'data/tags'
        tags_rst_path = 'doc/tags.rst'
        man_rst_path = 'doc/manpage.rst'
        man_path = 'doc/pydiatra.1'
        self.make_file([data_path], tags_rst_path, self.make_tags_rst, [data_path, tags_rst_path])
        self.make_file([tags_rst_path, man_rst_path], man_path, self.make_man, [man_rst_path, man_path])

distutils_build.sub_commands[:0] = [('build_doc', None)]

class cmd_sdist(distutils_sdist):

    def run(self):
        self.run_command('build_doc')
        return distutils_sdist.run(self)

    def make_release_tree(self, base_dir, files):
        distutils_sdist.make_release_tree(self, base_dir, files)
        # distutils doesn't seem to handle symlinks-to-directories
        # out of the box, so let's take care of them manually:
        target = os.readlink('data')
        dest = os.path.join(base_dir, 'data')
        distutils.log.info('linking %s -> %s', dest, target)
        if not self.dry_run:
            os.symlink(target, dest)

classifiers = '''
Development Status :: 4 - Beta
Environment :: Console
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 3
Topic :: Software Development :: Quality Assurance
'''.strip().splitlines()

setup_options = dict(
    name='pydiatra',
    version=get_version(),
    license='MIT',
    description='yet another static checker for Python code',
    classifiers=classifiers,
    url='http://jwilk.net/software/pydiatra',
    author='Jakub Wilk',
    author_email='jwilk@jwilk.net',
    packages=['pydiatra'],
    package_data=dict(pydiatra=['data/*']),
    scripts=['py{0}diatra'.format(*sys.version_info)],
    data_files = [('share/man/man1', ['doc/pydiatra.1', 'doc/py{0}diatra.1'.format(*sys.version_info)])],
    cmdclass=dict(
        build_doc=cmd_build_doc,
        sdist=cmd_sdist,
    ),
)

if __name__ == '__main__':
    distutils.core.setup(**setup_options)

# vim:ts=4 sts=4 sw=4 et
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import copy
import six
from jsrn import exceptions, registration
from jsrn.exceptions import ValidationError

RESOURCE_TYPE_FIELD = '$'
DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'abstract', 'name_space', 'name',)

class ResourceOptions(object):
    def __init__(self, meta):
        self.meta = meta
        self.fields = []
        self.virtual_fields = []
        self.name = None
        self.name_space = None
        self.abstract = False
        self.serialized_name = ''
        self.verbose_name = None
        self.verbose_name_plural = None
        self.parents = []

    def contribute_to_class(self, cls, name):
        cls._meta = self
        self.name = cls.__name__

        if self.meta:
            meta_attrs = self.meta.__dict__.copy()
            for name in self.meta.__dict__:
                if name.startswith('_'):
                    del meta_attrs[name]
            for attr_name in DEFAULT_NAMES:
                if attr_name in meta_attrs:
                    setattr(self, attr_name, meta_attrs.pop(attr_name))
                elif hasattr(self.meta, attr_name):
                    setattr(self, attr_name, getattr(self.meta, attr_name))

            # Any leftover attributes must be invalid.
            if meta_attrs != {}:
                raise TypeError("'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys()))
        del self.meta

        if not self.verbose_name:
            self.verbose_name = self.name.replace('_', ' ').strip('_ ')
        if not self.verbose_name_plural:
            self.verbose_name_plural = self.verbose_name + 's'

    def add_field(self, field):
        self.fields.append(field)
        if hasattr(self, '_field_cache'):
            del self._field_cache

        if hasattr(self, '_name_map'):
            del self._name_map

    def add_virtual_field(self, field):
        self.virtual_fields.append(field)

    @property
    def resource_name(self):
        """
        Full name of resource including namespace (if specified)
        """
        if self.name_space:
            return "%s.%s" % (self.name_space, self.name)
        else:
            return self.name

    @property
    def parent_resource_names(self):
        """
        List of parent resource names.
        """
        if not hasattr(self, '_parent_resource_names'):
            self._parent_resource_names = [p._meta.resource_name for p in self.parents]
        return self._parent_resource_names

    def __repr__(self):
        return '<Options for %s>' % self.resource_name

class ResourceBase(type):
    """
    Metaclass for all Resources.
    """
    def __new__(cls, name, bases, attrs):
        super_new = super(ResourceBase, cls).__new__

        parents = [b for b in bases if isinstance(b, ResourceBase)]
        if not parents:
            # If this isn't a subclass of Resource, don't do anything special.
            return super_new(cls, name, bases, attrs)

        # Create the class.
        module = attrs.pop('__module__')
        new_class = super_new(cls, name, bases, {'__module__': module})
        attr_meta = attrs.pop('Meta', None)
        abstract = getattr(attr_meta, 'abstract', False)
        if not attr_meta:
            meta = getattr(new_class, 'Meta', None)
        else:
            meta = attr_meta
        base_meta = getattr(new_class, '_meta', None)

        new_class.add_to_class('_meta', ResourceOptions(meta))
        if not abstract:
            # Namespace is inherited
            if not new_class._meta.name_space and base_meta:
                new_class._meta.name_space = base_meta.name_space

        # Bail out early if we have already created this class.
        r = registration.get_resource(new_class._meta.resource_name)
        if r is not None:
            return r

        # Add all attributes to the class.
        for obj_name, obj in attrs.items():
            new_class.add_to_class(obj_name, obj)

        # All the fields of any type declared on this model
        new_fields = new_class._meta.fields + new_class._meta.virtual_fields
        field_attnames = set([f.attname for f in new_fields])

        for base in parents:
            if not hasattr(base, '_meta'):
                # Things without _meta aren't functional models, so they're
                # uninteresting parents.
                continue

            parent_fields = base._meta.fields
            # Check for clashes between locally declared fields and those
            # on the base classes (we cannot handle shadowed fields at the
            # moment).
            for field in parent_fields:
                if field.attname in field_attnames:
                    raise Exception('Local field %r in class %r clashes with field of similar name from '
                                    'base class %r' % (field.attname, name, base.__name__))
            for field in parent_fields:
                new_class.add_to_class(field.attname, copy.deepcopy(field))

            new_class._meta.parents.append(base)

        if abstract:
            return new_class

        # Register resource
        registration.register_resources(new_class)

        # Because of the way imports happen (recursively), we may or may not be
        # the first time this model tries to register with the framework. There
        # should only be one class for each model, so we always return the
        # registered version.
        return registration.get_resource(new_class._meta.resource_name)

    def add_to_class(cls, name, value):
        if hasattr(value, 'contribute_to_class'):
            value.contribute_to_class(cls, name)
        else:
            setattr(cls, name, value)

class Resource(six.with_metaclass(ResourceBase)):
    def __init__(self, **kwargs):
        for field in iter(self._meta.fields):
            try:
                val = kwargs.pop(field.attname)
            except KeyError:
                val = field.get_default()
            setattr(self, field.attname, val)

        if kwargs:
            raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])

    def __repr__(self):
        return '<%s: %s>' % (self.__class__.__name__, self)

    def __str__(self):
        return '%s resource' % self.__class__.__name__

    def clean(self):
        """
        Chance to do more in depth validation.
        """
        pass

    def full_clean(self):
        """
        Calls clean_fields, clean on the resource and raises ``ValidationError``
        for any errors that occurred.
        """
        errors = {}

        try:
            self.clean_fields()
        except ValidationError as e:
            errors = e.update_error_dict(errors)

        try:
            self.clean()
        except ValidationError as e:
            errors = e.update_error_dict(errors)

        if errors:
            raise ValidationError(errors)

    def clean_fields(self):
        errors = {}

        for f in self._meta.fields:
            raw_value = f.value_from_object(self)

            if f.null and raw_value is None:
                continue
            try:
                setattr(self, f.attname, f.clean(raw_value))
            except ValidationError as e:
                errors[f.name] = e.messages

        if errors:
            raise ValidationError(errors)

def create_resource_from_dict(obj, resource_name=None):
    """
    Create a resource from a dict object.
    """
    assert isinstance(obj, dict)

    # Get the correct resource name
    document_resource_name = obj.pop(RESOURCE_TYPE_FIELD, resource_name)
    if not (document_resource_name or resource_name):
        raise exceptions.ValidationError("Resource not defined.")

    resource_type = registration.get_resource(document_resource_name)
    if not resource_type:
        raise exceptions.ValidationError("Resource `%s` is not registered." % document_resource_name)

    # Check if we have an inherited type.
    if resource_name and not (resource_name == document_resource_name or
                              resource_name in resource_type._meta.parent_resource_names):
        raise exceptions.ValidationError(
            "Expected resource `%s` does not match resource defined in JSRN document `%s`." % (
                resource_name, document_resource_name))

    errors = {}
    attrs = {}
    for f in resource_type._meta.fields:
        try:
            attrs[f.attname] = f.clean(obj.get(f.name))
        except exceptions.ValidationError as ve:
            errors[f.name] = ve.error_messages

    if errors:
        raise exceptions.ValidationError(errors)

    new_resource = resource_type(**attrs)
    new_resource.full_clean()
    return new_resource
<commit_msg>Fix issue causing Resource to be listed as a parent (from Django models). Issue is a side effect of using six to provide python 2.7 and 3 compatibility.<commit_after># -*- coding: utf-8 -*-
import copy
import six
from jsrn import exceptions, registration
from jsrn.exceptions import ValidationError

RESOURCE_TYPE_FIELD = '$'
DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'abstract', 'name_space', 'name',)

class ResourceOptions(object):
    def __init__(self, meta):
        self.meta = meta
        self.fields = []
        self.virtual_fields = []
        self.name = None
        self.name_space = None
        self.abstract = False
        self.serialized_name = ''
        self.verbose_name = None
        self.verbose_name_plural = None
        self.parents = []

    def contribute_to_class(self, cls, name):
        cls._meta = self
        self.name = cls.__name__

        if self.meta:
            meta_attrs = self.meta.__dict__.copy()
            for name in self.meta.__dict__:
                if name.startswith('_'):
                    del meta_attrs[name]
            for attr_name in DEFAULT_NAMES:
                if attr_name in meta_attrs:
                    setattr(self, attr_name, meta_attrs.pop(attr_name))
                elif hasattr(self.meta, attr_name):
                    setattr(self, attr_name, getattr(self.meta, attr_name))

            # Any leftover attributes must be invalid.
            if meta_attrs != {}:
                raise TypeError("'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys()))
        del self.meta

        if not self.verbose_name:
            self.verbose_name = self.name.replace('_', ' ').strip('_ ')
        if not self.verbose_name_plural:
            self.verbose_name_plural = self.verbose_name + 's'

    def add_field(self, field):
        self.fields.append(field)
        if hasattr(self, '_field_cache'):
            del self._field_cache

        if hasattr(self, '_name_map'):
            del self._name_map

    def add_virtual_field(self, field):
        self.virtual_fields.append(field)

    @property
    def resource_name(self):
        """
        Full name of resource including namespace (if specified)
        """
        if self.name_space:
            return "%s.%s" % (self.name_space, self.name)
        else:
            return self.name

    @property
    def parent_resource_names(self):
        """
        List of parent resource names.
        """
        if not hasattr(self, '_parent_resource_names'):
            self._parent_resource_names = [p._meta.resource_name for p in self.parents]
        return self._parent_resource_names

    def __repr__(self):
        return '<Options for %s>' % self.resource_name

class ResourceBase(type):
    """
    Metaclass for all Resources.
    """
    def __new__(cls, name, bases, attrs):
        super_new = super(ResourceBase, cls).__new__

        # attrs will never be empty for classes declared in the standard way
        # (ie. with the `class` keyword). This is quite robust.
        if name == 'NewBase' and attrs == {}:
            return super_new(cls, name, bases, attrs)

        parents = [b for b in bases if isinstance(b, ResourceBase) and
                                       not (b.__name__ == 'NewBase' and b.__mro__ == (b, object))]
        if not parents:
            # If this isn't a subclass of Resource, don't do anything special.
            return super_new(cls, name, bases, attrs)

        # Create the class.
        module = attrs.pop('__module__')
        new_class = super_new(cls, name, bases, {'__module__': module})
        attr_meta = attrs.pop('Meta', None)
        abstract = getattr(attr_meta, 'abstract', False)
        if not attr_meta:
            meta = getattr(new_class, 'Meta', None)
        else:
            meta = attr_meta
        base_meta = getattr(new_class, '_meta', None)

        new_class.add_to_class('_meta', ResourceOptions(meta))
        if not abstract:
            # Namespace is inherited
            if not new_class._meta.name_space and base_meta:
                new_class._meta.name_space = base_meta.name_space

        # Bail out early if we have already created this class.
        r = registration.get_resource(new_class._meta.resource_name)
        if r is not None:
            return r

        # Add all attributes to the class.
        for obj_name, obj in attrs.items():
            new_class.add_to_class(obj_name, obj)

        # All the fields of any type declared on this model
        new_fields = new_class._meta.fields + new_class._meta.virtual_fields
        field_attnames = set([f.attname for f in new_fields])

        for base in parents:
            if not hasattr(base, '_meta'):
                # Things without _meta aren't functional models, so they're
                # uninteresting parents.
                continue

            parent_fields = base._meta.fields
            # Check for clashes between locally declared fields and those
            # on the base classes (we cannot handle shadowed fields at the
            # moment).
            for field in parent_fields:
                if field.attname in field_attnames:
                    raise Exception('Local field %r in class %r clashes with field of similar name from '
                                    'base class %r' % (field.attname, name, base.__name__))
            for field in parent_fields:
                new_class.add_to_class(field.attname, copy.deepcopy(field))

            new_class._meta.parents.append(base)

        if abstract:
            return new_class

        # Register resource
        registration.register_resources(new_class)

        # Because of the way imports happen (recursively), we may or may not be
        # the first time this model tries to register with the framework. There
        # should only be one class for each model, so we always return the
        # registered version.
        return registration.get_resource(new_class._meta.resource_name)

    def add_to_class(cls, name, value):
        if hasattr(value, 'contribute_to_class'):
            value.contribute_to_class(cls, name)
        else:
            setattr(cls, name, value)

class Resource(six.with_metaclass(ResourceBase)):
    def __init__(self, **kwargs):
        for field in iter(self._meta.fields):
            try:
                val = kwargs.pop(field.attname)
            except KeyError:
                val = field.get_default()
            setattr(self, field.attname, val)

        if kwargs:
            raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])

    def __repr__(self):
        return '<%s: %s>' % (self.__class__.__name__, self)

    def __str__(self):
        return '%s resource' % self.__class__.__name__

    def clean(self):
        """
        Chance to do more in depth validation.
        """
        pass

    def full_clean(self):
        """
        Calls clean_fields, clean on the resource and raises ``ValidationError``
        for any errors that occurred.
        """
        errors = {}

        try:
            self.clean_fields()
        except ValidationError as e:
            errors = e.update_error_dict(errors)

        try:
            self.clean()
        except ValidationError as e:
            errors = e.update_error_dict(errors)

        if errors:
            raise ValidationError(errors)

    def clean_fields(self):
        errors = {}

        for f in self._meta.fields:
            raw_value = f.value_from_object(self)

            if f.null and raw_value is None:
                continue
            try:
                setattr(self, f.attname, f.clean(raw_value))
            except ValidationError as e:
                errors[f.name] = e.messages

        if errors:
            raise ValidationError(errors)

def create_resource_from_dict(obj, resource_name=None):
    """
    Create a resource from a dict object.
    """
    assert isinstance(obj, dict)

    # Get the correct resource name
    document_resource_name = obj.pop(RESOURCE_TYPE_FIELD, resource_name)
    if not (document_resource_name or resource_name):
        raise exceptions.ValidationError("Resource not defined.")

    resource_type = registration.get_resource(document_resource_name)
    if not resource_type:
        raise exceptions.ValidationError("Resource `%s` is not registered." % document_resource_name)

    # Check if we have an inherited type.
    if resource_name and not (resource_name == document_resource_name or
                              resource_name in resource_type._meta.parent_resource_names):
        raise exceptions.ValidationError(
            "Expected resource `%s` does not match resource defined in JSRN document `%s`." % (
                resource_name, document_resource_name))

    errors = {}
    attrs = {}
    for f in resource_type._meta.fields:
        try:
            attrs[f.attname] = f.clean(obj.get(f.name))
        except exceptions.ValidationError as ve:
            errors[f.name] = ve.error_messages

    if errors:
        raise exceptions.ValidationError(errors)

    new_resource = resource_type(**attrs)
    new_resource.full_clean()
    return new_resource
<|endoftext|>


<commit_before>__author__ = 'Georgios Rizos (georgerizos@iti.gr)'

from setuptools import setup
from setuptools.extension import Extension
try:
    from Cython.Distutils import build_ext
except ImportError:
    USE_CYTHON = False
else:
    USE_CYTHON = True
import numpy
C_OPT_FLAG = "-O3"

def readme():
    with open("README.md") as f:
        return f.read()

cmdclass = dict()
ext_modules = list()

# Either use cython to translate the .pyx files, or compile the distributed .c files as translated by the author.
if USE_CYTHON:
    ext_modules.append(Extension(name="reveal_graph_embedding.embedding.arcte.cython_opt.arcte",
                                 sources=["reveal_graph_embedding/embedding/arcte/cython_opt/arcte.pyx"],
                                 extra_compile_args=[C_OPT_FLAG, '-I/user/local/include/python3.4'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.push",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/push.pyx"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.transition",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/transition.pyx"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.similarity",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/similarity.pyx"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    cmdclass.update({"build_ext": build_ext})
else:
    ext_modules.append(Extension(name="reveal_graph_embedding.embedding.arcte.cython_opt.arcte",
                                 sources=["reveal_graph_embedding/embedding/arcte/cython_opt/arcte.c"],
                                 extra_compile_args=[C_OPT_FLAG, '-I/user/local/include/python3.4'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.push",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/push.c"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.transition",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/transition.c"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.similarity",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/similarity.c"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))

setup(
    name='reveal-graph-embedding',
    version='0.1',
    author='Georgios Rizos',
    author_email='georgerizos@iti.gr',
    packages=['reveal_graph_embedding',
              'reveal_graph_embedding.datautil',
              'reveal_graph_embedding.datautil.asu_datautil',
              'reveal_graph_embedding.datautil.insight_datautil',
              'reveal_graph_embedding.datautil.snow_datautil',
              'reveal_graph_embedding.embedding',
              'reveal_graph_embedding.embedding.arcte',
              'reveal_graph_embedding.embedding.arcte.cython_opt',
              'reveal_graph_embedding.eps_randomwalk',
              'reveal_graph_embedding.eps_randomwalk.benchmarks',
              'reveal_graph_embedding.eps_randomwalk.benchmarks.time_comparisons',
              'reveal_graph_embedding.eps_randomwalk.cython_opt',
              'reveal_graph_embedding.learning',
              'reveal_graph_embedding.quality'],
    cmdclass=cmdclass,
    ext_modules=ext_modules,
    url='https://github.com/MKLab-ITI/reveal-graph-embedding',
    license='Apache',
    description='Implementation of community-based graph embedding for user classification.',
    long_description=readme(),
    classifiers=[
        'Development Status :: 2 - Pre-Alpha',
        'Intended Audience :: Science/Research',
        'License :: OSI Approved :: Apache Software License',
        'Natural Language :: English',
        'Operating System :: Unix',
        'Programming Language :: Cython',
        'Programming Language :: Python',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3 :: Only',
        'Programming Language :: Python :: Implementation',
        'Programming Language :: Python :: Implementation :: CPython',
        'Topic :: Scientific/Engineering :: Information Analysis'
    ],
    keywords="online-social-network user-centric-pagerank user-centric-community-detection graph-embedding Reveal-FP7",
    entry_points={
        'console_scripts': ['arcte=reveal_graph_embedding.entry_points.arcte:main'],
    },
    include_package_data=False,
    install_requires=[]
)
<commit_msg>PyPI upload changes.<commit_after>__author__ = 'Georgios Rizos (georgerizos@iti.gr)'

from setuptools import setup
from setuptools.extension import Extension
try:
    from Cython.Distutils import build_ext
except ImportError:
    USE_CYTHON = False
else:
    USE_CYTHON = True
import numpy
C_OPT_FLAG = "-O3"

def readme():
    with open("README.md") as f:
        return f.read()

cmdclass = dict()
ext_modules = list()

# Either use cython to translate the .pyx files, or compile the distributed .c files as translated by the author.
if USE_CYTHON:
    ext_modules.append(Extension(name="reveal_graph_embedding.embedding.arcte.cython_opt.arcte",
                                 sources=["reveal_graph_embedding/embedding/arcte/cython_opt/arcte.pyx"],
                                 extra_compile_args=[C_OPT_FLAG, '-I/user/local/include/python3.4'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.push",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/push.pyx"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.transition",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/transition.pyx"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.similarity",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/similarity.pyx"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    cmdclass.update({"build_ext": build_ext})
else:
    ext_modules.append(Extension(name="reveal_graph_embedding.embedding.arcte.cython_opt.arcte",
                                 sources=["reveal_graph_embedding/embedding/arcte/cython_opt/arcte.c"],
                                 extra_compile_args=[C_OPT_FLAG, '-I/user/local/include/python3.4'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.push",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/push.c"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.transition",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/transition.c"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))
    ext_modules.append(Extension(name="reveal_graph_embedding.eps_randomwalk.cython_opt.similarity",
                                 sources=["reveal_graph_embedding/eps_randomwalk/cython_opt/similarity.c"],
                                 extra_compile_args=[C_OPT_FLAG, '-fopenmp', '-I/user/local/include/python3.4'],
                                 extra_link_args=['-fopenmp'],
                                 include_dirs=[numpy.get_include()]))

setup(
    name='reveal-graph-embedding',
    version='0.1.2',
    author='Georgios Rizos',
    author_email='georgerizos@iti.gr',
    packages=['reveal_graph_embedding',
              'reveal_graph_embedding.datautil',
              'reveal_graph_embedding.datautil.asu_datautil',
              'reveal_graph_embedding.datautil.insight_datautil',
              'reveal_graph_embedding.datautil.snow_datautil',
              'reveal_graph_embedding.embedding',
              'reveal_graph_embedding.embedding.arcte',
              'reveal_graph_embedding.embedding.arcte.cython_opt',
              'reveal_graph_embedding.eps_randomwalk',
              'reveal_graph_embedding.eps_randomwalk.benchmarks',
              'reveal_graph_embedding.eps_randomwalk.benchmarks.time_comparisons',
              'reveal_graph_embedding.eps_randomwalk.cython_opt',
              'reveal_graph_embedding.learning',
              'reveal_graph_embedding.quality'],
    cmdclass=cmdclass,
    ext_modules=ext_modules,
    url='https://github.com/MKLab-ITI/reveal-graph-embedding',
    license='Apache',
    description='Implementation of community-based graph embedding for user classification.',
    long_description=readme(),
    classifiers=[
        'Development Status :: 2 - Pre-Alpha',
        'Intended Audience :: Science/Research',
        'License :: OSI Approved :: Apache Software License',
        'Natural Language :: English',
        'Operating System :: Unix',
        'Programming Language :: Cython',
        'Programming Language :: Python',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3 :: Only',
        'Programming Language :: Python :: Implementation',
        'Programming Language :: Python :: Implementation :: CPython',
        'Topic :: Scientific/Engineering :: Information Analysis'
    ],
    keywords="online-social-network user-centric-pagerank user-centric-community-detection graph-embedding Reveal-FP7",
    entry_points={
        'console_scripts': ['arcte=reveal_graph_embedding.entry_points.arcte:main'],
    },
    include_package_data=False,
    install_requires=[]
)
<|endoftext|>


<commit_before>from setuptools import setup
from setuptools import find_packages
from os.path import join, dirname
# We need io.open() (Python 3's default open) to specify file encodings
import io

with open(join(dirname(__file__), 'foolbox/VERSION')) as f:
    version = f.read().strip()

try:
    # obtain long description from README
    # Specify encoding to get a unicode type in Python 2 and a str in Python 3
    readme_path = join(dirname(__file__), 'README.rst')
    with io.open(readme_path, encoding='utf-8') as fr:
        README = fr.read()
except IOError:
    README = ''

install_requires = [
    'numpy',
    'scipy',
    'setuptools',
    'requests',
    'GitPython'
]

tests_require = [
    'pytest',
    'pytest-cov',
]

setup(
    name="foolbox",
    version=version,
    description="Python toolbox to create adversarial examples that fool neural networks",
    long_description=README,
    classifiers=[
        "Development Status :: 3 - Alpha",
        "Intended Audience :: Developers",
        "Intended Audience :: Science/Research",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: 2.7",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.5",
        "Programming Language :: Python :: 3.6",
        "Topic :: Scientific/Engineering :: Artificial Intelligence",
    ],
    keywords="",
    author="Jonas Rauber & Wieland Brendel",
    author_email="opensource@bethgelab.org",
    url="https://github.com/bethgelab/foolbox",
    license="MIT",
    packages=find_packages(),
    include_package_data=True,
    zip_safe=False,
    install_requires=install_requires,
    extras_require={
        'testing': tests_require,
        ':python_version == "2.7"': ['future', 'futures'],
    },
)
<commit_msg>removed Python 2.7 from setup.py<commit_after>from setuptools import setup
from setuptools import find_packages
from os.path import join, dirname
# We need io.open() (Python 3's default open) to specify file encodings
import io

with open(join(dirname(__file__), 'foolbox/VERSION')) as f:
    version = f.read().strip()

try:
    # obtain long description from README
    # Specify encoding to get a unicode type in Python 2 and a str in Python 3
    readme_path = join(dirname(__file__), 'README.rst')
    with io.open(readme_path, encoding='utf-8') as fr:
        README = fr.read()
except IOError:
    README = ''

install_requires = [
    'numpy',
    'scipy',
    'setuptools',
    'requests',
    'GitPython'
]

tests_require = [
    'pytest',
    'pytest-cov',
]

setup(
    name="foolbox",
    version=version,
    description="Python toolbox to create adversarial examples that fool neural networks",
    long_description=README,
    classifiers=[
        "Development Status :: 3 - Alpha",
        "Intended Audience :: Developers",
        "Intended Audience :: Science/Research",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.5",
        "Programming Language :: Python :: 3.6",
        "Topic :: Scientific/Engineering :: Artificial Intelligence",
    ],
    keywords="",
    author="Jonas Rauber & Wieland Brendel",
    author_email="opensource@bethgelab.org",
    url="https://github.com/bethgelab/foolbox",
    license="MIT",
    packages=find_packages(),
    include_package_data=True,
    zip_safe=False,
    install_requires=install_requires,
    extras_require={
        'testing': tests_require,
    },
)
<|endoftext|>


<commit_before>from distutils.version import LooseVersion
from setuptools import setup

import versioneer

using_ipy4 = False
try:
    from IPython import __version__ as ipyv
    using_ipy4 = (ipyv >= LooseVersion("4"))
except ImportError:
    using_ipy4 = True

install_requires = [
    'Jinja2>=2.7.2',
    'Pygments>=1.6',
    'ipython>=2.3.1',
    'pyzmq>=14.1.0',
]
if using_ipy4:
    install_requires.extend([
        'ipykernel>=4.0.0',
        'nbconvert>=4.0.0',
        'nbformat>=4.0.0',
    ])

readme = ""
with open("README.rst") as readme_file:
    readme = readme_file.read()

setup(
    name='runipy',
    version=versioneer.get_version(),
    license="BSD 2-Clause",
    description='Run IPython notebooks from the command line',
    long_description=readme,
    url='https://github.com/paulgb/runipy',
    author='Paul Butler',
    author_email='paulgb@gmail.com',
    maintainer='John Kirkham',
    maintainer_email='jakirkham@gmail.com',
    platforms='any',
    classifiers=[
        'Environment :: Console',
        'Framework :: IPython',
        'License :: OSI Approved :: BSD License',
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
    ],
    install_requires=install_requires,
    packages=['runipy'],
    entry_points={
        'console_scripts': [
            'runipy = runipy.main:main'
        ]
    },
    cmdclass=versioneer.get_cmdclass(),
    test_suite="test_runipy",
    zip_safe=True
)
<commit_msg>setup.py: Add "ipython" to the `keywords`.<commit_after>from distutils.version import LooseVersion
from setuptools import setup

import versioneer

using_ipy4 = False
try:
    from IPython import __version__ as ipyv
    using_ipy4 = (ipyv >= LooseVersion("4"))
except ImportError:
    using_ipy4 = True

install_requires = [
    'Jinja2>=2.7.2',
    'Pygments>=1.6',
    'ipython>=2.3.1',
    'pyzmq>=14.1.0',
]
if using_ipy4:
    install_requires.extend([
        'ipykernel>=4.0.0',
        'nbconvert>=4.0.0',
        'nbformat>=4.0.0',
    ])

readme = ""
with open("README.rst") as readme_file:
    readme = readme_file.read()

setup(
    name='runipy',
    version=versioneer.get_version(),
    license="BSD 2-Clause",
    description='Run IPython notebooks from the command line',
    long_description=readme,
    url='https://github.com/paulgb/runipy',
    author='Paul Butler',
    author_email='paulgb@gmail.com',
    maintainer='John Kirkham',
    maintainer_email='jakirkham@gmail.com',
    platforms='any',
    classifiers=[
        'Environment :: Console',
        'Framework :: IPython',
        'License :: OSI Approved :: BSD License',
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
    ],
    keywords='ipython',
    install_requires=install_requires,
    packages=['runipy'],
    entry_points={
        'console_scripts': [
            'runipy = runipy.main:main'
        ]
    },
    cmdclass=versioneer.get_cmdclass(),
    test_suite="test_runipy",
    zip_safe=True
)
<|endoftext|>


<commit_before># Copyright (c) 2014. Mount Sinai School of Medicine
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os

readme_filename = os.path.join(os.path.dirname(__file__), 'README.md')

try:
    with open(readme_filename, 'r') as f:
        readme = f.read()
except:
    print("Failed to load README file")
    readme = ""

try:
    import pypandoc
    readme = pypandoc.convert(readme, to='rst', format='md')
except:
    print("Conversion of long_description from markdown to reStructuredText failed, skipping...")

from setuptools import setup

if __name__ == '__main__':
    setup(
        name='datacache',
        version="0.4.6",
        description="Helpers for transparently downloading datasets",
        author="Alex Rubinsteyn",
        author_email="alex {dot} rubinsteyn {at} mssm {dot} edu",
        url="https://github.com/hammerlab/datacache",
        license="http://www.apache.org/licenses/LICENSE-2.0.html",
        classifiers=[
            'Development Status :: 3 - Alpha',
            'Environment :: Console',
            'Operating System :: OS Independent',
            'Intended Audience :: Science/Research',
            'License :: OSI Approved :: Apache Software License',
            'Programming Language :: Python',
            'Topic :: Scientific/Engineering :: Bio-Informatics',
        ],
        install_requires=[
            'pandas>=0.15.2',
            'appdirs>=1.4.0',
            'progressbar>=2.2',
            'biopython>=1.65',
            'requests>=2.5.1',
            'typechecks>=0.0.0'
        ],
        long_description=readme,
        packages=['datacache'],
    )
<commit_msg>version bump<commit_after># Copyright (c) 2014. Mount Sinai School of Medicine
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os

readme_filename = os.path.join(os.path.dirname(__file__), 'README.md')

try:
    with open(readme_filename, 'r') as f:
        readme = f.read()
except:
    print("Failed to load README file")
    readme = ""

try:
    import pypandoc
    readme = pypandoc.convert(readme, to='rst', format='md')
except:
    print("Conversion of long_description from markdown to reStructuredText failed, skipping...")

from setuptools import setup

if __name__ == '__main__':
    setup(
        name='datacache',
        version="0.4.7",
        description="Helpers for transparently downloading datasets",
        author="Alex Rubinsteyn",
        author_email="alex {dot} rubinsteyn {at} mssm {dot} edu",
        url="https://github.com/hammerlab/datacache",
        license="http://www.apache.org/licenses/LICENSE-2.0.html",
        classifiers=[
            'Development Status :: 3 - Alpha',
            'Environment :: Console',
            'Operating System :: OS Independent',
            'Intended Audience :: Science/Research',
            'License :: OSI Approved :: Apache Software License',
            'Programming Language :: Python',
            'Topic :: Scientific/Engineering :: Bio-Informatics',
        ],
        install_requires=[
            'pandas>=0.15.2',
            'appdirs>=1.4.0',
            'progressbar>=2.2',
            'biopython>=1.65',
            'requests>=2.5.1',
            'typechecks>=0.0.0'
        ],
        long_description=readme,
        packages=['datacache'],
    )
<|endoftext|>


<commit_before>from __future__ import absolute_import, division

from twisted.internet import defer
from twisted.python import log, failure
from twisted.python.compat import unicode, intToBytes
from twisted.web import server
from twisted.web.iweb import IRenderable
from twisted.web.resource import Resource, IResource, getChildForRequest
from twisted.web.server import NOT_DONE_YET
from twisted.web.template import renderElement

from werkzeug.exceptions import HTTPException

from klein.interfaces import IKleinRequest

__all__ = ["KleinResource", "ensure_utf8_bytes"]

def ensure_utf8_bytes(v):
    """
    Coerces a value which is either a C{unicode} or C{str} to a C{str}.
    If ``v`` is a C{unicode} object it is encoded as utf-8.
    """
    if isinstance(v, unicode):
        v = v.encode("utf-8")
    return v

class _StandInResource(object):
    """
    A standin for a Resource.

    This is a sentinel value for L{KleinResource}, to say that we are rendering
    a L{Resource}, which may close the connection itself later.
    """

class _URLDecodeError(Exception):
    """
    Raised if one or more string parts of the URL could not be decoded.
    """
    __slots__ = ["errors"]

    def __init__(self, errors):
        """
        @param errors: List of decoding errors.
        @type errors: L{list} of L{tuple} of L{str},
            L{twisted.python.failure.Failure}
        """
        self.errors = errors

    def __repr__(self):
        return "<URLDecodeError(errors={0!r})>".format(self.errors)

def _extractURLparts(request):
    """
    Extracts and decodes URI parts from C{request}.

    All strings must be UTF8-decodable.

    @param request: A Twisted Web request.
    @type request: L{twisted.web.iweb.IRequest}

    @raise URLDecodeError: If one of the parts could not be decoded as UTF-8.

    @return: L{tuple} of the URL scheme, the server name, the server port, the
        path info and the script name.
    @rtype: L{tuple} of L{unicode}, L{unicode}, L{int}, L{unicode}, L{unicode}
    """
    server_name = request.getRequestHostname()
    if hasattr(request.getHost(), 'port'):
        server_port = request.getHost().port
    else:
        server_port = 0
    if (bool(request.isSecure()), server_port) not in [
            (True, 443), (False, 80), (False, 0), (True, 0)]:
        server_name = server_name + b":" + intToBytes(server_port)

    script_name = b''
    if request.prepath:
        script_name = b'/'.join(request.prepath)

        if not script_name.startswith(b'/'):
            script_name = b'/' + script_name

    path_info = b''
    if request.postpath:
        path_info = b'/'.join(request.postpath)

        if not path_info.startswith(b'/'):
            path_info = b'/' + path_info

    url_scheme = u'https' if request.isSecure() else u'http'

    utf8Failures = []
    try:
        server_name = server_name.decode("utf-8")
    except UnicodeDecodeError:
        utf8Failures.append(("SERVER_NAME", failure.Failure()))
    try:
        path_info = path_info.decode("utf-8")
    except UnicodeDecodeError:
        utf8Failures.append(("PATH_INFO", failure.Failure()))
    try:
        script_name = script_name.decode("utf-8")
    except UnicodeDecodeError:
        utf8Failures.append(("SCRIPT_NAME", failure.Failure()))

    if utf8Failures:
        raise _URLDecodeError(utf8Failures)

    return url_scheme, server_name, server_port, path_info, script_name

class KleinResource(Resource):
    """
    A ``Resource`` that can do URL routing.
    """
    isLeaf = True

    def __init__(self, app):
        Resource.__init__(self)
        self._app = app

    def __eq__(self, other):
        if isinstance(other, KleinResource):
            return vars(self) == vars(other)
        return NotImplemented

    def __ne__(self, other):
        result = self.__eq__(other)
        if result is NotImplemented:
            return result
        return not result

    def render(self, request):
        # Stuff we need to know for the mapper.
        try:
            url_scheme, server_name, server_port, path_info, script_name = \
                _extractURLparts(request)
        except _URLDecodeError as e:
            for what, fail in e.errors:
                log.err(fail, "Invalid encoding in {what}.".format(what=what))
            request.setResponseCode(400)
            return b"Non-UTF-8 encoding in URL."

        # Bind our mapper.
        mapper = self._app.url_map.bind(
            server_name,
            script_name,
            path_info=path_info,
            default_method=request.method,
            url_scheme=url_scheme,
        )
        # Make the mapper available to the view.
        kleinRequest = IKleinRequest(request)
        kleinRequest.mapper = mapper

        # Make sure we'll notice when the connection goes away unambiguously.
        request_finished = [False]

        def _finish(result):
            request_finished[0] = True

        def _execute():
            # Actually doing the match right here. This can cause an exception
            # to percolate up. If that happens it will be handled below in
            # processing_failed, either by a user-registered error handler or
            # one of our defaults.
            (rule, kwargs) = mapper.match(return_rule=True)
            endpoint = rule.endpoint

            # Try pretty hard to fix up prepath and postpath.
            segment_count = self._app.endpoints[endpoint].segment_count
            request.prepath.extend(request.postpath[:segment_count])
            request.postpath = request.postpath[segment_count:]

            request.notifyFinish().addBoth(_finish)

            # Standard Twisted Web stuff. Defer the method action, giving us
            # something renderable or printable. Return NOT_DONE_YET and set up
            # the incremental renderer.
            d = defer.maybeDeferred(self._app.execute_endpoint,
                                    endpoint,
                                    request,
                                    **kwargs)

            request.notifyFinish().addErrback(lambda _: d.cancel())

            return d

        d = defer.maybeDeferred(_execute)

        def write_response(r):
            if r is not _StandInResource:
                if isinstance(r, unicode):
                    r = r.encode('utf-8')

                if (r is not None) and (r != NOT_DONE_YET):
                    request.write(r)

                if not request_finished[0]:
                    request.finish()

        def process(r):
            """
            Recursively go through r and any child Resources until something
            returns an IRenderable, then render it and let the result of that
            bubble back up.
            """

            if IResource.providedBy(r):
                request.render(getChildForRequest(r, request))
                return _StandInResource

            if IRenderable.providedBy(r):
                renderElement(request, r)
                return _StandInResource

            return r

        d.addCallback(process)

        def processing_failed(failure, error_handlers):
            # The failure processor writes to the request.  If the
            # request is already finished we should suppress failure
            # processing.  We don't return failure here because there
            # is no way to surface this failure to the user if the
            # request is finished.
            if request_finished[0]:
                if not failure.check(defer.CancelledError):
                    log.err(failure, "Unhandled Error Processing Request.")
                return

            # If there are no more registered handlers, apply some defaults
            if len(error_handlers) == 0:
                if failure.check(HTTPException):
                    he = failure.value
                    request.setResponseCode(he.code)
                    resp = he.get_response({})

                    for header, value in resp.headers:
                        request.setHeader(ensure_utf8_bytes(header), ensure_utf8_bytes(value))

                    return ensure_utf8_bytes(he.get_body({}))
                else:
                    request.processingFailed(failure)
                    return

            error_handler = error_handlers[0]

            # Each error handler is a tuple of (list_of_exception_types, handler_fn)
            if failure.check(*error_handler[0]):
                d = defer.maybeDeferred(self._app.execute_error_handler,
                                        error_handler[1],
                                        request,
                                        failure)

                return d.addErrback(processing_failed, error_handlers[1:])

            return processing_failed(failure, error_handlers[1:])

        d.addErrback(processing_failed, self._app._error_handlers)
        d.addCallback(write_response).addErrback(log.err, _why="Unhandled Error writing response")
        return server.NOT_DONE_YET
<commit_msg>test case name<commit_after># -*- test-case-name: klein.test.test_resource -*-

from __future__ import absolute_import, division

from twisted.internet import defer
from twisted.python import log, failure
from twisted.python.compat import unicode, intToBytes
from twisted.web import server
from twisted.web.iweb import IRenderable
from twisted.web.resource import Resource, IResource, getChildForRequest
from twisted.web.server import NOT_DONE_YET
from twisted.web.template import renderElement

from werkzeug.exceptions import HTTPException

from klein.interfaces import IKleinRequest

__all__ = ["KleinResource", "ensure_utf8_bytes"]

def ensure_utf8_bytes(v):
    """
    Coerces a value which is either a C{unicode} or C{str} to a C{str}.
    If ``v`` is a C{unicode} object it is encoded as utf-8.
    """
    if isinstance(v, unicode):
        v = v.encode("utf-8")
    return v

class _StandInResource(object):
    """
    A standin for a Resource.

    This is a sentinel value for L{KleinResource}, to say that we are rendering
    a L{Resource}, which may close the connection itself later.
    """

class _URLDecodeError(Exception):
    """
    Raised if one or more string parts of the URL could not be decoded.
    """
    __slots__ = ["errors"]

    def __init__(self, errors):
        """
        @param errors: List of decoding errors.
        @type errors: L{list} of L{tuple} of L{str},
            L{twisted.python.failure.Failure}
        """
        self.errors = errors

    def __repr__(self):
        return "<URLDecodeError(errors={0!r})>".format(self.errors)

def _extractURLparts(request):
    """
    Extracts and decodes URI parts from C{request}.

    All strings must be UTF8-decodable.

    @param request: A Twisted Web request.
    @type request: L{twisted.web.iweb.IRequest}

    @raise URLDecodeError: If one of the parts could not be decoded as UTF-8.

    @return: L{tuple} of the URL scheme, the server name, the server port, the
        path info and the script name.
    @rtype: L{tuple} of L{unicode}, L{unicode}, L{int}, L{unicode}, L{unicode}
    """
    server_name = request.getRequestHostname()
    if hasattr(request.getHost(), 'port'):
        server_port = request.getHost().port
    else:
        server_port = 0
    if (bool(request.isSecure()), server_port) not in [
            (True, 443), (False, 80), (False, 0), (True, 0)]:
        server_name = server_name + b":" + intToBytes(server_port)

    script_name = b''
    if request.prepath:
        script_name = b'/'.join(request.prepath)

        if not script_name.startswith(b'/'):
            script_name = b'/' + script_name

    path_info = b''
    if request.postpath:
        path_info = b'/'.join(request.postpath)

        if not path_info.startswith(b'/'):
            path_info = b'/' + path_info

    url_scheme = u'https' if request.isSecure() else u'http'

    utf8Failures = []
    try:
        server_name = server_name.decode("utf-8")
    except UnicodeDecodeError:
        utf8Failures.append(("SERVER_NAME", failure.Failure()))
    try:
        path_info = path_info.decode("utf-8")
    except UnicodeDecodeError:
        utf8Failures.append(("PATH_INFO", failure.Failure()))
    try:
        script_name = script_name.decode("utf-8")
    except UnicodeDecodeError:
        utf8Failures.append(("SCRIPT_NAME", failure.Failure()))

    if utf8Failures:
        raise _URLDecodeError(utf8Failures)

    return url_scheme, server_name, server_port, path_info, script_name

class KleinResource(Resource):
    """
    A ``Resource`` that can do URL routing.
    """
    isLeaf = True

    def __init__(self, app):
        Resource.__init__(self)
        self._app = app

    def __eq__(self, other):
        if isinstance(other, KleinResource):
            return vars(self) == vars(other)
        return NotImplemented

    def __ne__(self, other):
        result = self.__eq__(other)
        if result is NotImplemented:
            return result
        return not result

    def render(self, request):
        # Stuff we need to know for the mapper.
        try:
            url_scheme, server_name, server_port, path_info, script_name = \
                _extractURLparts(request)
        except _URLDecodeError as e:
            for what, fail in e.errors:
                log.err(fail, "Invalid encoding in {what}.".format(what=what))
            request.setResponseCode(400)
            return b"Non-UTF-8 encoding in URL."

        # Bind our mapper.
        mapper = self._app.url_map.bind(
            server_name,
            script_name,
            path_info=path_info,
            default_method=request.method,
            url_scheme=url_scheme,
        )
        # Make the mapper available to the view.
        kleinRequest = IKleinRequest(request)
        kleinRequest.mapper = mapper

        # Make sure we'll notice when the connection goes away unambiguously.
        request_finished = [False]

        def _finish(result):
            request_finished[0] = True

        def _execute():
            # Actually doing the match right here. This can cause an exception
            # to percolate up. If that happens it will be handled below in
            # processing_failed, either by a user-registered error handler or
            # one of our defaults.
            (rule, kwargs) = mapper.match(return_rule=True)
            endpoint = rule.endpoint

            # Try pretty hard to fix up prepath and postpath.
            segment_count = self._app.endpoints[endpoint].segment_count
            request.prepath.extend(request.postpath[:segment_count])
            request.postpath = request.postpath[segment_count:]

            request.notifyFinish().addBoth(_finish)

            # Standard Twisted Web stuff. Defer the method action, giving us
            # something renderable or printable. Return NOT_DONE_YET and set up
            # the incremental renderer.
            d = defer.maybeDeferred(self._app.execute_endpoint,
                                    endpoint,
                                    request,
                                    **kwargs)

            request.notifyFinish().addErrback(lambda _: d.cancel())

            return d

        d = defer.maybeDeferred(_execute)

        def write_response(r):
            if r is not _StandInResource:
                if isinstance(r, unicode):
                    r = r.encode('utf-8')

                if (r is not None) and (r != NOT_DONE_YET):
                    request.write(r)

                if not request_finished[0]:
                    request.finish()

        def process(r):
            """
            Recursively go through r and any child Resources until something
            returns an IRenderable, then render it and let the result of that
            bubble back up.
            """

            if IResource.providedBy(r):
                request.render(getChildForRequest(r, request))
                return _StandInResource

            if IRenderable.providedBy(r):
                renderElement(request, r)
                return _StandInResource

            return r

        d.addCallback(process)

        def processing_failed(failure, error_handlers):
            # The failure processor writes to the request.  If the
            # request is already finished we should suppress failure
            # processing.  We don't return failure here because there
            # is no way to surface this failure to the user if the
            # request is finished.
            if request_finished[0]:
                if not failure.check(defer.CancelledError):
                    log.err(failure, "Unhandled Error Processing Request.")
                return

            # If there are no more registered handlers, apply some defaults
            if len(error_handlers) == 0:
                if failure.check(HTTPException):
                    he = failure.value
                    request.setResponseCode(he.code)
                    resp = he.get_response({})

                    for header, value in resp.headers:
                        request.setHeader(ensure_utf8_bytes(header), ensure_utf8_bytes(value))

                    return ensure_utf8_bytes(he.get_body({}))
                else:
                    request.processingFailed(failure)
                    return

            error_handler = error_handlers[0]

            # Each error handler is a tuple of (list_of_exception_types, handler_fn)
            if failure.check(*error_handler[0]):
                d = defer.maybeDeferred(self._app.execute_error_handler,
                                        error_handler[1],
                                        request,
                                        failure)

                return d.addErrback(processing_failed, error_handlers[1:])

            return processing_failed(failure, error_handlers[1:])

        d.addErrback(processing_failed, self._app._error_handlers)
        d.addCallback(write_response).addErrback(log.err, _why="Unhandled Error writing response")
        return server.NOT_DONE_YET
<|endoftext|>