<commit_before>#
#    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 functools
import logging
import os
import pkgutil
import re

from oslo_utils import strutils

import novaclient
from novaclient import exceptions
from novaclient.i18n import _, _LW
from novaclient import utils

LOG = logging.getLogger(__name__)
if not LOG.handlers:
    LOG.addHandler(logging.StreamHandler())

# key is a deprecated version and value is an alternative version.
DEPRECATED_VERSIONS = {"1.1": "2"}

_SUBSTITUTIONS = {}

_type_error_msg = _("'%(other)s' should be an instance of '%(cls)s'")

class APIVersion(object):
    """This class represents an API Version with convenience
    methods for manipulation and comparison of version
    numbers that we need to do to implement microversions.
    """

    def __init__(self, version_str=None):
        """Create an API version object."""
        self.ver_major = 0
        self.ver_minor = 0

        if version_str is not None:
            match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0|latest)$", version_str)
            if match:
                self.ver_major = int(match.group(1))
                if match.group(2) == "latest":
                    # NOTE(andreykurilin): Infinity allows to easily determine
                    # latest version and doesn't require any additional checks
                    # in comparison methods.
                    self.ver_minor = float("inf")
                else:
                    self.ver_minor = int(match.group(2))
            else:
                msg = _("Invalid format of client version '%s'. "
                        "Expected format 'X.Y', where X is a major part and Y "
                        "is a minor part of version.") % version_str
                raise exceptions.UnsupportedVersion(msg)

    def __str__(self):
        """Debug/Logging representation of object."""
        if self.is_latest():
            return "Latest API Version Major: %s" % self.ver_major
        return ("API Version Major: %s, Minor: %s"
                % (self.ver_major, self.ver_minor))

    def __repr__(self):
        if self.is_null():
            return "<APIVersion: null>"
        else:
            return "<APIVersion: %s>" % self.get_string()

    def is_null(self):
        return self.ver_major == 0 and self.ver_minor == 0

    def is_latest(self):
        return self.ver_minor == float("inf")

    def __lt__(self, other):
        if not isinstance(other, APIVersion):
            raise TypeError(_type_error_msg % {"other": other,
                                               "cls": self.__class__})

        return ((self.ver_major, self.ver_minor) <
                (other.ver_major, other.ver_minor))

    def __eq__(self, other):
        if not isinstance(other, APIVersion):
            raise TypeError(_type_error_msg % {"other": other,
                                               "cls": self.__class__})

        return ((self.ver_major, self.ver_minor) ==
                (other.ver_major, other.ver_minor))

    def __gt__(self, other):
        if not isinstance(other, APIVersion):
            raise TypeError(_type_error_msg % {"other": other,
                                               "cls": self.__class__})

        return ((self.ver_major, self.ver_minor) >
                (other.ver_major, other.ver_minor))

    def __le__(self, other):
        return self < other or self == other

    def __ne__(self, other):
        return not self.__eq__(other)

    def __ge__(self, other):
        return self > other or self == other

    def matches(self, min_version, max_version):
        """Returns whether the version object represents a version
        greater than or equal to the minimum version and less than
        or equal to the maximum version.

        :param min_version: Minimum acceptable version.
        :param max_version: Maximum acceptable version.
        :returns: boolean

        If min_version is null then there is no minimum limit.
        If max_version is null then there is no maximum limit.
        If self is null then raise ValueError
        """

        if self.is_null():
            raise ValueError(_("Null APIVersion doesn't support 'matches'."))
        if max_version.is_null() and min_version.is_null():
            return True
        elif max_version.is_null():
            return min_version <= self
        elif min_version.is_null():
            return self <= max_version
        else:
            return min_version <= self <= max_version

    def get_string(self):
        """Converts object to string representation which if used to create
        an APIVersion object results in the same version.
        """
        if self.is_null():
            raise ValueError(
                _("Null APIVersion cannot be converted to string."))
        elif self.is_latest():
            return "%s.%s" % (self.ver_major, "latest")
        return "%s.%s" % (self.ver_major, self.ver_minor)

class VersionedMethod(object):

    def __init__(self, name, start_version, end_version, func):
        """Versioning information for a single method

        :param name: Name of the method
        :param start_version: Minimum acceptable version
        :param end_version: Maximum acceptable_version
        :param func: Method to call

        Minimum and maximums are inclusive
        """
        self.name = name
        self.start_version = start_version
        self.end_version = end_version
        self.func = func

    def __str__(self):
        return ("Version Method %s: min: %s, max: %s"
                % (self.name, self.start_version, self.end_version))

    def __repr__(self):
        return "<VersionedMethod %s>" % self.name

def get_available_major_versions():
    # NOTE(andreykurilin): available clients version should not be
    # hardcoded, so let's discover them.
    matcher = re.compile(r"v[0-9]*$")
    submodules = pkgutil.iter_modules([os.path.dirname(__file__)])
    available_versions = [name[1:] for loader, name, ispkg in submodules
                          if matcher.search(name)]

    return available_versions

def check_major_version(api_version):
    """Checks major part of ``APIVersion`` obj is supported.

    :raises novaclient.exceptions.UnsupportedVersion: if major part is not
                                                      supported
    """
    available_versions = get_available_major_versions()
    if (not api_version.is_null() and
            str(api_version.ver_major) not in available_versions):
        if len(available_versions) == 1:
            msg = _("Invalid client version '%(version)s'. "
                    "Major part should be '%(major)s'") % {
                "version": api_version.get_string(),
                "major": available_versions[0]}
        else:
            msg = _("Invalid client version '%(version)s'. "
                    "Major part must be one of: '%(major)s'") % {
                "version": api_version.get_string(),
                "major": ", ".join(available_versions)}
        raise exceptions.UnsupportedVersion(msg)

def get_api_version(version_string):
    """Returns checked APIVersion object"""
    version_string = str(version_string)
    if version_string in DEPRECATED_VERSIONS:
        LOG.warning(
            _LW("Version %(deprecated_version)s is deprecated, using "
                "alternative version %(alternative)s instead.") %
            {"deprecated_version": version_string,
             "alternative": DEPRECATED_VERSIONS[version_string]})
        version_string = DEPRECATED_VERSIONS[version_string]
    if strutils.is_int_like(version_string):
        version_string = "%s.0" % version_string

    api_version = APIVersion(version_string)
    check_major_version(api_version)
    return api_version

def _get_server_version_range(client):
    version = client.versions.get_current()

    if not hasattr(version, 'version') or not version.version:
        return APIVersion(), APIVersion()

    return APIVersion(version.min_version), APIVersion(version.version)

def discover_version(client, requested_version):
    """Returns latest version supported by both API and client.

    :param client: client object
    :returns: APIVersion
    """

    server_start_version, server_end_version = _get_server_version_range(
        client)

    if (not requested_version.is_latest() and
            requested_version != APIVersion('2.0')):
        if server_start_version.is_null() and server_end_version.is_null():
            raise exceptions.UnsupportedVersion(
                _("Server doesn't support microversions"))
        if not requested_version.matches(server_start_version,
                                         server_end_version):
            raise exceptions.UnsupportedVersion(
                _("The specified version isn't supported by server. The valid "
                  "version range is '%(min)s' to '%(max)s'") % {
                    "min": server_start_version.get_string(),
                    "max": server_end_version.get_string()})
        return requested_version

    if requested_version == APIVersion('2.0'):
        if (server_start_version == APIVersion('2.1') or
                (server_start_version.is_null() and
                 server_end_version.is_null())):
            return APIVersion('2.0')
        else:
            raise exceptions.UnsupportedVersion(
                _("The server isn't backward compatible with Nova V2 REST "
                  "API"))

    if server_start_version.is_null() and server_end_version.is_null():
        return APIVersion('2.0')
    elif novaclient.API_MIN_VERSION > server_end_version:
        raise exceptions.UnsupportedVersion(
            _("Server version is too old. The client valid version range is "
              "'%(client_min)s' to '%(client_max)s'. The server valid version "
              "range is '%(server_min)s' to '%(server_max)s'.") % {
                  'client_min': novaclient.API_MIN_VERSION.get_string(),
                  'client_max': novaclient.API_MAX_VERSION.get_string(),
                  'server_min': server_start_version.get_string(),
                  'server_max': server_end_version.get_string()})
    elif novaclient.API_MAX_VERSION < server_start_version:
        raise exceptions.UnsupportedVersion(
            _("Server version is too new. The client valid version range is "
              "'%(client_min)s' to '%(client_max)s'. The server valid version "
              "range is '%(server_min)s' to '%(server_max)s'.") % {
                  'client_min': novaclient.API_MIN_VERSION.get_string(),
                  'client_max': novaclient.API_MAX_VERSION.get_string(),
                  'server_min': server_start_version.get_string(),
                  'server_max': server_end_version.get_string()})
    elif novaclient.API_MAX_VERSION <= server_end_version:
        return novaclient.API_MAX_VERSION
    elif server_end_version < novaclient.API_MAX_VERSION:
        return server_end_version

def update_headers(headers, api_version):
    """Set 'X-OpenStack-Nova-API-Version' header if api_version is not null"""

    if not api_version.is_null() and api_version.ver_minor != 0:
        headers["X-OpenStack-Nova-API-Version"] = api_version.get_string()

def add_substitution(versioned_method):
    _SUBSTITUTIONS.setdefault(versioned_method.name, [])
    _SUBSTITUTIONS[versioned_method.name].append(versioned_method)

def get_substitutions(func_name, api_version=None):
    substitutions = _SUBSTITUTIONS.get(func_name, [])
    if api_version and not api_version.is_null():
        return [m for m in substitutions
                if api_version.matches(m.start_version, m.end_version)]
    return substitutions

def wraps(start_version, end_version=None):
    start_version = APIVersion(start_version)
    if end_version:
        end_version = APIVersion(end_version)
    else:
        end_version = APIVersion("%s.latest" % start_version.ver_major)

    def decor(func):
        func.versioned = True
        name = utils.get_function_name(func)
        versioned_method = VersionedMethod(name, start_version,
                                           end_version, func)
        add_substitution(versioned_method)

        @functools.wraps(func)
        def substitution(obj, *args, **kwargs):
            methods = get_substitutions(name, obj.api_version)

            if not methods:
                raise exceptions.VersionNotFoundForAPIMethod(
                    obj.api_version.get_string(), name)
            else:
                return max(methods, key=lambda f: f.start_version).func(
                    obj, *args, **kwargs)
        return substitution
    return decor
<commit_msg>Change docstring of api_versions.discover_version<commit_after>#
#    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 functools
import logging
import os
import pkgutil
import re

from oslo_utils import strutils

import novaclient
from novaclient import exceptions
from novaclient.i18n import _, _LW
from novaclient import utils

LOG = logging.getLogger(__name__)
if not LOG.handlers:
    LOG.addHandler(logging.StreamHandler())

# key is a deprecated version and value is an alternative version.
DEPRECATED_VERSIONS = {"1.1": "2"}

_SUBSTITUTIONS = {}

_type_error_msg = _("'%(other)s' should be an instance of '%(cls)s'")

class APIVersion(object):
    """This class represents an API Version with convenience
    methods for manipulation and comparison of version
    numbers that we need to do to implement microversions.
    """

    def __init__(self, version_str=None):
        """Create an API version object."""
        self.ver_major = 0
        self.ver_minor = 0

        if version_str is not None:
            match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0|latest)$", version_str)
            if match:
                self.ver_major = int(match.group(1))
                if match.group(2) == "latest":
                    # NOTE(andreykurilin): Infinity allows to easily determine
                    # latest version and doesn't require any additional checks
                    # in comparison methods.
                    self.ver_minor = float("inf")
                else:
                    self.ver_minor = int(match.group(2))
            else:
                msg = _("Invalid format of client version '%s'. "
                        "Expected format 'X.Y', where X is a major part and Y "
                        "is a minor part of version.") % version_str
                raise exceptions.UnsupportedVersion(msg)

    def __str__(self):
        """Debug/Logging representation of object."""
        if self.is_latest():
            return "Latest API Version Major: %s" % self.ver_major
        return ("API Version Major: %s, Minor: %s"
                % (self.ver_major, self.ver_minor))

    def __repr__(self):
        if self.is_null():
            return "<APIVersion: null>"
        else:
            return "<APIVersion: %s>" % self.get_string()

    def is_null(self):
        return self.ver_major == 0 and self.ver_minor == 0

    def is_latest(self):
        return self.ver_minor == float("inf")

    def __lt__(self, other):
        if not isinstance(other, APIVersion):
            raise TypeError(_type_error_msg % {"other": other,
                                               "cls": self.__class__})

        return ((self.ver_major, self.ver_minor) <
                (other.ver_major, other.ver_minor))

    def __eq__(self, other):
        if not isinstance(other, APIVersion):
            raise TypeError(_type_error_msg % {"other": other,
                                               "cls": self.__class__})

        return ((self.ver_major, self.ver_minor) ==
                (other.ver_major, other.ver_minor))

    def __gt__(self, other):
        if not isinstance(other, APIVersion):
            raise TypeError(_type_error_msg % {"other": other,
                                               "cls": self.__class__})

        return ((self.ver_major, self.ver_minor) >
                (other.ver_major, other.ver_minor))

    def __le__(self, other):
        return self < other or self == other

    def __ne__(self, other):
        return not self.__eq__(other)

    def __ge__(self, other):
        return self > other or self == other

    def matches(self, min_version, max_version):
        """Returns whether the version object represents a version
        greater than or equal to the minimum version and less than
        or equal to the maximum version.

        :param min_version: Minimum acceptable version.
        :param max_version: Maximum acceptable version.
        :returns: boolean

        If min_version is null then there is no minimum limit.
        If max_version is null then there is no maximum limit.
        If self is null then raise ValueError
        """

        if self.is_null():
            raise ValueError(_("Null APIVersion doesn't support 'matches'."))
        if max_version.is_null() and min_version.is_null():
            return True
        elif max_version.is_null():
            return min_version <= self
        elif min_version.is_null():
            return self <= max_version
        else:
            return min_version <= self <= max_version

    def get_string(self):
        """Converts object to string representation which if used to create
        an APIVersion object results in the same version.
        """
        if self.is_null():
            raise ValueError(
                _("Null APIVersion cannot be converted to string."))
        elif self.is_latest():
            return "%s.%s" % (self.ver_major, "latest")
        return "%s.%s" % (self.ver_major, self.ver_minor)

class VersionedMethod(object):

    def __init__(self, name, start_version, end_version, func):
        """Versioning information for a single method

        :param name: Name of the method
        :param start_version: Minimum acceptable version
        :param end_version: Maximum acceptable_version
        :param func: Method to call

        Minimum and maximums are inclusive
        """
        self.name = name
        self.start_version = start_version
        self.end_version = end_version
        self.func = func

    def __str__(self):
        return ("Version Method %s: min: %s, max: %s"
                % (self.name, self.start_version, self.end_version))

    def __repr__(self):
        return "<VersionedMethod %s>" % self.name

def get_available_major_versions():
    # NOTE(andreykurilin): available clients version should not be
    # hardcoded, so let's discover them.
    matcher = re.compile(r"v[0-9]*$")
    submodules = pkgutil.iter_modules([os.path.dirname(__file__)])
    available_versions = [name[1:] for loader, name, ispkg in submodules
                          if matcher.search(name)]

    return available_versions

def check_major_version(api_version):
    """Checks major part of ``APIVersion`` obj is supported.

    :raises novaclient.exceptions.UnsupportedVersion: if major part is not
                                                      supported
    """
    available_versions = get_available_major_versions()
    if (not api_version.is_null() and
            str(api_version.ver_major) not in available_versions):
        if len(available_versions) == 1:
            msg = _("Invalid client version '%(version)s'. "
                    "Major part should be '%(major)s'") % {
                "version": api_version.get_string(),
                "major": available_versions[0]}
        else:
            msg = _("Invalid client version '%(version)s'. "
                    "Major part must be one of: '%(major)s'") % {
                "version": api_version.get_string(),
                "major": ", ".join(available_versions)}
        raise exceptions.UnsupportedVersion(msg)

def get_api_version(version_string):
    """Returns checked APIVersion object"""
    version_string = str(version_string)
    if version_string in DEPRECATED_VERSIONS:
        LOG.warning(
            _LW("Version %(deprecated_version)s is deprecated, using "
                "alternative version %(alternative)s instead.") %
            {"deprecated_version": version_string,
             "alternative": DEPRECATED_VERSIONS[version_string]})
        version_string = DEPRECATED_VERSIONS[version_string]
    if strutils.is_int_like(version_string):
        version_string = "%s.0" % version_string

    api_version = APIVersion(version_string)
    check_major_version(api_version)
    return api_version

def _get_server_version_range(client):
    version = client.versions.get_current()

    if not hasattr(version, 'version') or not version.version:
        return APIVersion(), APIVersion()

    return APIVersion(version.min_version), APIVersion(version.version)

def discover_version(client, requested_version):
    """Checks ``requested_version`` and returns the most recent version
    supported by both the API and the client.

    :param client: client object
    :param requested_version: requested version represented by APIVersion obj
    :returns: APIVersion
    """

    server_start_version, server_end_version = _get_server_version_range(
        client)

    if (not requested_version.is_latest() and
            requested_version != APIVersion('2.0')):
        if server_start_version.is_null() and server_end_version.is_null():
            raise exceptions.UnsupportedVersion(
                _("Server doesn't support microversions"))
        if not requested_version.matches(server_start_version,
                                         server_end_version):
            raise exceptions.UnsupportedVersion(
                _("The specified version isn't supported by server. The valid "
                  "version range is '%(min)s' to '%(max)s'") % {
                    "min": server_start_version.get_string(),
                    "max": server_end_version.get_string()})
        return requested_version

    if requested_version == APIVersion('2.0'):
        if (server_start_version == APIVersion('2.1') or
                (server_start_version.is_null() and
                 server_end_version.is_null())):
            return APIVersion('2.0')
        else:
            raise exceptions.UnsupportedVersion(
                _("The server isn't backward compatible with Nova V2 REST "
                  "API"))

    if server_start_version.is_null() and server_end_version.is_null():
        return APIVersion('2.0')
    elif novaclient.API_MIN_VERSION > server_end_version:
        raise exceptions.UnsupportedVersion(
            _("Server version is too old. The client valid version range is "
              "'%(client_min)s' to '%(client_max)s'. The server valid version "
              "range is '%(server_min)s' to '%(server_max)s'.") % {
                  'client_min': novaclient.API_MIN_VERSION.get_string(),
                  'client_max': novaclient.API_MAX_VERSION.get_string(),
                  'server_min': server_start_version.get_string(),
                  'server_max': server_end_version.get_string()})
    elif novaclient.API_MAX_VERSION < server_start_version:
        raise exceptions.UnsupportedVersion(
            _("Server version is too new. The client valid version range is "
              "'%(client_min)s' to '%(client_max)s'. The server valid version "
              "range is '%(server_min)s' to '%(server_max)s'.") % {
                  'client_min': novaclient.API_MIN_VERSION.get_string(),
                  'client_max': novaclient.API_MAX_VERSION.get_string(),
                  'server_min': server_start_version.get_string(),
                  'server_max': server_end_version.get_string()})
    elif novaclient.API_MAX_VERSION <= server_end_version:
        return novaclient.API_MAX_VERSION
    elif server_end_version < novaclient.API_MAX_VERSION:
        return server_end_version

def update_headers(headers, api_version):
    """Set 'X-OpenStack-Nova-API-Version' header if api_version is not null"""

    if not api_version.is_null() and api_version.ver_minor != 0:
        headers["X-OpenStack-Nova-API-Version"] = api_version.get_string()

def add_substitution(versioned_method):
    _SUBSTITUTIONS.setdefault(versioned_method.name, [])
    _SUBSTITUTIONS[versioned_method.name].append(versioned_method)

def get_substitutions(func_name, api_version=None):
    substitutions = _SUBSTITUTIONS.get(func_name, [])
    if api_version and not api_version.is_null():
        return [m for m in substitutions
                if api_version.matches(m.start_version, m.end_version)]
    return substitutions

def wraps(start_version, end_version=None):
    start_version = APIVersion(start_version)
    if end_version:
        end_version = APIVersion(end_version)
    else:
        end_version = APIVersion("%s.latest" % start_version.ver_major)

    def decor(func):
        func.versioned = True
        name = utils.get_function_name(func)
        versioned_method = VersionedMethod(name, start_version,
                                           end_version, func)
        add_substitution(versioned_method)

        @functools.wraps(func)
        def substitution(obj, *args, **kwargs):
            methods = get_substitutions(name, obj.api_version)

            if not methods:
                raise exceptions.VersionNotFoundForAPIMethod(
                    obj.api_version.get_string(), name)
            else:
                return max(methods, key=lambda f: f.start_version).func(
                    obj, *args, **kwargs)
        return substitution
    return decor
<|endoftext|>


<commit_before>"""Monitoring utilities."""

import json
import logging
import operator
import os
import uuid

import raven
from raven.handlers.logging import SentryHandler

from .state import get_secret

from .kinesis import (unpack_kinesis_event, send_to_kinesis_stream,
                      send_to_delivery_stream)
from .exception import CriticalError, ProcessingError, OutOfOrderError

# Sentry logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.WARNING)

# The AWS Lambda logger
rlogger = logging.getLogger()
rlogger.setLevel(logging.INFO)

def _sentry_context_dict(context):
    """Create a dict with context information for Sentry."""
    d = {
        "function_name": context.function_name,
        "function_version": context.function_version,
        "invoked_function_arn": context.invoked_function_arn,
        "memory_limit_in_mb": context.memory_limit_in_mb,
        "aws_request_id": context.aws_request_id,
        "log_group_name": context.log_group_name,
        "cognito_identity_id": context.identity.cognito_identity_id,
        "cognito_identity_pool_id": context.identity.cognito_identity_pool_id}
    for k, v in os.environ.items():
        if k not in {"AWS_SECURITY_TOKEN", "AWS_SESSION_TOKEN",
                     "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"}:
            # Do not log credentials
            d[k] = v

    return d

def sentry_monitor(error_stream=None, **kwargs):
    """Sentry monitoring for AWS Lambda handler."""
    def decorator(func):
        """A decorator that adds Sentry monitoring to a Lambda handler."""
        def wrapper(event, context):
            """Wrap the target function."""
            client = _setup_sentry_client(context)
            try:
                return func(event, context)
            except CriticalError:
                # Raise the exception and block the stream processor
                logger.error("Caught a blocking exception", exc_info=True)
                if client:
                    client.captureException()
                raise
            except ProcessingError as err:
                # A controlled exception from the Kinesis processor
                _handle_processing_error(err, error_stream, client)
            except Exception as err:
                # An uncontrolled (by default non-critical) exception
                recs = _get_records(event)
                _handle_non_critical_exception(
                    err, error_stream, recs, client)
        return wrapper

    return decorator

def _setup_sentry_client(context):
    """Produce and configure the sentry client."""

    dsn = get_secret("sentry.dsn")
    try:
        client = raven.Client(dsn)
        handler = SentryHandler(client)
        logger.addHandler(handler)
        client.user_context(_sentry_context_dict(context))
        return client
    except:
        logger.error("Raven client error", exc_info=True)
        return None

def _handle_processing_error(err, errstream, client):
    """Handle ProcessingError exceptions."""

    errors = sorted(err.events, key=operator.attrgetter("index"))
    failed = [e.event for e in errors]
    silent = all(isinstance(e.error, OutOfOrderError) for e in errors)
    _handle_non_critical_exception(err, errstream, failed, client, silent)
    for _, event, error, tb in errors:
        if isinstance(error, OutOfOrderError):
            # Not really an error: do not log this to Sentry
            continue
        try:
            raise error
        except type(error) as catched_error:
            msg = "{}: {}".format(catched_error.message,
                                  json.dumps(event, indent=4))
            logger.error(msg, exc_info=(type(error), error.args or None, tb))

def _handle_non_critical_exception(err, errstream, recs, client, silent=False):
    """Deliver errors to error stream."""
    try:
        if silent:
            rlogger.error("AWS Lambda exception", exc_info=True)
        else:
            logger.error("AWS Lambda exception", exc_info=True)
        rlogger.info("Going to handle %s failed events", len(recs))
        if recs:
            rlogger.info(
                "First failed event: %s", json.dumps(recs[0], indent=4))
        errevents = _make_error_events(err, recs)

        kinesis_stream = errstream.get("kinesis_stream")
        randomkey = str(uuid.uuid4())
        if kinesis_stream:
            send_to_kinesis_stream(
                errevents,
                kinesis_stream,
                partition_key=errstream.get("partition_key", randomkey))
            rlogger.info("Sent errors to Kinesis stream '%s'", errstream)

        delivery_stream = errstream.get("firehose_delivery_stream")
        if delivery_stream:
            send_to_delivery_stream(errevents, delivery_stream)
            rlogger.info("Sent error payload to Firehose delivery stream '%s'",
                         delivery_stream)

        if not kinesis_stream and not delivery_stream:
            # Promote to Critical exception
            raise err
    except:
        if client:
            client.captureException()
        raise

def _get_records(event):
    """Get records from an AWS Lambda trigger event."""
    try:
        recs, _ = unpack_kinesis_event(event, deserializer=None)
    except KeyError:
        # If not a Kinesis event, just unpack the records
        recs = event["Records"]
    return recs

def _make_error_events(err, recs):
    """Make error events."""
    return [{
        "message_id": str(uuid.uuid4()),
        "schema_version": "1.0.0",
        "type": "error",
        "channel": "polku",
        "message": getattr(err, "message", None),
        "payload": rec} for rec in recs]
<commit_msg>Fix Error payload<commit_after>"""Monitoring utilities."""

import json
import logging
import operator
import os
import uuid

import raven
from raven.handlers.logging import SentryHandler

from .state import get_secret

from .kinesis import (unpack_kinesis_event, send_to_kinesis_stream,
                      send_to_delivery_stream)
from .exception import CriticalError, ProcessingError, OutOfOrderError

# Sentry logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.WARNING)

# The AWS Lambda logger
rlogger = logging.getLogger()
rlogger.setLevel(logging.INFO)

def _sentry_context_dict(context):
    """Create a dict with context information for Sentry."""
    d = {
        "function_name": context.function_name,
        "function_version": context.function_version,
        "invoked_function_arn": context.invoked_function_arn,
        "memory_limit_in_mb": context.memory_limit_in_mb,
        "aws_request_id": context.aws_request_id,
        "log_group_name": context.log_group_name,
        "cognito_identity_id": context.identity.cognito_identity_id,
        "cognito_identity_pool_id": context.identity.cognito_identity_pool_id}
    for k, v in os.environ.items():
        if k not in {"AWS_SECURITY_TOKEN", "AWS_SESSION_TOKEN",
                     "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"}:
            # Do not log credentials
            d[k] = v

    return d

def sentry_monitor(error_stream=None, **kwargs):
    """Sentry monitoring for AWS Lambda handler."""
    def decorator(func):
        """A decorator that adds Sentry monitoring to a Lambda handler."""
        def wrapper(event, context):
            """Wrap the target function."""
            client = _setup_sentry_client(context)
            try:
                return func(event, context)
            except CriticalError:
                # Raise the exception and block the stream processor
                logger.error("Caught a blocking exception", exc_info=True)
                if client:
                    client.captureException()
                raise
            except ProcessingError as err:
                # A controlled exception from the Kinesis processor
                _handle_processing_error(err, error_stream, client)
            except Exception as err:
                # An uncontrolled (by default non-critical) exception
                recs = _get_records(event)
                _handle_non_critical_exception(
                    err, error_stream, recs, client)
        return wrapper

    return decorator

def _setup_sentry_client(context):
    """Produce and configure the sentry client."""

    dsn = get_secret("sentry.dsn")
    try:
        client = raven.Client(dsn)
        handler = SentryHandler(client)
        logger.addHandler(handler)
        client.user_context(_sentry_context_dict(context))
        return client
    except:
        logger.error("Raven client error", exc_info=True)
        return None

def _handle_processing_error(err, errstream, client):
    """Handle ProcessingError exceptions."""

    errors = sorted(err.events, key=operator.attrgetter("index"))
    failed = [e.event for e in errors]
    silent = all(isinstance(e.error, OutOfOrderError) for e in errors)
    _handle_non_critical_exception(err, errstream, failed, client, silent)
    for _, event, error, tb in errors:
        if isinstance(error, OutOfOrderError):
            # Not really an error: do not log this to Sentry
            continue
        try:
            raise error
        except type(error) as catched_error:
            msg = "{}: {}".format(catched_error.message,
                                  json.dumps(event, indent=4))
            logger.error(msg, exc_info=(type(error), error.args or None, tb))

def _handle_non_critical_exception(err, errstream, recs, client, silent=False):
    """Deliver errors to error stream."""
    try:
        if silent:
            rlogger.error("AWS Lambda exception", exc_info=True)
        else:
            logger.error("AWS Lambda exception", exc_info=True)
        rlogger.info("Going to handle %s failed events", len(recs))
        if recs:
            rlogger.info(
                "First failed event: %s", json.dumps(recs[0], indent=4))
        errevents = _make_error_events(err, recs)

        kinesis_stream = errstream.get("kinesis_stream")
        randomkey = str(uuid.uuid4())
        if kinesis_stream:
            send_to_kinesis_stream(
                errevents,
                kinesis_stream,
                partition_key=errstream.get("partition_key", randomkey))
            rlogger.info("Sent errors to Kinesis stream '%s'", errstream)

        delivery_stream = errstream.get("firehose_delivery_stream")
        if delivery_stream:
            send_to_delivery_stream(errevents, delivery_stream)
            rlogger.info("Sent error payload to Firehose delivery stream '%s'",
                         delivery_stream)

        if not kinesis_stream and not delivery_stream:
            # Promote to Critical exception
            raise err
    except:
        if client:
            client.captureException()
        raise

def _get_records(event):
    """Get records from an AWS Lambda trigger event."""
    try:
        recs, _ = unpack_kinesis_event(event, deserializer=None)
    except KeyError:
        # If not a Kinesis event, just unpack the records
        recs = event["Records"]
    return recs

def _make_error_events(err, recs):
    """Make error events."""
    return [{
        "message_id": str(uuid.uuid4()),
        "schema_version": "1.0.0",
        "type": "error",
        "channel": "polku",
        "payload": rec} for rec in recs]
<|endoftext|>


<commit_before>from vj4 import app
from vj4.model import builtin
from vj4.model import domain
from vj4.model.adaptor import discussion
from vj4.handler import base

@app.route('/', 'domain_main')
class DomainMainHandler(base.Handler):
  async def get(self):
    self.render('domain_main.html', discussion_nodes=await discussion.get_nodes(self.domain_id))

@app.route('/manage', 'domain_manage')
class DomainMainHandler(base.Handler):
  async def get(self):
    self.render('domain_manage.html')

@app.route('/domain/edit', 'domain_edit')
class DomainEditHandler(base.Handler):
  @base.require_perm(builtin.PERM_EDIT_DESCRIPTION)
  async def get(self):
    self.render('domain_edit.html',
                path_components=[(self.domain_id, self.reverse_url('main')),
                                 (self.translate('domain_edit'), None)])

  @base.require_perm(builtin.PERM_EDIT_DESCRIPTION)
  @base.post_argument
  @base.require_csrf_token
  @base.sanitize
  async def post(self, *, name: str, gravatar: str):
    ddoc = await domain.edit(self.domain_id, name=name, gravatar=gravatar)
    if ddoc:
      self.domain = ddoc
    self.render('domain_edit.html',
                path_components=[(self.domain_id, self.reverse_url('main')),
                                 (self.translate('domain_edit'), None)])

@app.route('/domain/user', 'domain_user')
class DomainUserHandler(base.Handler):
  async def get(self):
    self.render('domain_user.html')

@app.route('/domain/permission', 'domain_permission')
class DomainPermissionHandler(base.Handler):
  async def get(self):
    self.render('domain_permission.html')

@app.route('/domain/role', 'domain_role')
class DomainRoleHandler(base.OperationHandler):
  async def get(self):
    rudocs = dict((role, []) for role in self.domain['roles'])
    uddocs = await domain.get_list_users_by_role(self.domain_id, {'$gt': ''}, {'uid': 1, 'role': 1})
    for uddoc in uddocs:
      if uddoc['role'] in rudocs:
        rudocs[uddoc['role']].append(uddoc)
    self.render('domain_role.html', rudocs=rudocs,
                path_components=[(self.domain_id, self.reverse_url('main')),
                                 (self.translate('domain_role'), None)])

  @base.require_perm(builtin.PERM_EDIT_PERM)
  @base.require_csrf_token
  @base.sanitize
  async def post_set(self, *, role: str, perm: int):
    await domain.set_role(self.domain_id, role, perm)
    self.json_or_redirect(self.referer_or_main)

  @base.require_perm(builtin.PERM_EDIT_PERM)
  @base.require_csrf_token
  @base.sanitize
  async def post_delete(self, *, role: str, perm: int=None):
    await domain.delete_role(self.domain_id, role)
    self.json_or_redirect(self.referer_or_main)

  @base.require_perm(builtin.PERM_EDIT_PERM)
  @base.require_csrf_token
  @base.sanitize
  async def post_set_user(self, *, uid: int, role: str):
    await domain.set_user_role(self.domain_id, uid, role)
    self.json_or_redirect(self.referer_or_main)

  @base.require_perm(builtin.PERM_EDIT_PERM)
  @base.require_csrf_token
  @base.sanitize
  async def post_unset_user(self, *, uid: int):
    await domain.unset_user_role(self.domain_id, uid)
    self.json_or_redirect(self.referer_or_main)
<commit_msg>temporary fix for domain_role<commit_after>import collections

from vj4 import app
from vj4.model import builtin
from vj4.model import domain
from vj4.model.adaptor import discussion
from vj4.handler import base

@app.route('/', 'domain_main')
class DomainMainHandler(base.Handler):
  async def get(self):
    self.render('domain_main.html', discussion_nodes=await discussion.get_nodes(self.domain_id))

@app.route('/manage', 'domain_manage')
class DomainMainHandler(base.Handler):
  async def get(self):
    self.render('domain_manage.html')

@app.route('/domain/edit', 'domain_edit')
class DomainEditHandler(base.Handler):
  @base.require_perm(builtin.PERM_EDIT_DESCRIPTION)
  async def get(self):
    self.render('domain_edit.html',
                path_components=[(self.domain_id, self.reverse_url('main')),
                                 (self.translate('domain_edit'), None)])

  @base.require_perm(builtin.PERM_EDIT_DESCRIPTION)
  @base.post_argument
  @base.require_csrf_token
  @base.sanitize
  async def post(self, *, name: str, gravatar: str):
    ddoc = await domain.edit(self.domain_id, name=name, gravatar=gravatar)
    if ddoc:
      self.domain = ddoc
    self.render('domain_edit.html',
                path_components=[(self.domain_id, self.reverse_url('main')),
                                 (self.translate('domain_edit'), None)])

@app.route('/domain/user', 'domain_user')
class DomainUserHandler(base.Handler):
  async def get(self):
    self.render('domain_user.html')

@app.route('/domain/permission', 'domain_permission')
class DomainPermissionHandler(base.Handler):
  async def get(self):
    self.render('domain_permission.html')

@app.route('/domain/role', 'domain_role')
class DomainRoleHandler(base.OperationHandler):
  async def get(self):
    rudocs = collections.defaultdict(list)
    async for uddoc in domain.get_multi_user(domain_id=self.domain_id,
                                             fields={'uid': 1, 'role': 1}):
      if 'role' in uddoc:
        rudocs[uddoc['role']].append(uddoc)
    self.render('domain_role.html', rudocs=rudocs)

  @base.require_perm(builtin.PERM_EDIT_PERM)
  @base.require_csrf_token
  @base.sanitize
  async def post_set(self, *, role: str, perm: int):
    await domain.set_role(self.domain_id, role, perm)
    self.json_or_redirect(self.referer_or_main)

  @base.require_perm(builtin.PERM_EDIT_PERM)
  @base.require_csrf_token
  @base.sanitize
  async def post_delete(self, *, role: str, perm: int=None):
    await domain.delete_role(self.domain_id, role)
    self.json_or_redirect(self.referer_or_main)

  @base.require_perm(builtin.PERM_EDIT_PERM)
  @base.require_csrf_token
  @base.sanitize
  async def post_set_user(self, *, uid: int, role: str):
    await domain.set_user_role(self.domain_id, uid, role)
    self.json_or_redirect(self.referer_or_main)

  @base.require_perm(builtin.PERM_EDIT_PERM)
  @base.require_csrf_token
  @base.sanitize
  async def post_unset_user(self, *, uid: int):
    await domain.unset_user_role(self.domain_id, uid)
    self.json_or_redirect(self.referer_or_main)
<|endoftext|>


<commit_before>#! /usr/bin/env python
"""Create landlab model grids."""
import inspect

from warnings import warn

from landlab.core import model_parameter_dictionary as mpd
from landlab.core import load_params
from landlab.io import read_esri_ascii
from landlab.io.netcdf import read_netcdf
from landlab.values import constant, plane, random, sine

from .hex import HexModelGrid, from_dict as hex_from_dict
from .network import NetworkModelGrid
from .radial import RadialModelGrid
from .raster import RasterModelGrid, from_dict as raster_from_dict
from .voronoi import VoronoiDelaunayGrid

_MODEL_GRIDS = {
    "RasterModelGrid": RasterModelGrid,
    "HexModelGrid": HexModelGrid,
    "VoronoiDelaunayGrid": VoronoiDelaunayGrid,
    "NetworkModelGrid": NetworkModelGrid,
    "RadialModelGrid": RadialModelGrid,
}

_SYNTHETIC_FIELD_CONSTRUCTORS = {
    "plane": plane,
    "random": random,
    "sine": sine,
    "constant": constant,
}

_READ_FROM_FILE = {
    "read_netcdf": read_netcdf,
    "read_esri_ascii": read_esri_ascii,
}

class Error(Exception):

    """Base class for exceptions from this module."""

    pass

class BadGridTypeError(Error):

    """Raise this error for a bad grid type."""

    def __init__(self, grid_type):
        self._type = str(grid_type)

    def __str__(self):
        return self._type

_GRID_READERS = {"raster": raster_from_dict, "hex": hex_from_dict}

def create_and_initialize_grid(input_source):
    """Create and initialize a grid from a file.

    Creates, initializes, and returns a new grid object using parameters
    specified in *input_source*. *input_source* is either a
    ModelParameterDictionary instance (or, really, just dict-like) or a
    named input file.

    Parameters
    ----------
    input_source : str or dict
        Input file or ``dict`` of parameter values.

    Raises
    ------
    KeyError
        If missing a key from the input file.

    Examples
    --------
    >>> from six import StringIO
    >>> import pytest
    >>> test_file = StringIO('''
    ... GRID_TYPE:
    ... raster
    ... NUM_ROWS:
    ... 4
    ... NUM_COLS:
    ... 5
    ... GRID_SPACING:
    ... 2.5
    ... ''')
    >>> from landlab import create_and_initialize_grid
    >>> with pytest.warns(DeprecationWarning):
    ...    grid = create_and_initialize_grid(test_file)
    >>> grid.number_of_nodes
    20
    """
    msg = (
        "create_and_initialize_grid is deprecated and will be removed "
        "in landlab 2.0. Use create_grid instead."
    )
    warn(msg, DeprecationWarning)
    if isinstance(input_source, dict):
        param_dict = input_source
    else:
        param_dict = mpd.ModelParameterDictionary(from_file=input_source)

    grid_type = param_dict["GRID_TYPE"]

    grid_type.strip().lower()

    # Read parameters appropriate to that type, create it, and initialize it
    try:
        grid_reader = _GRID_READERS[grid_type]
    except KeyError:
        raise BadGridTypeError(grid_type)

    # Return the created and initialized grid
    return grid_reader(param_dict)

def create_grid(dict_like):
    """Create grid, initialize fields, and set boundary conditions.

    Examples
    --------
    >>> import numpy as np
    >>> np.random.seed(42)
    >>> from landlab import create_grid
    >>> p = {'grid': {'RasterModelGrid': {'shape': (4,5),
    ...                                   'xy_spacing': (3, 4)}
    ...               },
    ...      'fields': {'at_node': {'spam': {'plane': {'point': (1, 1, 1),
    ...                                                'normal': (-2, -1, 1)},
    ...                                      'random': {'distribution': 'uniform',
    ...                                                 'low': 1,
    ...                                                 'high': 4}
    ...                                      },
    ...                             },
    ...                 'at_link': {'eggs' : {'constant': {'where': 'ACTIVE_LINK',
    ...                                                    'constant': 12},
    ...                                       },
    ...                             },
    ...                 },
    ...      'boundary_conditions': [
    ...                     {'set_closed_boundaries_at_grid_edges':
    ...                                 {'right_is_closed': True,
    ...                                  'top_is_closed': True,
    ...                                  'left_is_closed': True,
    ...                                  'bottom_is_closed': True
    ...                                  }
    ...                      }]
    ...      }
    >>> mg = create_grid(p)
    >>> mg.number_of_nodes
    20
    >>> "spam" in mg.at_node
    True
    >>> "eggs" in mg.at_link
    True
    >>> mg.x_of_node
    array([  0.,   3.,   6.,   9.,  12.,
             0.,   3.,   6.,   9.,  12.,
             0.,   3.,   6.,   9.,  12.,
             0.,   3.,   6.,   9.,  12.])
    >>> mg.status_at_node
    array([4, 4, 4, 4, 4,
           4, 0, 0, 0, 4,
           4, 0, 0, 0, 4,
           4, 4, 4, 4, 4], dtype=uint8)
    """
    # part 0, parse input
    if isinstance(file_like, dict):
        dict_like = file_like
    else:
        dict_like = load_params(file_like)

    # part 1 create grid
    grid_dict = dict_like.pop("grid", None)
    if grid_dict is None:
        msg = "create_grid: no grid dictionary provided. This is required."
        raise ValueError(msg)

    for grid_type in grid_dict:
        if grid_type in _MODEL_GRIDS:
            grid_class = _MODEL_GRIDS[grid_type]
        else:
            msg = "create_grid: provided grid type not supported."
            raise ValueError

    if len(grid_dict) != 1:
        msg = (
            "create_grid: two entries to grid dictionary provided. "
            "This is not supported."
        )
        raise ValueError

    grid_params = grid_dict.pop(grid_type)
    grid = grid_class.from_dict(grid_params)

    # part two, create fields
    fields_dict = dict_like.pop("fields", {})

    # for each grid element:
    for at_group in fields_dict:
        at = at_group[3:]
        if at not in grid.groups:
            msg = ("")
            raise ValueError(msg)

        at_dict = fields_dict[at_group]
        # for field at grid element
        for name in at_dict:
            name_dict = at_dict[name]

            # for each function, add values.
            for func in name_dict:
                func_dict = name_dict[func]
                if func in _SYNTHETIC_FIELD_CONSTRUCTORS:
                    synth_function = _SYNTHETIC_FIELD_CONSTRUCTORS[func]
                    synth_function(grid, name, at=at, **func_dict)
                elif func in _READ_FROM_FILE:
                    from_file_func = _READ_FROM_FILE[func]
                    from_file_func(grid=grid, **func_dict)
                else:
                    msg = "Bad function supplied to construct field"

    # part three, set boundary conditions
    bc_list = dict_like.pop("boundary_conditions", [])
    for bc_function_dict in bc_list:

        if len(bc_function_dict) != 1:
            msg = ""
            raise ValueError(msg)

        for bc_function in bc_function_dict:
            bc_params = bc_function_dict[bc_function]
            methods = dict(inspect.getmembers(grid, inspect.ismethod))
            if bc_function in methods:
                methods[bc_function](**bc_params)
            else:
                msg = ("create_grid: No function ",
                       "{func} ".format(func=bc_function),
                       "exists for grid types ",
                       "{grid}. ".format(grid=grid_type),
                       "If you think this type of grid should have such a ",
                       "function. Please create a GitHub Issue to discuss ",
                       "contributing it to the Landlab codebase.")
                raise ValueError(msg)

    return grid
<commit_msg>adding documentation (in progress)<commit_after>#! /usr/bin/env python
"""Create landlab model grids."""
import inspect

from warnings import warn

from landlab.core import model_parameter_dictionary as mpd
from landlab.core import load_params
from landlab.io import read_esri_ascii
from landlab.io.netcdf import read_netcdf
from landlab.values import constant, plane, random, sine

from .hex import HexModelGrid, from_dict as hex_from_dict
from .network import NetworkModelGrid
from .radial import RadialModelGrid
from .raster import RasterModelGrid, from_dict as raster_from_dict
from .voronoi import VoronoiDelaunayGrid

_MODEL_GRIDS = {
    "RasterModelGrid": RasterModelGrid,
    "HexModelGrid": HexModelGrid,
    "VoronoiDelaunayGrid": VoronoiDelaunayGrid,
    "NetworkModelGrid": NetworkModelGrid,
    "RadialModelGrid": RadialModelGrid,
}

_SYNTHETIC_FIELD_CONSTRUCTORS = {
    "plane": plane,
    "random": random,
    "sine": sine,
    "constant": constant,
}

_READ_FROM_FILE = {
    "read_netcdf": read_netcdf,
    "read_esri_ascii": read_esri_ascii,
}

class Error(Exception):

    """Base class for exceptions from this module."""

    pass

class BadGridTypeError(Error):

    """Raise this error for a bad grid type."""

    def __init__(self, grid_type):
        self._type = str(grid_type)

    def __str__(self):
        return self._type

_GRID_READERS = {"raster": raster_from_dict, "hex": hex_from_dict}

def create_and_initialize_grid(input_source):
    """Create and initialize a grid from a file.

    Creates, initializes, and returns a new grid object using parameters
    specified in *input_source*. *input_source* is either a
    ModelParameterDictionary instance (or, really, just dict-like) or a
    named input file.

    Parameters
    ----------
    input_source : str or dict
        Input file or ``dict`` of parameter values.

    Raises
    ------
    KeyError
        If missing a key from the input file.

    Examples
    --------
    >>> from six import StringIO
    >>> import pytest
    >>> test_file = StringIO('''
    ... GRID_TYPE:
    ... raster
    ... NUM_ROWS:
    ... 4
    ... NUM_COLS:
    ... 5
    ... GRID_SPACING:
    ... 2.5
    ... ''')
    >>> from landlab import create_and_initialize_grid
    >>> with pytest.warns(DeprecationWarning):
    ...    grid = create_and_initialize_grid(test_file)
    >>> grid.number_of_nodes
    20
    """
    msg = (
        "create_and_initialize_grid is deprecated and will be removed "
        "in landlab 2.0. Use create_grid instead."
    )
    warn(msg, DeprecationWarning)
    if isinstance(input_source, dict):
        param_dict = input_source
    else:
        param_dict = mpd.ModelParameterDictionary(from_file=input_source)

    grid_type = param_dict["GRID_TYPE"]

    grid_type.strip().lower()

    # Read parameters appropriate to that type, create it, and initialize it
    try:
        grid_reader = _GRID_READERS[grid_type]
    except KeyError:
        raise BadGridTypeError(grid_type)

    # Return the created and initialized grid
    return grid_reader(param_dict)

def create_grid(file_like):
    """Create grid, initialize fields, and set boundary conditions.

    Parameters
    ----------
    file_like : file_like or str
        Dictionary, contents of a dictionary as a string, a file-like object,
        or the path to a file containing a YAML dictionary.

    *create_grid* expects a dictionary with three keys "grid", "fields", and
    "boundary_conditions".

    **grid**
    The value associated with the "grid" key should itself be a dictionary
    containing the name of a Landlab model grid type as its only key. The
    following grid types are valid:

        - RasterModelGrid
        - HexModelGrid
        - RadialModelGrid
        - NetworkModelGrid
        - VoronoiDelaunayGrid

    The value associated with the grid name key is a dictionary of keyword
    arguments that will be passed to the ``__init__`` constructor of the
    specified model grid.

    **fields**

    **boundary_conditions**

    function_name: [arg1, arg2, {kwarg1: kwarg1, kwarg2: kwarg2}]

    Examples
    --------
    >>> import numpy as np
    >>> np.random.seed(42)
    >>> from landlab import create_grid
    >>> p = {'grid': {'RasterModelGrid': {'shape': (4,5),
    ...                                   'xy_spacing': (3, 4)}
    ...               },
    ...      'fields': {'at_node': {'spam': {'plane': {'point': (1, 1, 1),
    ...                                                'normal': (-2, -1, 1)},
    ...                                      'random': {'distribution': 'uniform',
    ...                                                 'low': 1,
    ...                                                 'high': 4}
    ...                                      },
    ...                             },
    ...                 'at_link': {'eggs' : {'constant': {'where': 'ACTIVE_LINK',
    ...                                                    'constant': 12},
    ...                                       },
    ...                             },
    ...                 },
    ...      'boundary_conditions': [
    ...                     {'set_closed_boundaries_at_grid_edges':
    ...                                 {'right_is_closed': True,
    ...                                  'top_is_closed': True,
    ...                                  'left_is_closed': True,
    ...                                  'bottom_is_closed': True
    ...                                  }
    ...                      }]
    ...      }
    >>> mg = create_grid(p)
    >>> mg.number_of_nodes
    20
    >>> "spam" in mg.at_node
    True
    >>> "eggs" in mg.at_link
    True
    >>> mg.x_of_node
    array([  0.,   3.,   6.,   9.,  12.,
             0.,   3.,   6.,   9.,  12.,
             0.,   3.,   6.,   9.,  12.,
             0.,   3.,   6.,   9.,  12.])
    >>> mg.status_at_node
    array([4, 4, 4, 4, 4,
           4, 0, 0, 0, 4,
           4, 0, 0, 0, 4,
           4, 4, 4, 4, 4], dtype=uint8)
    """
    # part 0, parse input
    if isinstance(file_like, dict):
        dict_like = file_like
    else:
        dict_like = load_params(file_like)

    # part 1 create grid
    grid_dict = dict_like.pop("grid", None)
    if grid_dict is None:
        msg = "create_grid: no grid dictionary provided. This is required."
        raise ValueError(msg)

    for grid_type in grid_dict:
        if grid_type in _MODEL_GRIDS:
            grid_class = _MODEL_GRIDS[grid_type]
        else:
            msg = "create_grid: provided grid type not supported."
            raise ValueError

    if len(grid_dict) != 1:
        msg = (
            "create_grid: two entries to grid dictionary provided. "
            "This is not supported."
        )
        raise ValueError

    grid_params = grid_dict.pop(grid_type)
    grid = grid_class.from_dict(grid_params)

    # part two, create fields
    fields_dict = dict_like.pop("fields", {})

    # for each grid element:
    for at_group in fields_dict:
        at = at_group[3:]
        if at not in grid.groups:
            msg = ("")
            raise ValueError(msg)

        at_dict = fields_dict[at_group]
        # for field at grid element
        for name in at_dict:
            name_dict = at_dict[name]

            # for each function, add values.
            for func in name_dict:
                func_dict = name_dict[func]
                if func in _SYNTHETIC_FIELD_CONSTRUCTORS:
                    synth_function = _SYNTHETIC_FIELD_CONSTRUCTORS[func]
                    synth_function(grid, name, at=at, **func_dict)
                elif func in _READ_FROM_FILE:
                    from_file_func = _READ_FROM_FILE[func]
                    from_file_func(grid=grid, **func_dict)
                else:
                    msg = "Bad function supplied to construct field"

    # part three, set boundary conditions
    bc_list = dict_like.pop("boundary_conditions", [])
    for bc_function_dict in bc_list:

        if len(bc_function_dict) != 1:
            msg = ""
            raise ValueError(msg)

        for bc_function in bc_function_dict:
            bc_params = bc_function_dict[bc_function]
            methods = dict(inspect.getmembers(grid, inspect.ismethod))
            if bc_function in methods:
                methods[bc_function](**bc_params)
            else:
                msg = ("create_grid: No function ",
                       "{func} ".format(func=bc_function),
                       "exists for grid types ",
                       "{grid}. ".format(grid=grid_type),
                       "If you think this type of grid should have such a ",
                       "function. Please create a GitHub Issue to discuss ",
                       "contributing it to the Landlab codebase.")
                raise ValueError(msg)

    return grid
<|endoftext|>


<commit_before># coding=utf-8
from django.contrib import messages
from django.contrib.auth import logout as auth_logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import login as auth_login
from django.core.paginator import Paginator
from django.db.models import Count, Max, Q
from django.http import HttpResponseForbidden
from django.shortcuts import redirect, render, get_object_or_404
from django.views.decorators.http import require_POST

from .forms import (
    LoginForm, PrivateMessageForm, PublicMessageForm, RoomCreationForm, RoomChangeForm,
    RoomPasswordPrompt, UserCreationForm, UserChangeForm
)
from .models import PrivateMessage, PublicMessage, Room, RoomVisit
from .utils import user_can_view_protected_room, get_ip_addr

def room_view(request, room_slug):
    room = get_object_or_404(Room, slug=room_slug)

    if room.protected:
        if not request.user.is_authenticated():
            messages.error(request, "Do zaheslovaných místností mají přístup pouze přihlášení uživatelé.")
            return redirect("home")
        elif not user_can_view_protected_room(request.user, room):
            return redirect("room_password_prompt", room_slug=room_slug)

    page_number = request.GET.get("page", 1)

    threads = PublicMessage.objects\
        .filter(room=room, thread=None) \
        .order_by("-last_reply") \
        .prefetch_related("author", "children__author", "children__recipient")

    paginator = Paginator(threads, 10)
    threads = paginator.page(page_number)

    last_visit_time = None
    new_posts = None
    if request.user.is_authenticated():
        visit, created = RoomVisit.objects.get_or_create(user=request.user, room=room)
        if not created:
            new_posts = PublicMessage.objects.filter(room=room, created__gte=visit.visit_time).count()
            last_visit_time = visit.visit_time
            # just update the time
            visit.save()
        else:
            new_posts = PublicMessage.objects.filter(room=room).count()

    return render(request, "phorum/room_view.html", {
        'room': room,
        'new_posts': new_posts,
        'threads': threads,
        'last_visit_time': last_visit_time,
        'message_form': PublicMessageForm(request.POST or None),
        'login_form': LoginForm(),
    })

@login_required
def room_password_prompt(request, room_slug):
    room = get_object_or_404(Room, slug=room_slug)

    form = RoomPasswordPrompt(request.POST or None, user=request.user, room=room)
    if form.is_valid():
        return redirect("room_view", room_slug=room_slug)

    return render(request, "phorum/room_password_prompt.html", {
        'room': room,
        'form': form,
    })

@login_required
def room_new(request):
    form = RoomCreationForm(request.POST or None)

    if request.method == "POST":
        if form.is_valid():
            room = form.save(author=request.user)
            return redirect("room_view", room_slug=room.slug)

    return render(request, "phorum/room_new.html", {
        'form': form,
    })

@login_required
def room_edit(request, room_slug):
    room = get_object_or_404(Room, slug=room_slug)

    if not room.can_be_modified_by(request.user):
        return HttpResponseForbidden("Nemáte oprávnění editovat tuto místnost.")

    form = RoomChangeForm(request.POST or None, instance=room)

    if request.method == "POST":
        if form.is_valid():
            room = form.save()
            return redirect("room_view", room_slug=room.slug)

    return render(request, "phorum/room_edit.html", {
        'room': room,
        'form': form,
    })

@login_required
def inbox(request):
    page_number = request.GET.get("page", 1)

    threads = PrivateMessage.objects\
        .filter(thread=None) \
        .filter(Q(author=request.user) | Q(recipient=request.user)) \
        .order_by("-last_reply") \
        .prefetch_related("author", "children__author", "children__recipient")

    paginator = Paginator(threads, 10)
    threads = paginator.page(page_number)

    last_visit_time = request.user.inbox_visit_time
    request.user.update_inbox_visit_time()

    return render(request, "phorum/inbox.html", {
        'threads': threads,
        'last_visit_time': last_visit_time,
        'message_form': PrivateMessageForm(request.POST or None),
    })

@require_POST
def inbox_send(request):
    message_form = PrivateMessageForm(request.POST or None)

    if request.user.is_authenticated():
        if message_form.is_valid():
            message_form.save(author=request.user)
            return redirect("inbox")
        else:
            messages.error(request, "Formulář se zprávou obsahuje chyby.")
    else:
        messages.error(request, "Pro zasílání zpráv musíte být přihlášen.")

    return inbox(request)

@require_POST
def message_send(request, room_slug):
    message_form = PublicMessageForm(request.POST or None)
    room = get_object_or_404(Room, slug=room_slug)

    if request.user.is_authenticated():
        if room.protected and not user_can_view_protected_room(request.user, room):
            messages.error(request, "Do místnosti, do které zasíláte zprávu, již nemáte přístup.")
            return redirect("home")

        if message_form.is_valid():
            message_form.save(author=request.user, room=room)
            request.user.increase_kredyti()
            return redirect("room_view", room_slug=room.slug)
        else:
            messages.error(request, "Formulář se zprávou obsahuje chyby.")
    else:
        messages.error(request, "Pro zasílání zpráv musíte být přihlášen.")

    return room_view(request, room_slug)

def room_list(request):
    rooms = Room.objects.annotate(total_messages=Count("publicmessage"),
                                  last_message_time=Max("publicmessage__created"))

    visits = RoomVisit.objects.visits_for_user(request.user) if request.user.is_authenticated() else None

    return render(request, "phorum/room_list.html", {
        'rooms': rooms,
        'login_form': LoginForm(),
        'visits': visits,
    })

@login_required
def message_delete(request, message_id):
    is_private = request.GET.get("inbox", 0) == "1"
    message = get_object_or_404(PrivateMessage if is_private else PublicMessage, pk=message_id)

    if message.can_be_deleted_by(request.user):
        if not is_private:
            message.author.decrease_kredyti()
        message.delete()
        messages.info(request, "Zpráva byla smazána.")
    else:
        messages.error(request, "Nemáte oprávnění ke smazání zprávy.")

    if is_private:
        return redirect("inbox")

    message_room_slug = message.room.slug
    return redirect("room_view", room_slug=message_room_slug)

def login(request):
    if request.method == "POST":
        form = LoginForm(request, data=request.POST)
        if form.is_valid():
            auth_login(request, form.get_user())
            request.user.last_ip = get_ip_addr(request)
            request.user.save(update_fields=['last_ip'])
        else:
            user = form.get_user()
            if user and not user.is_active:
                messages.info(request, "Uživatelský účet není aktivní.")
            else:
                messages.error(request, "Neplatný login nebo heslo.")

    return redirect("home")

def logout(request):
    auth_logout(request)
    return redirect("home")

def user_new(request):
    form = UserCreationForm(request.POST or None)

    if request.method == "POST":
        if form.is_valid():
            form.save()
            messages.info(request, "Uživatelský účet vytvořen, vyčkejte prosím na jeho aktivaci administrátorem.")
            return redirect("home")

    return render(request, "phorum/user_new.html", {
        'form': form
    })

@login_required
def user_edit(request):
    form = UserChangeForm(request.POST or None, request.FILES or None,
                          instance=request.user)

    if request.method == "POST":
        if form.is_valid():
            form.save()
            messages.info(request, "Profil uživatele upraven.")
            return redirect("user_edit")

    return render(request, "phorum/user_edit.html", {
        'form': form
    })
<commit_msg>do not cache room list (force GET when back is pressed in browser)<commit_after># coding=utf-8
from django.contrib import messages
from django.contrib.auth import logout as auth_logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import login as auth_login
from django.core.paginator import Paginator
from django.db.models import Count, Max, Q
from django.http import HttpResponseForbidden
from django.shortcuts import redirect, render, get_object_or_404
from django.views.decorators.cache import cache_control
from django.views.decorators.http import require_POST

from .forms import (
    LoginForm, PrivateMessageForm, PublicMessageForm, RoomCreationForm, RoomChangeForm,
    RoomPasswordPrompt, UserCreationForm, UserChangeForm
)
from .models import PrivateMessage, PublicMessage, Room, RoomVisit
from .utils import user_can_view_protected_room, get_ip_addr

def room_view(request, room_slug):
    room = get_object_or_404(Room, slug=room_slug)

    if room.protected:
        if not request.user.is_authenticated():
            messages.error(request, "Do zaheslovaných místností mají přístup pouze přihlášení uživatelé.")
            return redirect("home")
        elif not user_can_view_protected_room(request.user, room):
            return redirect("room_password_prompt", room_slug=room_slug)

    page_number = request.GET.get("page", 1)

    threads = PublicMessage.objects\
        .filter(room=room, thread=None) \
        .order_by("-last_reply") \
        .prefetch_related("author", "children__author", "children__recipient")

    paginator = Paginator(threads, 10)
    threads = paginator.page(page_number)

    last_visit_time = None
    new_posts = None
    if request.user.is_authenticated():
        visit, created = RoomVisit.objects.get_or_create(user=request.user, room=room)
        if not created:
            new_posts = PublicMessage.objects.filter(room=room, created__gte=visit.visit_time).count()
            last_visit_time = visit.visit_time
            # just update the time
            visit.save()
        else:
            new_posts = PublicMessage.objects.filter(room=room).count()

    return render(request, "phorum/room_view.html", {
        'room': room,
        'new_posts': new_posts,
        'threads': threads,
        'last_visit_time': last_visit_time,
        'message_form': PublicMessageForm(request.POST or None),
        'login_form': LoginForm(),
    })

@login_required
def room_password_prompt(request, room_slug):
    room = get_object_or_404(Room, slug=room_slug)

    form = RoomPasswordPrompt(request.POST or None, user=request.user, room=room)
    if form.is_valid():
        return redirect("room_view", room_slug=room_slug)

    return render(request, "phorum/room_password_prompt.html", {
        'room': room,
        'form': form,
    })

@login_required
def room_new(request):
    form = RoomCreationForm(request.POST or None)

    if request.method == "POST":
        if form.is_valid():
            room = form.save(author=request.user)
            return redirect("room_view", room_slug=room.slug)

    return render(request, "phorum/room_new.html", {
        'form': form,
    })

@login_required
def room_edit(request, room_slug):
    room = get_object_or_404(Room, slug=room_slug)

    if not room.can_be_modified_by(request.user):
        return HttpResponseForbidden("Nemáte oprávnění editovat tuto místnost.")

    form = RoomChangeForm(request.POST or None, instance=room)

    if request.method == "POST":
        if form.is_valid():
            room = form.save()
            return redirect("room_view", room_slug=room.slug)

    return render(request, "phorum/room_edit.html", {
        'room': room,
        'form': form,
    })

@login_required
def inbox(request):
    page_number = request.GET.get("page", 1)

    threads = PrivateMessage.objects\
        .filter(thread=None) \
        .filter(Q(author=request.user) | Q(recipient=request.user)) \
        .order_by("-last_reply") \
        .prefetch_related("author", "children__author", "children__recipient")

    paginator = Paginator(threads, 10)
    threads = paginator.page(page_number)

    last_visit_time = request.user.inbox_visit_time
    request.user.update_inbox_visit_time()

    return render(request, "phorum/inbox.html", {
        'threads': threads,
        'last_visit_time': last_visit_time,
        'message_form': PrivateMessageForm(request.POST or None),
    })

@require_POST
def inbox_send(request):
    message_form = PrivateMessageForm(request.POST or None)

    if request.user.is_authenticated():
        if message_form.is_valid():
            message_form.save(author=request.user)
            return redirect("inbox")
        else:
            messages.error(request, "Formulář se zprávou obsahuje chyby.")
    else:
        messages.error(request, "Pro zasílání zpráv musíte být přihlášen.")

    return inbox(request)

@require_POST
def message_send(request, room_slug):
    message_form = PublicMessageForm(request.POST or None)
    room = get_object_or_404(Room, slug=room_slug)

    if request.user.is_authenticated():
        if room.protected and not user_can_view_protected_room(request.user, room):
            messages.error(request, "Do místnosti, do které zasíláte zprávu, již nemáte přístup.")
            return redirect("home")

        if message_form.is_valid():
            message_form.save(author=request.user, room=room)
            request.user.increase_kredyti()
            return redirect("room_view", room_slug=room.slug)
        else:
            messages.error(request, "Formulář se zprávou obsahuje chyby.")
    else:
        messages.error(request, "Pro zasílání zpráv musíte být přihlášen.")

    return room_view(request, room_slug)

@cache_control(no_cache=True, must_revalidate=True, no_store=True, max_age=0)
def room_list(request):
    rooms = Room.objects.annotate(total_messages=Count("publicmessage"),
                                  last_message_time=Max("publicmessage__created"))

    visits = RoomVisit.objects.visits_for_user(request.user) if request.user.is_authenticated() else None

    return render(request, "phorum/room_list.html", {
        'rooms': rooms,
        'login_form': LoginForm(),
        'visits': visits,
    })

@login_required
def message_delete(request, message_id):
    is_private = request.GET.get("inbox", 0) == "1"
    message = get_object_or_404(PrivateMessage if is_private else PublicMessage, pk=message_id)

    if message.can_be_deleted_by(request.user):
        if not is_private:
            message.author.decrease_kredyti()
        message.delete()
        messages.info(request, "Zpráva byla smazána.")
    else:
        messages.error(request, "Nemáte oprávnění ke smazání zprávy.")

    if is_private:
        return redirect("inbox")

    message_room_slug = message.room.slug
    return redirect("room_view", room_slug=message_room_slug)

def login(request):
    if request.method == "POST":
        form = LoginForm(request, data=request.POST)
        if form.is_valid():
            auth_login(request, form.get_user())
            request.user.last_ip = get_ip_addr(request)
            request.user.save(update_fields=['last_ip'])
        else:
            user = form.get_user()
            if user and not user.is_active:
                messages.info(request, "Uživatelský účet není aktivní.")
            else:
                messages.error(request, "Neplatný login nebo heslo.")

    return redirect("home")

def logout(request):
    auth_logout(request)
    return redirect("home")

def user_new(request):
    form = UserCreationForm(request.POST or None)

    if request.method == "POST":
        if form.is_valid():
            form.save()
            messages.info(request, "Uživatelský účet vytvořen, vyčkejte prosím na jeho aktivaci administrátorem.")
            return redirect("home")

    return render(request, "phorum/user_new.html", {
        'form': form
    })

@login_required
def user_edit(request):
    form = UserChangeForm(request.POST or None, request.FILES or None,
                          instance=request.user)

    if request.method == "POST":
        if form.is_valid():
            form.save()
            messages.info(request, "Profil uživatele upraven.")
            return redirect("user_edit")

    return render(request, "phorum/user_edit.html", {
        'form': form
    })
<|endoftext|>


<commit_before># coding=utf-8
from .main import PhonemeList, Voice
<commit_msg>Woops<commit_after># coding=utf-8
from .main import Voice
from .phonemes import PhonemeList, FrenchPhonemes, BritishEnglishPhonemes, SpanishPhonemes, GermanPhonemes<|endoftext|>


<commit_before>#! /usr/bin/env python

import sys
import curses
from curses import KEY_ENTER
import time
from collections import namedtuple

KEY = "KEY"
K_A = ord("a")
K_D = ord("d")
K_SPACE = ord(" ")
K_ESCAPE = 27

class Point:
    def __init__(self, x, y):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, val):
        self._x = val

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, val):
        self._y = val

Event = namedtuple("Event", ["type", "val"])

class Spaceship(object):
    def __init__(self, border):
        self._image = "<i>"
        self._dx = 1
        self.border = border
        self._pos = Point(self.border.x // 2, self.border.y - 1)
        self._fire = False

    def events(self, event):
        if event.type == KEY:
            if event.val == K_A:
                self._dx = -1
            if event.val == K_D:
                self._dx = 1
            if event.val == K_SPACE:
                self._fire = True if self._fire else False

    def update(self):
        if self._pos.x == self.border.x - len(self._image) - 1 and self._dx > 0:
            self._pos.x = 0
        elif self._pos.x == 1 and self._dx < 0:
            self._pos.x = self.border.x - len(self._image)

        self._pos.x += self._dx
        self._dx = 0

        if self._fire:
            pass

    def draw(self, screen):
        screen.addstr(self._pos.y, self._pos.x, self._image, curses.A_BOLD)

class App(object):
    def __init__(self):
        #self.screen = curses.initscr()
        curses.initscr()
        self.border = Point(x=80, y=24)
        self.field  = Point(x=self.border.x, y=self.border.y-1)
        self.screen = curses.newwin(self.border.y, self.border.x, 0, 0)
        self.screen.keypad(1)
        self.screen.nodelay(1)
        curses.noecho()
        #curses.cbreak()
        curses.curs_set(0)
        self.spaceship = Spaceship(self.field)
        self._objects = []
        self._objects.append(self.spaceship)

    def deinit(self):
        self.screen.nodelay(0)
        self.screen.keypad(0)
        curses.nocbreak()
        curses.echo()
        curses.curs_set(1)
        curses.endwin()

    def events(self):
        c = self.screen.getch()
        if c == K_ESCAPE:
            self.deinit()
            sys.exit(1)
        else:
            for o in self._objects:
                o.events(Event(type="KEY", val=c))

    def update(self):
        for o in self._objects:
            o.update()

    def render(self):
        self.screen.clear()
        self.screen.border(0)
        self.screen.addstr(0, 2, "Score: {} ".format(0))
        self.screen.addstr(0, self.border.x // 2 - 4, "XOInvader", curses.A_BOLD)
        for o in self._objects:
            o.draw(self.screen)
        self.screen.refresh()
        time.sleep(0.03)

    def loop(self):
        while True:
            self.events()
            self.update()
            try:
                self.render()
            except:
                self.deinit()
                sys.exit(1)
def main():
    app = App()
    app.loop()

if __name__ == "__main__":
    main()
<commit_msg>add weapon abstract class stub, nothing works yet<commit_after>#! /usr/bin/env python

import sys
import curses
from curses import KEY_ENTER
import time
from collections import namedtuple

KEY = "KEY"
K_A = ord("a")
K_D = ord("d")
K_SPACE = ord(" ")
K_ESCAPE = 27

class Point:
    def __init__(self, x, y):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, val):
        self._x = val

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, val):
        self._y = val

Event = namedtuple("Event", ["type", "val"])

def Weapon(w_class, w_ammo=-1, w_time=-1):
    from abc import ABCMeta
    class AbstractWeapon(object, metaclass=ABCMeta):
        def __init__(self, image, damage, ammo, delay, radius):
            self.__type == None

            self.__image = image
            self.__damage = damage
            self.__ammo = ammo
            self.__delay = delay

            self.__coords = []

            #Behaviour
            self.update = None
            self.render = None

        @property
        def image(self):
            return self.__image

        #TODO:
        def __iter__(self):
            return (c for c in self._coords)

        @classmethod
        def create_weapon(cls, w_type, behaviour=None):
            weapons = {
                    "Blaster": cls(image="^", damage=1, ammo=-1, delay= 5, radius=0),
                    "Laser"  : cls(image="|", damage=2, ammo=10, delay=10, radius=0),
                    "NCRC"   : cls(image="*", damage=5, ammo= 5, delay=15, radius=2),
                    }
            try:
                weapon = weapons[w_type]
                weapon.__type = w_type
                weapon.
            except KeyError as e:
                print("No such weapon type! Error: {}".format(str(e))); return None
            except:
                print("Unhandled exception! Error: {}".format(str(e))); return None

        def update(self):
            pass

        def render(self, screen):
            pass

        create_weapon = lambda w_class, *args, **kwargs: w_class(*args, **kwargs)

    weapons = {
            "Laser" : None,
            "Blaster" : None,
            "Rocket" : None,
            }
    if not weapons.has_key(w_class):
        raise KeyError("No such weapon class")
    return weapons[w_class]

class Spaceship(object):
    def __init__(self, border):
        self._image = "<i>"
        self._dx = 1
        self.border = border
        self._pos = Point(self.border.x // 2, self.border.y - 1)
        self._fire = False
        self.weapon = Weapon(type="Laser", ammo=-1)

    def events(self, event):
        if event.type == KEY:
            if event.val == K_A:
                self._dx = -1
            if event.val == K_D:
                self._dx = 1
            if event.val == K_SPACE:
                self._fire = True if self._fire else False

    def update(self):
        if self._pos.x == self.border.x - len(self._image) - 1 and self._dx > 0:
            self._pos.x = 0
        elif self._pos.x == 1 and self._dx < 0:
            self._pos.x = self.border.x - len(self._image)

        self._pos.x += self._dx
        self._dx = 0

        if self._fire:
            pass

    def draw(self, screen):
        screen.addstr(self._pos.y, self._pos.x, self._image, curses.A_BOLD)

class App(object):
    def __init__(self):
        #self.screen = curses.initscr()
        curses.initscr()
        self.border = Point(x=80, y=24)
        self.field  = Point(x=self.border.x, y=self.border.y-1)
        self.screen = curses.newwin(self.border.y, self.border.x, 0, 0)
        self.screen.keypad(1)
        self.screen.nodelay(1)
        curses.noecho()
        #curses.cbreak()
        curses.curs_set(0)
        self.spaceship = Spaceship(self.field)
        self._objects = []
        self._objects.append(self.spaceship)

    def deinit(self):
        self.screen.nodelay(0)
        self.screen.keypad(0)
        curses.nocbreak()
        curses.echo()
        curses.curs_set(1)
        curses.endwin()

    def events(self):
        c = self.screen.getch()
        if c == K_ESCAPE:
            self.deinit()
            sys.exit(1)
        else:
            for o in self._objects:
                o.events(Event(type="KEY", val=c))

    def update(self):
        for o in self._objects:
            o.update()

    def render(self):
        self.screen.clear()
        self.screen.border(0)
        self.screen.addstr(0, 2, "Score: {} ".format(0))
        self.screen.addstr(0, self.border.x // 2 - 4, "XOInvader", curses.A_BOLD)
        for o in self._objects:
            o.draw(self.screen)
        self.screen.refresh()
        time.sleep(0.03)

    def loop(self):
        while True:
            self.events()
            self.update()
            try:
                self.render()
            except:
                self.deinit()
                sys.exit(1)
def main():
    app = App()
    app.loop()

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before># Add ramp properties to paths in roads layer

# Steps with ramp:bicycle=yes in Copenhagen
# https://www.openstreetmap.org/way/91275149
assert_has_feature(
    15, 17527, 10257, 'roads',
    { 'id': 91275149, 'kind': 'path', 'kind_detail': 'steps', 'is_bicycle_related': True, 'ramp_bicycle': 'yes'})

# Footway with ramp=yes in San Francisco
# https://www.openstreetmap.org/way/346088008
assert_has_feature(
    15, 5235, 12671, 'roads',
    { 'id': 10273013, 'kind': 'path', 'kind_detail': 'footway', 'ramp': 'yes'})<commit_msg>[tests] fix copy-paste job on feature ID<commit_after># Add ramp properties to paths in roads layer

# Steps with ramp:bicycle=yes in Copenhagen
# https://www.openstreetmap.org/way/91275149
assert_has_feature(
    15, 17527, 10257, 'roads',
    { 'id': 91275149, 'kind': 'path', 'kind_detail': 'steps', 'is_bicycle_related': True, 'ramp_bicycle': 'yes'})

# Footway with ramp=yes in San Francisco
# https://www.openstreetmap.org/way/346088008
assert_has_feature(
    15, 5235, 12671, 'roads',
    { 'id': 346088008, 'kind': 'path', 'kind_detail': 'footway', 'ramp': 'yes'})<|endoftext|>


<commit_before>import geopandas as gpd
import pandas
import numpy
import matplotlib
import matplotlib.pyplot as plt

from geopandas import read_file # convenience

class Map:
	def __init__(self,
				 center=(None,None), extent=(None,None),
				 xlim=None, ylim=None,
				 xticks=None, yticks=None,
				 title=None, bgcolor=None):
		fig, ax = plt.subplots()
		ax.set_aspect('equal')

		if center[0] and extent[0]:
			ax.set_xlim(center[0]-extent[0], center[0]+extent[0])
		elif xlim is not None:
			ax.set_xlim(*xlim)

		if center[1] and extent[1]:
			ax.set_ylim(center[1]-extent[1], center[1]+extent[1])
		elif ylim is not None:
			ax.set_ylim(*ylim)

		if xticks is None or xticks is False:
			ax.set_xticks([])
		elif xticks is not True:
			ax.set_xticks(xticks)

		if yticks is None or yticks is False:
			ax.set_yticks([])
		elif yticks is not True:
			ax.set_yticks(yticks)

		if bgcolor is not None:
			fig.patch.set_facecolor(bgcolor)

		self.ax = ax
		self.fig = fig

		self.set_title(title)

	def set_title(self, title):
		self._title = title
		if title is not None:
			self.ax.set_title(title)

	def __repr__(self):
		if self._title:
			return f"<pines.geoviz.Map: {self._title}>"
		else:
			return f"<pines.geoviz.Map: Untitled>"

	def choropleth(self, gdf, column, cmap=None, legend=True, vmin=None, vmax=None, labels=None, **kwargs):
		y = gdf.plot(
			ax=self.ax,
			column=column,
			cmap=cmap,
			legend=legend,
			vmin=vmin,
			vmax=vmax,
			**kwargs
		)
		if labels is not None:
			from seaborn.utils import relative_luminance
			areacolors = y.collections[0].get_facecolors()
			label_col = labels.pop('column')
			formatter = labels.pop('formatter', lambda x: x)
			for r in range(len(gdf)):
				self.ax.annotate(
					s=str(formatter(gdf.iloc[r][label_col])),
					xy=gdf.iloc[r].geometry.representative_point().coords[0],
					ha='center', va='center', clip_on=True,
					color=".15" if relative_luminance(areacolors[r]) > .408 else "w",
					**labels
				)
		return self

	def invalid_area(self, gdf, color='#000000AA', **kwargs):
		gdf.plot(
			ax=self.ax,
			color=color,
			**kwargs
		)
		return self

	def borderlines(self, gdf, edgecolor="#000000FF", weight=1, **kwargs):
		gdf.plot(
			ax=self.ax,
			color="#FFFFFF00", # transparent fill color
			edgecolor=edgecolor,
			linewidth=weight,
			**kwargs
		)
		return self

	def labels(self, gdf, column, formatter=lambda x:x, **kwargs):
		if column not in gdf.columns:
			raise KeyError(f'column "{column}" not in gdf.columns')
		gdf.apply(
			lambda x: self.ax.annotate(
				s=str(formatter(x[column])), xy=x.geometry.centroid.coords[0],
				ha='center', va='center', clip_on=True,
				**kwargs
			),
			axis=1
		)
		return self

class MapMaker:
	def __init__(self, *args, **kwargs):
		self._args = args
		self._kwargs = kwargs

	def __call__(self, **kwargs):
		return Map(*self._args, **self._kwargs, **kwargs)

<commit_msg>reduce_coordinate_precision_of_shapefile<commit_after>import geopandas as gpd
import pandas
import numpy
import matplotlib
import matplotlib.pyplot as plt

from geopandas import read_file # convenience

class Map:
	def __init__(self,
				 center=(None,None), extent=(None,None),
				 xlim=None, ylim=None,
				 xticks=None, yticks=None,
				 title=None, bgcolor=None):
		fig, ax = plt.subplots()
		ax.set_aspect('equal')

		if center[0] and extent[0]:
			ax.set_xlim(center[0]-extent[0], center[0]+extent[0])
		elif xlim is not None:
			ax.set_xlim(*xlim)

		if center[1] and extent[1]:
			ax.set_ylim(center[1]-extent[1], center[1]+extent[1])
		elif ylim is not None:
			ax.set_ylim(*ylim)

		if xticks is None or xticks is False:
			ax.set_xticks([])
		elif xticks is not True:
			ax.set_xticks(xticks)

		if yticks is None or yticks is False:
			ax.set_yticks([])
		elif yticks is not True:
			ax.set_yticks(yticks)

		if bgcolor is not None:
			fig.patch.set_facecolor(bgcolor)

		self.ax = ax
		self.fig = fig

		self.set_title(title)

	def set_title(self, title):
		self._title = title
		if title is not None:
			self.ax.set_title(title)

	def __repr__(self):
		if self._title:
			return f"<pines.geoviz.Map: {self._title}>"
		else:
			return f"<pines.geoviz.Map: Untitled>"

	def choropleth(self, gdf, column, cmap=None, legend=True, vmin=None, vmax=None, labels=None, **kwargs):
		y = gdf.plot(
			ax=self.ax,
			column=column,
			cmap=cmap,
			legend=legend,
			vmin=vmin,
			vmax=vmax,
			**kwargs
		)
		if labels is not None:
			from seaborn.utils import relative_luminance
			areacolors = y.collections[0].get_facecolors()
			label_col = labels.pop('column')
			formatter = labels.pop('formatter', lambda x: x)
			for r in range(len(gdf)):
				self.ax.annotate(
					s=str(formatter(gdf.iloc[r][label_col])),
					xy=gdf.iloc[r].geometry.representative_point().coords[0],
					ha='center', va='center', clip_on=True,
					color=".15" if relative_luminance(areacolors[r]) > .408 else "w",
					**labels
				)
		return self

	def invalid_area(self, gdf, color='#000000AA', **kwargs):
		gdf.plot(
			ax=self.ax,
			color=color,
			**kwargs
		)
		return self

	def borderlines(self, gdf, edgecolor="#000000FF", weight=1, **kwargs):
		gdf.plot(
			ax=self.ax,
			color="#FFFFFF00", # transparent fill color
			edgecolor=edgecolor,
			linewidth=weight,
			**kwargs
		)
		return self

	def labels(self, gdf, column, formatter=lambda x:x, **kwargs):
		if column not in gdf.columns:
			raise KeyError(f'column "{column}" not in gdf.columns')
		gdf.apply(
			lambda x: self.ax.annotate(
				s=str(formatter(x[column])), xy=x.geometry.centroid.coords[0],
				ha='center', va='center', clip_on=True,
				**kwargs
			),
			axis=1
		)
		return self

class MapMaker:
	def __init__(self, *args, **kwargs):
		self._args = args
		self._kwargs = kwargs

	def __call__(self, **kwargs):
		return Map(*self._args, **self._kwargs, **kwargs)

def reduce_coordinate_precision_of_shapefile(in_filename, *out_filename, **kwargs):
	from shapely.geometry import shape, mapping

	gdf = gpd.read_file(in_filename)

	for xx in gdf.index:
		geojson = mapping(gdf.geometry[xx])
		geojson['coordinates'] = numpy.round(numpy.array(geojson['coordinates']), 6)
		gdf.loc[xx, 'geometry'] = shape(geojson)

	gdf.to_file(*out_filename, **kwargs)<|endoftext|>