<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 json
import re

from typing import Optional

import attr
import attr.validators
import cattr
import packaging.version

from packaging.specifiers import SpecifierSet

class UnknownUserAgentError(ValueError):
    pass

@attr.s(slots=True, frozen=True)
class Installer:

    name = attr.ib(type=Optional[str], default=None)
    version = attr.ib(type=Optional[str], default=None)

@attr.s(slots=True, frozen=True)
class Implementation:

    name = attr.ib(type=Optional[str], default=None)
    version = attr.ib(type=Optional[str], default=None)

@attr.s(slots=True, frozen=True)
class LibC:

    lib = attr.ib(type=Optional[str], default=None)
    version = attr.ib(type=Optional[str], default=None)

@attr.s(slots=True, frozen=True)
class Distro:

    name = attr.ib(type=Optional[str], default=None)
    version = attr.ib(type=Optional[str], default=None)
    id = attr.ib(type=Optional[str], default=None)
    libc = attr.ib(type=Optional[LibC], default=None)

@attr.s(slots=True, frozen=True)
class System:

    name = attr.ib(type=Optional[str], default=None)
    release = attr.ib(type=Optional[str], default=None)

@attr.s(slots=True, frozen=True)
class UserAgent:

    installer = attr.ib(type=Optional[Installer], default=None)
    python = attr.ib(type=Optional[str], default=None)
    implementation = attr.ib(type=Optional[Implementation], default=None)
    distro = attr.ib(type=Optional[Distro], default=None)
    system = attr.ib(type=Optional[System], default=None)
    cpu = attr.ib(type=Optional[str], default=None)
    openssl_version = attr.ib(type=Optional[str], default=None)
    setuptools_version = attr.ib(type=Optional[str], default=None)

class Parser:
    @staticmethod
    def pip_6_format(user_agent):
        # We're only concerned about pip user agents.
        if not user_agent.startswith("pip/"):
            return

        # This format was brand new in pip 6.0, so we'll need to restrict it
        # to only versions of pip newer than that.
        version_str = user_agent.split()[0].split("/", 1)[1]
        version = packaging.version.parse(version_str)
        if version not in SpecifierSet(">=6", prereleases=True):
            return

        try:
            return json.loads(user_agent.split(maxsplit=1)[1])
        except json.JSONDecodeError:
            return

    @staticmethod
    def pip_1_4_format(user_agent):
        # We're only concerned about pip user agents.
        if not user_agent.startswith("pip/"):
            return

        # This format was brand new in pip 1.4, and went away in pip 6.0, so
        # we'll need to restrict it to only versions of pip between 1.4 and 6.0
        version_str = user_agent.split()[0].split("/", 1)[1]
        version = packaging.version.parse(version_str)
        if version not in SpecifierSet(">=1.4,<6", prereleases=True):
            return

        _, impl, system = user_agent.split(maxsplit=2)

        data = {
            "installer": {"name": "pip", "version": version_str},
            "implementation": {"name": impl.split("/", 1)[0]},
        }

        if not impl.endswith("/Unknown"):
            data["implementation"]["version"] = impl.split("/", 1)[1]

        if not system.startswith("Unknown/"):
            data.setdefault("system", {})["name"] = system.split("/", 1)[0]

        if not system.endswith("/Unknown"):
            data.setdefault("system", {})["release"] = system.split("/", 1)[1]

        if data["implementation"]["name"].lower() == "cpython" and data[
            "implementation"
        ].get("version"):
            data["python"] = data["implementation"]["version"]

        return data

    _distribute_re = re.compile(
        r"^Python-urllib/(?P<python>\d\.\d) distribute/(?P<version>\S+)$"
    )

    @classmethod
    def distribute_format(cls, user_agent):
        m = cls._distribute_re.search(user_agent)
        if m is None:
            return

        return {
            "installer": {"name": "distribute", "version": m.group("version")},
            "python": m.group("python"),
        }

    _setuptools_re = re.compile(
        r"^Python-urllib/(?P<python>\d\.\d) setuptools/(?P<version>\S+)$"
    )

    _setuptools_new_re = re.compile(
        r"^setuptools/(?P<version>\S+) Python-urllib/(?P<python>\d\.\d)$"
    )

    @classmethod
    def setuptools_format(cls, user_agent):
        m = cls._setuptools_re.search(user_agent)
        if m is None:
            m = cls._setuptools_new_re.search(user_agent)
            if m is None:
                return

        return {
            "installer": {"name": "setuptools", "version": m.group("version")},
            "python": m.group("python"),
        }

    _pex_re = re.compile(r"pex/(?P<version>\S+)$")

    @classmethod
    def pex_format(cls, user_agent):
        m = cls._pex_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "pex", "version": m.group("version")}}

    _conda_re = re.compile(r"^conda/(?P<version>\S+)(?: .+)?$")

    @classmethod
    def conda_format(cls, user_agent):
        m = cls._conda_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "conda", "version": m.group("version")}}

    _bandersnatch_re = re.compile(r"^bandersnatch/(?P<version>\S+) \(.+\)$")

    @classmethod
    def bandersnatch_format(cls, user_agent):
        m = cls._bandersnatch_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "bandersnatch", "version": m.group("version")}}

    _devpi_re = re.compile(r"devpi-server/(?P<version>\S+) \(.+\)$")

    @classmethod
    def devpi_format(cls, user_agent):
        m = cls._devpi_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "devpi", "version": m.group("version")}}

    _z3c_pypimirror_re = re.compile(r"^z3c\.pypimirror/(?P<version>\S+)$")

    @classmethod
    def z3c_pypimirror_format(cls, user_agent):
        m = cls._z3c_pypimirror_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "z3c.pypimirror", "version": m.group("version")}}

    _artifactory_re = re.compile(r"^Artifactory/(?P<version>\S+)$")

    @classmethod
    def artifactory_format(cls, user_agent):
        m = cls._artifactory_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "Artifactory", "version": m.group("version")}}

    _pep381client_re = re.compile(r"^pep381client(?:-proxy)?/(?P<version>\S+)$")

    @classmethod
    def pep381client_format(cls, user_agent):
        m = cls._pep381client_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "pep381client", "version": m.group("version")}}

    @staticmethod
    def urllib2_format(user_agent):
        # This isn't really a format exactly, prior to pip 1.4 pip used urllib2
        # and it didn't bother to change the default user agent. This means
        # we'll miscount this version as higher than it actually is, however
        # I'm not sure there is any better way around that.
        if not user_agent.startswith("Python-urllib/"):
            return

        # Some projects (like setuptools) add an additional item to the end of
        # the urllib string. We want to make sure this is _only_ Python-urllib
        if len(user_agent.split()) > 1:
            return

        return {"python": user_agent.split("/", 1)[1]}

    _requests_re = re.compile(r"^python-requests/(?P<version>\S+)(?: .+)?$")

    @classmethod
    def requests_format(cls, user_agent):
        # Older versions of devpi used requests without modifying the user
        # agent. However this could also just be someone using requests to
        # download things from PyPI naturally. This means we can't count this
        # as anything other than requests, but it might be something else.
        m = cls._requests_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "requests", "version": m.group("version")}}

    _os_re = re.compile(
        r"""
        (?:
            ^fetch\ libfetch/\S+$ |
            ^libfetch/\S+$ |
            ^OpenBSD\ ftp$ |
            ^Homebrew\ |
            ^MacPorts/? |
            ^NetBSD-ftp/ |
            ^slapt-get |
            ^pypi-install/ |
            ^slackrepo$ |
            ^PTXdist |
            ^GARstow/ |
            ^xbps/
        )
        """,
        re.VERBOSE,
    )

    @classmethod
    def os_format(cls, user_agent):
        m = cls._os_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "OS"}}

    _homebrew_re = re.compile(
        r"""
        ^
        Homebrew/(?P<version>\S+)
        \s+
        \(Macintosh;\ Intel\ Mac\ OS\ X\ (?P<osx_version>[^)]+)\)
        """,
        re.VERBOSE,
    )

    @classmethod
    def homebrew_format(cls, user_agent):
        m = cls._homebrew_re.search(user_agent)
        if m is None:
            return

        return {
            "installer": {"name": "Homebrew", "version": m.group("version")},
            "distro": {"name": "OS X", "version": m.group("osx_version")},
        }

    _browser_re = re.compile(
        r"""
            ^
            (?:
                Mozilla |
                Safari |
                wget |
                curl |
                Opera |
                aria2 |
                AndroidDownloadManager |
                com\.apple\.WebKit\.Networking/ |
                FDM\ \S+ |
                URL/Emacs |
                Firefox/ |
                UCWEB |
                Links
            )
            (?:/|$)
        """,
        re.IGNORECASE | re.VERBOSE,
    )

    @classmethod
    def browser_format(cls, user_agent):
        m = cls._browser_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "Browser"}}

    _ignore_re = re.compile(
        r"""
        (?:
            ^Datadog\ Agent/ |
            ^\(null\)$ |
            ^WordPress/ |
            ^Chef\ (?:Client|Knife)/ |
            ^Ruby$ |
            ^Slackbot-LinkExpanding |
            ^TextualInlineMedia/ |
            ^WeeChat/ |
            ^Download\ Master$ |
            ^Java/ |
            ^Go\ \d\.\d\ package\ http$ |
            ^Go-http-client/ |
            ^GNU\ Guile$ |
            ^github-olee$ |
            ^YisouSpider$ |
            ^Apache\ Ant/ |
            ^Salt/ |
            ^ansible-httpget$ |
            ^ltx71\ -\ \(http://ltx71.com/\) |
            ^Scrapy/ |
            ^spectool/ |
            Nutch |
            ^AWSBrewLinkChecker/ |
            ^Y!J-ASR/ |
            ^NSIS_Inetc\ \(Mozilla\)$ |
            ^Debian\ uscan
        )
        """,
        re.VERBOSE,
    )

    @classmethod
    def ignored(cls, user_agent):
        m = cls._ignore_re.search(user_agent)
        return m is not None

    @classmethod
    def parse(cls, user_agent):
        formats = [
            cls.pip_6_format,
            cls.pip_1_4_format,
            cls.setuptools_format,
            cls.distribute_format,
            cls.pex_format,
            cls.conda_format,
            cls.bandersnatch_format,
            cls.z3c_pypimirror_format,
            cls.devpi_format,
            cls.artifactory_format,
            cls.pep381client_format,
            cls.urllib2_format,
            cls.requests_format,
            cls.homebrew_format,
            cls.os_format,
            cls.browser_format,
        ]

        for format in formats:
            data = format(user_agent)
            if data is not None:
                return cattr.structure(data, UserAgent)

        if cls.ignored(user_agent):
            return

        raise UnknownUserAgentError(user_agent)

parse = Parser.parse
<commit_msg>Add logging when parsing raises an exception<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 json
import logging
import re

from typing import Optional

import attr
import attr.validators
import cattr
import packaging.version

from packaging.specifiers import SpecifierSet

logger = logging.getLogger(__name__)

class UnknownUserAgentError(ValueError):
    pass

@attr.s(slots=True, frozen=True)
class Installer:

    name = attr.ib(type=Optional[str], default=None)
    version = attr.ib(type=Optional[str], default=None)

@attr.s(slots=True, frozen=True)
class Implementation:

    name = attr.ib(type=Optional[str], default=None)
    version = attr.ib(type=Optional[str], default=None)

@attr.s(slots=True, frozen=True)
class LibC:

    lib = attr.ib(type=Optional[str], default=None)
    version = attr.ib(type=Optional[str], default=None)

@attr.s(slots=True, frozen=True)
class Distro:

    name = attr.ib(type=Optional[str], default=None)
    version = attr.ib(type=Optional[str], default=None)
    id = attr.ib(type=Optional[str], default=None)
    libc = attr.ib(type=Optional[LibC], default=None)

@attr.s(slots=True, frozen=True)
class System:

    name = attr.ib(type=Optional[str], default=None)
    release = attr.ib(type=Optional[str], default=None)

@attr.s(slots=True, frozen=True)
class UserAgent:

    installer = attr.ib(type=Optional[Installer], default=None)
    python = attr.ib(type=Optional[str], default=None)
    implementation = attr.ib(type=Optional[Implementation], default=None)
    distro = attr.ib(type=Optional[Distro], default=None)
    system = attr.ib(type=Optional[System], default=None)
    cpu = attr.ib(type=Optional[str], default=None)
    openssl_version = attr.ib(type=Optional[str], default=None)
    setuptools_version = attr.ib(type=Optional[str], default=None)

class Parser:
    @staticmethod
    def pip_6_format(user_agent):
        # We're only concerned about pip user agents.
        if not user_agent.startswith("pip/"):
            return

        # This format was brand new in pip 6.0, so we'll need to restrict it
        # to only versions of pip newer than that.
        version_str = user_agent.split()[0].split("/", 1)[1]
        version = packaging.version.parse(version_str)
        if version not in SpecifierSet(">=6", prereleases=True):
            return

        try:
            return json.loads(user_agent.split(maxsplit=1)[1])
        except json.JSONDecodeError:
            return

    @staticmethod
    def pip_1_4_format(user_agent):
        # We're only concerned about pip user agents.
        if not user_agent.startswith("pip/"):
            return

        # This format was brand new in pip 1.4, and went away in pip 6.0, so
        # we'll need to restrict it to only versions of pip between 1.4 and 6.0
        version_str = user_agent.split()[0].split("/", 1)[1]
        version = packaging.version.parse(version_str)
        if version not in SpecifierSet(">=1.4,<6", prereleases=True):
            return

        _, impl, system = user_agent.split(maxsplit=2)

        data = {
            "installer": {"name": "pip", "version": version_str},
            "implementation": {"name": impl.split("/", 1)[0]},
        }

        if not impl.endswith("/Unknown"):
            data["implementation"]["version"] = impl.split("/", 1)[1]

        if not system.startswith("Unknown/"):
            data.setdefault("system", {})["name"] = system.split("/", 1)[0]

        if not system.endswith("/Unknown"):
            data.setdefault("system", {})["release"] = system.split("/", 1)[1]

        if data["implementation"]["name"].lower() == "cpython" and data[
            "implementation"
        ].get("version"):
            data["python"] = data["implementation"]["version"]

        return data

    _distribute_re = re.compile(
        r"^Python-urllib/(?P<python>\d\.\d) distribute/(?P<version>\S+)$"
    )

    @classmethod
    def distribute_format(cls, user_agent):
        m = cls._distribute_re.search(user_agent)
        if m is None:
            return

        return {
            "installer": {"name": "distribute", "version": m.group("version")},
            "python": m.group("python"),
        }

    _setuptools_re = re.compile(
        r"^Python-urllib/(?P<python>\d\.\d) setuptools/(?P<version>\S+)$"
    )

    _setuptools_new_re = re.compile(
        r"^setuptools/(?P<version>\S+) Python-urllib/(?P<python>\d\.\d)$"
    )

    @classmethod
    def setuptools_format(cls, user_agent):
        m = cls._setuptools_re.search(user_agent)
        if m is None:
            m = cls._setuptools_new_re.search(user_agent)
            if m is None:
                return

        return {
            "installer": {"name": "setuptools", "version": m.group("version")},
            "python": m.group("python"),
        }

    _pex_re = re.compile(r"pex/(?P<version>\S+)$")

    @classmethod
    def pex_format(cls, user_agent):
        m = cls._pex_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "pex", "version": m.group("version")}}

    _conda_re = re.compile(r"^conda/(?P<version>\S+)(?: .+)?$")

    @classmethod
    def conda_format(cls, user_agent):
        m = cls._conda_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "conda", "version": m.group("version")}}

    _bandersnatch_re = re.compile(r"^bandersnatch/(?P<version>\S+) \(.+\)$")

    @classmethod
    def bandersnatch_format(cls, user_agent):
        m = cls._bandersnatch_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "bandersnatch", "version": m.group("version")}}

    _devpi_re = re.compile(r"devpi-server/(?P<version>\S+) \(.+\)$")

    @classmethod
    def devpi_format(cls, user_agent):
        m = cls._devpi_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "devpi", "version": m.group("version")}}

    _z3c_pypimirror_re = re.compile(r"^z3c\.pypimirror/(?P<version>\S+)$")

    @classmethod
    def z3c_pypimirror_format(cls, user_agent):
        m = cls._z3c_pypimirror_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "z3c.pypimirror", "version": m.group("version")}}

    _artifactory_re = re.compile(r"^Artifactory/(?P<version>\S+)$")

    @classmethod
    def artifactory_format(cls, user_agent):
        m = cls._artifactory_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "Artifactory", "version": m.group("version")}}

    _pep381client_re = re.compile(r"^pep381client(?:-proxy)?/(?P<version>\S+)$")

    @classmethod
    def pep381client_format(cls, user_agent):
        m = cls._pep381client_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "pep381client", "version": m.group("version")}}

    @staticmethod
    def urllib2_format(user_agent):
        # This isn't really a format exactly, prior to pip 1.4 pip used urllib2
        # and it didn't bother to change the default user agent. This means
        # we'll miscount this version as higher than it actually is, however
        # I'm not sure there is any better way around that.
        if not user_agent.startswith("Python-urllib/"):
            return

        # Some projects (like setuptools) add an additional item to the end of
        # the urllib string. We want to make sure this is _only_ Python-urllib
        if len(user_agent.split()) > 1:
            return

        return {"python": user_agent.split("/", 1)[1]}

    _requests_re = re.compile(r"^python-requests/(?P<version>\S+)(?: .+)?$")

    @classmethod
    def requests_format(cls, user_agent):
        # Older versions of devpi used requests without modifying the user
        # agent. However this could also just be someone using requests to
        # download things from PyPI naturally. This means we can't count this
        # as anything other than requests, but it might be something else.
        m = cls._requests_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "requests", "version": m.group("version")}}

    _os_re = re.compile(
        r"""
        (?:
            ^fetch\ libfetch/\S+$ |
            ^libfetch/\S+$ |
            ^OpenBSD\ ftp$ |
            ^Homebrew\ |
            ^MacPorts/? |
            ^NetBSD-ftp/ |
            ^slapt-get |
            ^pypi-install/ |
            ^slackrepo$ |
            ^PTXdist |
            ^GARstow/ |
            ^xbps/
        )
        """,
        re.VERBOSE,
    )

    @classmethod
    def os_format(cls, user_agent):
        m = cls._os_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "OS"}}

    _homebrew_re = re.compile(
        r"""
        ^
        Homebrew/(?P<version>\S+)
        \s+
        \(Macintosh;\ Intel\ Mac\ OS\ X\ (?P<osx_version>[^)]+)\)
        """,
        re.VERBOSE,
    )

    @classmethod
    def homebrew_format(cls, user_agent):
        m = cls._homebrew_re.search(user_agent)
        if m is None:
            return

        return {
            "installer": {"name": "Homebrew", "version": m.group("version")},
            "distro": {"name": "OS X", "version": m.group("osx_version")},
        }

    _browser_re = re.compile(
        r"""
            ^
            (?:
                Mozilla |
                Safari |
                wget |
                curl |
                Opera |
                aria2 |
                AndroidDownloadManager |
                com\.apple\.WebKit\.Networking/ |
                FDM\ \S+ |
                URL/Emacs |
                Firefox/ |
                UCWEB |
                Links
            )
            (?:/|$)
        """,
        re.IGNORECASE | re.VERBOSE,
    )

    @classmethod
    def browser_format(cls, user_agent):
        m = cls._browser_re.search(user_agent)
        if m is None:
            return

        return {"installer": {"name": "Browser"}}

    _ignore_re = re.compile(
        r"""
        (?:
            ^Datadog\ Agent/ |
            ^\(null\)$ |
            ^WordPress/ |
            ^Chef\ (?:Client|Knife)/ |
            ^Ruby$ |
            ^Slackbot-LinkExpanding |
            ^TextualInlineMedia/ |
            ^WeeChat/ |
            ^Download\ Master$ |
            ^Java/ |
            ^Go\ \d\.\d\ package\ http$ |
            ^Go-http-client/ |
            ^GNU\ Guile$ |
            ^github-olee$ |
            ^YisouSpider$ |
            ^Apache\ Ant/ |
            ^Salt/ |
            ^ansible-httpget$ |
            ^ltx71\ -\ \(http://ltx71.com/\) |
            ^Scrapy/ |
            ^spectool/ |
            Nutch |
            ^AWSBrewLinkChecker/ |
            ^Y!J-ASR/ |
            ^NSIS_Inetc\ \(Mozilla\)$ |
            ^Debian\ uscan
        )
        """,
        re.VERBOSE,
    )

    @classmethod
    def ignored(cls, user_agent):
        m = cls._ignore_re.search(user_agent)
        return m is not None

    @classmethod
    def parse(cls, user_agent):
        formats = [
            cls.pip_6_format,
            cls.pip_1_4_format,
            cls.setuptools_format,
            cls.distribute_format,
            cls.pex_format,
            cls.conda_format,
            cls.bandersnatch_format,
            cls.z3c_pypimirror_format,
            cls.devpi_format,
            cls.artifactory_format,
            cls.pep381client_format,
            cls.urllib2_format,
            cls.requests_format,
            cls.homebrew_format,
            cls.os_format,
            cls.browser_format,
        ]

        for format in formats:
            try:
                data = format(user_agent)
            except Exception as exc:
                logger.warning(
                    "Error parsing %r as %s", user_agent, format.__name__, exc_info=True
                )
                data = None

            if data is not None:
                return cattr.structure(data, UserAgent)

        if cls.ignored(user_agent):
            return

        raise UnknownUserAgentError(user_agent)

parse = Parser.parse
<|endoftext|>


<commit_before># -*- coding: UTF-8 -*-
# Copyright 2009-2017 Luc Saffre
#
# License: BSD (see file COPYING for details)

# ~ Note that this module may not have a docstring because any
# ~ global variable defined here will override the global
# ~ namespace of lino/__init__.py who includes it with execfile.

# This module is part of the Lino test suite.
# To test only this module:
#
#   $ python setup.py test -s tests.PackagesTests

from __future__ import unicode_literals

import sys
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

install_requires = ['lino', 'odfpy', 'bleach', 'weasyprint']

if PY2:
    install_requires.append('appy')
else:
    install_requires.append('appypod')

SETUP_INFO = dict(
    name='lino-xl',
    version='2016.12.0',
    # version='1.7.5',
    install_requires=install_requires,
    tests_require=[],
    description="Lino Extensions Library",
    license='BSD License',
    author='Luc Saffre',
    author_email='luc.saffre@gmail.com',
    url="http://www.lino-framework.org",
    # ~ test_suite = 'lino_xl.test_apps',
    test_suite='tests')

SETUP_INFO.update(long_description="""

.. raw:: html

The **Lino Extensions Library** is a collection of plugins used by
many Lino projects.
This package is written and maintained by the same author, but not
part of the Lino core because it adds a given set of solutions for
"Enterprise" style applications.  It is documented together with the
core at http://www.lino-framework.org

""")

SETUP_INFO.update(packages=[str(n) for n in """
lino_xl
lino_xl.lib
lino_xl.lib.addresses
lino_xl.lib.addresses.fixtures
lino_xl.lib.appypod
lino_xl.lib.beid
lino_xl.lib.blogs
lino_xl.lib.boards
lino_xl.lib.groups
lino_xl.lib.groups.fixtures
lino_xl.lib.teams
lino_xl.lib.cal
lino_xl.lib.cal.fixtures
lino_xl.lib.cal.management
lino_xl.lib.cal.management.commands
lino_xl.lib.cal.workflows
lino_xl.lib.coachings
lino_xl.lib.coachings.fixtures
lino_xl.lib.concepts
lino_xl.lib.contacts
lino_xl.lib.contacts.fixtures
lino_xl.lib.contacts.management
lino_xl.lib.contacts.management.commands
lino_xl.lib.countries
lino_xl.lib.countries.fixtures
lino_xl.lib.courses
lino_xl.lib.cv
lino_xl.lib.cv.fixtures
lino_xl.lib.dupable_partners
lino_xl.lib.dupable_partners.fixtures
lino_xl.lib.eid_jslib
lino_xl.lib.eid_jslib.beid
lino_xl.lib.events
lino_xl.lib.events.fixtures
lino_xl.lib.events.tests
lino_xl.lib.excerpts
lino_xl.lib.excerpts.fixtures
lino_xl.lib.extensible
lino_xl.lib.families
lino_xl.lib.households
lino_xl.lib.households.fixtures
lino_xl.lib.humanlinks
lino_xl.lib.humanlinks.fixtures
lino_xl.lib.lists
lino_xl.lib.lists.fixtures
lino_xl.lib.caldav
lino_xl.lib.mailbox
lino_xl.lib.mailbox.fixtures
lino_xl.lib.notes
lino_xl.lib.notes.fixtures
lino_xl.lib.outbox
lino_xl.lib.outbox.fixtures
lino_xl.lib.pages
lino_xl.lib.pages.fixtures
lino_xl.lib.pisa
lino_xl.lib.polls
lino_xl.lib.polls.fixtures
lino_xl.lib.postings
lino_xl.lib.products
lino_xl.lib.products.fixtures
lino_xl.lib.properties
lino_xl.lib.properties.fixtures
lino_xl.lib.reception
lino_xl.lib.rooms
lino_xl.lib.stars
lino_xl.lib.statbel
lino_xl.lib.statbel.countries
lino_xl.lib.statbel.countries.fixtures
lino_xl.lib.thirds
lino_xl.lib.topics
lino_xl.lib.xl

lino_xl.lib.accounts
lino_xl.lib.finan
lino_xl.lib.finan.fixtures
lino_xl.lib.ledger
lino_xl.lib.ledger.fixtures
lino_xl.lib.ledger.management
lino_xl.lib.ledger.management.commands
lino_xl.lib.sales
lino_xl.lib.sales.fixtures
lino_xl.lib.sepa
lino_xl.lib.inbox
lino_xl.lib.invoicing
lino_xl.lib.invoicing.fixtures
lino_xl.lib.sepa.fixtures
lino_xl.lib.tim2lino
lino_xl.lib.tim2lino.fixtures
lino_xl.lib.trends
lino_xl.lib.vat
lino_xl.lib.vat.fixtures
lino_xl.lib.vatless

lino_xl.lib.deploy
lino_xl.lib.deploy.fixtures
lino_xl.lib.tickets
lino_xl.lib.tickets.fixtures
lino_xl.lib.faculties
lino_xl.lib.clocking
lino_xl.lib.clocking.fixtures
lino_xl.lib.votes
lino_xl.lib.votes.fixtures
""".splitlines() if n])

SETUP_INFO.update(classifiers="""\
  Programming Language :: Python
  Programming Language :: Python :: 2
  Development Status :: 5 - Production/Stable
  Environment :: Web Environment
  Framework :: Django
  Intended Audience :: Developers
  Intended Audience :: System Administrators
  License :: OSI Approved :: BSD License
  Natural Language :: English
  Natural Language :: French
  Natural Language :: German
  Operating System :: OS Independent
  Topic :: Database :: Front-Ends
  Topic :: Home Automation
  Topic :: Office/Business
  Topic :: Software Development :: Libraries :: Application Frameworks""".splitlines())

SETUP_INFO.update(message_extractors={
    'lino_xl': [
        ('**/sandbox/**', 'ignore', None),
        ('**/cache/**', 'ignore', None),
        ('**.py', 'python', None),
        ('**/config/**.html', 'jinja2', None),
    ],
})

# SETUP_INFO.update(package_data=dict())
SETUP_INFO.update(include_package_data=True, zip_safe=False)

# def add_package_data(package, *patterns):
#     package = str(package)
#     l = SETUP_INFO['package_data'].setdefault(package, [])
#     l.extend(patterns)
#     return l

# add_package_data('lino_xl', 'config/*.odt')
# add_package_data('lino_xl.lib.cal', 'config/*.odt')
# add_package_data('lino_xl.lib.outbox', 'config/outbox/Mail/*.odt')
# # add_package_data('lino_xl.lib.cal', 'config/*.odt')
# # add_package_data('lino_xl.lib.notes', 'config/notes/Note/*.odt')
# # add_package_data('lino_xl.lib.outbox', 'config/outbox/Mail/*.odt')

# # l = add_package_data('lino_xl.lib.lino_startup')
# # for lng in 'de fr et nl'.split():
# #     l.append('lino/modlib/lino_startup/locale/%s/LC_MESSAGES/*.mo' % lng)
<commit_msg>Updateing git-readme's travis build icon to point to stable<commit_after># -*- coding: UTF-8 -*-
# Copyright 2009-2017 Luc Saffre
#
# License: BSD (see file COPYING for details)

# ~ Note that this module may not have a docstring because any
# ~ global variable defined here will override the global
# ~ namespace of lino/__init__.py who includes it with execfile.

# This module is part of the Lino test suite.
# To test only this module:
#
#   $ python setup.py test -s tests.PackagesTests

from __future__ import unicode_literals

import sys
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

install_requires = ['lino', 'odfpy', 'bleach', 'weasyprint']

if PY2:
    install_requires.append('appy')
else:
    install_requires.append('appypod')

SETUP_INFO = dict(
    name='lino-xl',
    version='2016.12.0',
    # version='1.7.5',
    install_requires=install_requires,
    tests_require=[],
    description="Lino Extensions Library",
    license='BSD License',
    author='Luc Saffre',
    author_email='luc.saffre@gmail.com',
    url="http://www.lino-framework.org",
    # ~ test_suite = 'lino_xl.test_apps',
    test_suite='tests')

SETUP_INFO.update(long_description="""

.. raw:: html

The **Lino Extensions Library** is a collection of plugins used by
many Lino projects.
This package is written and maintained by the same author, but not
part of the Lino core because it adds a given set of solutions for
"Enterprise" style applications.  It is documented together with the
core at http://www.lino-framework.org

""")

SETUP_INFO.update(packages=[str(n) for n in """
lino_xl
lino_xl.lib
lino_xl.lib.addresses
lino_xl.lib.addresses.fixtures
lino_xl.lib.appypod
lino_xl.lib.beid
lino_xl.lib.blogs
lino_xl.lib.boards
lino_xl.lib.groups
lino_xl.lib.groups.fixtures
lino_xl.lib.teams
lino_xl.lib.cal
lino_xl.lib.cal.fixtures
lino_xl.lib.cal.management
lino_xl.lib.cal.management.commands
lino_xl.lib.cal.workflows
lino_xl.lib.coachings
lino_xl.lib.coachings.fixtures
lino_xl.lib.concepts
lino_xl.lib.contacts
lino_xl.lib.contacts.fixtures
lino_xl.lib.contacts.management
lino_xl.lib.contacts.management.commands
lino_xl.lib.countries
lino_xl.lib.countries.fixtures
lino_xl.lib.courses
lino_xl.lib.cv
lino_xl.lib.cv.fixtures
lino_xl.lib.dupable_partners
lino_xl.lib.dupable_partners.fixtures
lino_xl.lib.eid_jslib
lino_xl.lib.eid_jslib.beid
lino_xl.lib.events
lino_xl.lib.events.fixtures
lino_xl.lib.events.tests
lino_xl.lib.excerpts
lino_xl.lib.excerpts.fixtures
lino_xl.lib.extensible
lino_xl.lib.families
lino_xl.lib.households
lino_xl.lib.households.fixtures
lino_xl.lib.humanlinks
lino_xl.lib.humanlinks.fixtures
lino_xl.lib.lists
lino_xl.lib.lists.fixtures
lino_xl.lib.caldav
lino_xl.lib.mailbox
lino_xl.lib.mailbox.fixtures
lino_xl.lib.notes
lino_xl.lib.notes.fixtures
lino_xl.lib.outbox
lino_xl.lib.outbox.fixtures
lino_xl.lib.pages
lino_xl.lib.pages.fixtures
lino_xl.lib.pisa
lino_xl.lib.polls
lino_xl.lib.polls.fixtures
lino_xl.lib.postings
lino_xl.lib.products
lino_xl.lib.products.fixtures
lino_xl.lib.properties
lino_xl.lib.properties.fixtures
lino_xl.lib.reception
lino_xl.lib.rooms
lino_xl.lib.stars
lino_xl.lib.statbel
lino_xl.lib.statbel.countries
lino_xl.lib.statbel.countries.fixtures
lino_xl.lib.thirds
lino_xl.lib.topics
lino_xl.lib.xl

lino_xl.lib.accounts
lino_xl.lib.finan
lino_xl.lib.finan.fixtures
lino_xl.lib.ledger
lino_xl.lib.ledger.fixtures
lino_xl.lib.ledger.management
lino_xl.lib.ledger.management.commands
lino_xl.lib.sales
lino_xl.lib.sales.fixtures
lino_xl.lib.sepa
lino_xl.lib.inbox
lino_xl.lib.invoicing
lino_xl.lib.invoicing.fixtures
lino_xl.lib.sepa.fixtures
lino_xl.lib.tim2lino
lino_xl.lib.tim2lino.fixtures
lino_xl.lib.trends
lino_xl.lib.vat
lino_xl.lib.vat.fixtures
lino_xl.lib.vatless

lino_xl.lib.deploy
lino_xl.lib.deploy.fixtures
lino_xl.lib.tickets
lino_xl.lib.tickets.fixtures
lino_xl.lib.faculties
lino_xl.lib.clocking
lino_xl.lib.clocking.fixtures
lino_xl.lib.votes
lino_xl.lib.votes.fixtures
""".splitlines() if n])

SETUP_INFO.update(classifiers="""\
  Programming Language :: Python
  Programming Language :: Python :: 2
  Development Status :: 5 - Production/Stable
  Environment :: Web Environment
  Framework :: Django
  Intended Audience :: Developers
  Intended Audience :: System Administrators
  License :: OSI Approved :: BSD License
  Natural Language :: English
  Natural Language :: French
  Natural Language :: German
  Operating System :: OS Independent
  Topic :: Database :: Front-Ends
  Topic :: Home Automation
  Topic :: Office/Business
  Topic :: Software Development :: Libraries :: Application Frameworks""".splitlines())

SETUP_INFO.update(message_extractors={
    'lino_xl': [
        ('**/sandbox/**', 'ignore', None),
        ('**/cache/**', 'ignore', None),
        ('**.py', 'python', None),
        ('**/config/**.html', 'jinja2', None),
    ],
})

# SETUP_INFO.update(package_data=dict())
SETUP_INFO.update(include_package_data=True, zip_safe=False)

# def add_package_data(package, *patterns):
#     package = str(package)
#     l = SETUP_INFO['package_data'].setdefault(package, [])
#     l.extend(patterns)
#     return l

# add_package_data('lino_xl', 'config/*.odt')
# add_package_data('lino_xl.lib.cal', 'config/*.odt')
# add_package_data('lino_xl.lib.outbox', 'config/outbox/Mail/*.odt')
# # add_package_data('lino_xl.lib.cal', 'config/*.odt')
# # add_package_data('lino_xl.lib.notes', 'config/notes/Note/*.odt')
# # add_package_data('lino_xl.lib.outbox', 'config/outbox/Mail/*.odt')

# # l = add_package_data('lino_xl.lib.lino_startup')
# # for lng in 'de fr et nl'.split():
# #     l.append('lino/modlib/lino_startup/locale/%s/LC_MESSAGES/*.mo' % lng)
<|endoftext|>


<commit_before>#
#  Copyright 2019 The FATE Authors. All Rights Reserved.
#
#  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.
#
from arch.api import eggroll
from arch.api.utils.core import json_loads, json_dumps, bytes_to_string
from arch.api.utils import log_utils
LOGGER = log_utils.getLogger()

def save_version(name, namespace, version_log='', tag=None, branch=None):
    try:
        if not tag or not branch:
            tmp_tag, tmp_branch = get_commit_tmp(commit_id=name, data_table_namespace=namespace)
            tag = tmp_tag if not tag else tag
            branch = tmp_branch if not branch else branch
        save_version_info(commit_id=name, data_table_namespace=namespace, version_log=version_log, tag=tag, branch=branch)
        return True
    except Exception as e:
        LOGGER.exception(e)
        return False
    finally:
        delete_commit_tmp(commit_id=name, data_table_namespace=namespace)

def save_version_info(commit_id, data_table_namespace, version_log, tag, branch):
    version_table = get_version_table(data_table_namespace=data_table_namespace)
    parent = get_branch_current_commit(version_table=version_table, branch_name=branch)
    version_info = dict()
    version_info["commitId"] = commit_id
    if parent != commit_id:
        version_info["parent"] = parent
    else:
        version_info.update(get_version_info(version_table=version_table, commit_id=parent))
        version_info["repeatCommit"] = True
    version_info["name"] = commit_id
    version_info["namespace"] = data_table_namespace
    version_info["log"] = version_log
    version_info["tag"] = tag
    version_table.put(commit_id, json_dumps(version_info), use_serialize=False)
    # todo: should be use a lock
    version_table.put(branch, commit_id, use_serialize=False)

def get_latest_commit(data_table_namespace, branch="master"):
    version_table = get_version_table(data_table_namespace=data_table_namespace)
    return get_branch_current_commit(version_table=version_table, branch_name=branch)

def version_history(data_table_namespace, commit_id=None, branch="master", limit=10):
    version_table = get_version_table(data_table_namespace=data_table_namespace)
    history = list()
    if commit_id:
        # Get this commit information
        history.append(get_version_info(version_table=version_table, commit_id=commit_id))
    else:
        branch_current_commit = get_branch_current_commit(version_table=version_table, branch_name=branch)
        if branch_current_commit:
            commit_id = branch_current_commit
            for i in range(limit):
                if not commit_id:
                    continue
                commit_info = get_version_info(version_table=version_table, commit_id=commit_id)
                if commit_info:
                    history.append(commit_info)
                    commit_id = commit_info["parent"]
                else:
                    break
    return history

def get_version_table(data_table_namespace):
    version_table = eggroll.table(name=data_table_namespace, namespace="version_control",
                                  partition=1, create_if_missing=True, error_if_exist=False)
    return version_table

def get_branch_current_commit(version_table, branch_name):
    try:
        return bytes_to_string(version_table.get(branch_name, use_serialize=False))
    except:
        return None

def get_version_info(version_table, commit_id):
    info = version_table.get(commit_id, use_serialize=False)
    if info:
        return json_loads(info)
    else:
        return dict()

def save_commit_tmp(commit_id, data_table_namespace, tag, branch):
    version_tmp_table = get_commit_tmp_table(data_table_namespace=data_table_namespace)
    version_tmp_table.put(commit_id, json_dumps({"tag": tag, "branch": branch}), use_serialize=False)

def get_commit_tmp(commit_id, data_table_namespace):
    version_tmp_table = get_commit_tmp_table(data_table_namespace=data_table_namespace)
    commit_tmp_info = version_tmp_table.get(commit_id, use_serialize=False)
    if commit_tmp_info:
        commit_tmp = json_loads(commit_tmp_info)
        return commit_tmp["tag"], commit_tmp["branch"]
    else:
        return None, "master"

def delete_commit_tmp(commit_id, data_table_namespace):
    version_tmp_table = get_commit_tmp_table(data_table_namespace=data_table_namespace)
    version_tmp_table.delete(commit_id)

def get_commit_tmp_table(data_table_namespace):
    version_tmp_table = eggroll.table(name=data_table_namespace, namespace="version_tmp",
                                      partition=1, create_if_missing=True, error_if_exist=False)
    return version_tmp_table

def get_id_library_table_name():
    id_library_info = eggroll.table('info', 'id_library', partition=10, create_if_missing=True, error_if_exist=False)
    return id_library_info.get("use_data_id")
<commit_msg>fate_flow: delete get_id_library_table_name function from version_control module<commit_after>#
#  Copyright 2019 The FATE Authors. All Rights Reserved.
#
#  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.
#
from arch.api import eggroll
from arch.api.utils.core import json_loads, json_dumps, bytes_to_string
from arch.api.utils import log_utils
LOGGER = log_utils.getLogger()

def save_version(name, namespace, version_log='', tag=None, branch=None):
    try:
        if not tag or not branch:
            tmp_tag, tmp_branch = get_commit_tmp(commit_id=name, data_table_namespace=namespace)
            tag = tmp_tag if not tag else tag
            branch = tmp_branch if not branch else branch
        save_version_info(commit_id=name, data_table_namespace=namespace, version_log=version_log, tag=tag, branch=branch)
        return True
    except Exception as e:
        LOGGER.exception(e)
        return False
    finally:
        delete_commit_tmp(commit_id=name, data_table_namespace=namespace)

def save_version_info(commit_id, data_table_namespace, version_log, tag, branch):
    version_table = get_version_table(data_table_namespace=data_table_namespace)
    parent = get_branch_current_commit(version_table=version_table, branch_name=branch)
    version_info = dict()
    version_info["commitId"] = commit_id
    if parent != commit_id:
        version_info["parent"] = parent
    else:
        version_info.update(get_version_info(version_table=version_table, commit_id=parent))
        version_info["repeatCommit"] = True
    version_info["name"] = commit_id
    version_info["namespace"] = data_table_namespace
    version_info["log"] = version_log
    version_info["tag"] = tag
    version_table.put(commit_id, json_dumps(version_info), use_serialize=False)
    # todo: should be use a lock
    version_table.put(branch, commit_id, use_serialize=False)

def get_latest_commit(data_table_namespace, branch="master"):
    version_table = get_version_table(data_table_namespace=data_table_namespace)
    return get_branch_current_commit(version_table=version_table, branch_name=branch)

def version_history(data_table_namespace, commit_id=None, branch="master", limit=10):
    version_table = get_version_table(data_table_namespace=data_table_namespace)
    history = list()
    if commit_id:
        # Get this commit information
        history.append(get_version_info(version_table=version_table, commit_id=commit_id))
    else:
        branch_current_commit = get_branch_current_commit(version_table=version_table, branch_name=branch)
        if branch_current_commit:
            commit_id = branch_current_commit
            for i in range(limit):
                if not commit_id:
                    continue
                commit_info = get_version_info(version_table=version_table, commit_id=commit_id)
                if commit_info:
                    history.append(commit_info)
                    commit_id = commit_info["parent"]
                else:
                    break
    return history

def get_version_table(data_table_namespace):
    version_table = eggroll.table(name=data_table_namespace, namespace="version_control",
                                  partition=1, create_if_missing=True, error_if_exist=False)
    return version_table

def get_branch_current_commit(version_table, branch_name):
    try:
        return bytes_to_string(version_table.get(branch_name, use_serialize=False))
    except:
        return None

def get_version_info(version_table, commit_id):
    info = version_table.get(commit_id, use_serialize=False)
    if info:
        return json_loads(info)
    else:
        return dict()

def save_commit_tmp(commit_id, data_table_namespace, tag, branch):
    version_tmp_table = get_commit_tmp_table(data_table_namespace=data_table_namespace)
    version_tmp_table.put(commit_id, json_dumps({"tag": tag, "branch": branch}), use_serialize=False)

def get_commit_tmp(commit_id, data_table_namespace):
    version_tmp_table = get_commit_tmp_table(data_table_namespace=data_table_namespace)
    commit_tmp_info = version_tmp_table.get(commit_id, use_serialize=False)
    if commit_tmp_info:
        commit_tmp = json_loads(commit_tmp_info)
        return commit_tmp["tag"], commit_tmp["branch"]
    else:
        return None, "master"

def delete_commit_tmp(commit_id, data_table_namespace):
    version_tmp_table = get_commit_tmp_table(data_table_namespace=data_table_namespace)
    version_tmp_table.delete(commit_id)

def get_commit_tmp_table(data_table_namespace):
    version_tmp_table = eggroll.table(name=data_table_namespace, namespace="version_tmp",
                                      partition=1, create_if_missing=True, error_if_exist=False)
    return version_tmp_table

<|endoftext|>


<commit_before>#
# adventure module
#

# A "direction" is all the ways you can describe going some way
#
# adventure module
#

# A "direction" is all the ways you can describe going some way
directions = {}
NORTH = 1
SOUTH = 2
EAST = 3
WEST = 4
UP = 5
DOWN = 6
RIGHT = 7
LEFT = 8
IN = 9
OUT = 10
FORWARD = 11
BACK = 12
NORTH_WEST = 13
NORTH_EAST = 14
SOUTH_WEST = 15
SOUTH_EAST = 16
NOT_DIRECTION = -1

# map direction names to direction numbers
def define_direction( number, name ):
  # check to see if we are trying to redefine an existing direction
  if name in directions:
    print name, "is already defined as,", directions[name]
  directions[name] = number

# see if a word is a defined direction
def lookup_dir( d ):
  if d in directions:
    return directions[d]
  else:
    return NOT_DIRECTION

define_direction( NORTH, "north" )
define_direction( NORTH, "n" )
define_direction( SOUTH, "south" )
define_direction( SOUTH, "s" )
define_direction( EAST, "east" )
define_direction( EAST, "e" )
define_direction( WEST, "west" )
define_direction( WEST, "w" )
define_direction( UP, "up" )
define_direction( UP, "u" )
define_direction( DOWN, "down" )
define_direction( DOWN, "d" )
define_direction( RIGHT, "right" )
define_direction( RIGHT, "r" )
define_direction( LEFT, "left" )
define_direction( LEFT, "l" )
define_direction( IN, "in" )
define_direction( OUT, "out" )
define_direction( FORWARD, "forward" )
define_direction( FORWARD, "fd" )
define_direction( FORWARD, "fwd" )
define_direction( FORWARD, "f" )
define_direction( BACK, "back" )
define_direction( BACK, "bk" )
define_direction( BACK, "b" )
define_direction( NORTH_WEST, "nw" )
define_direction( NORTH_EAST, "ne" )
define_direction( SOUTH_WEST, "sw" )
define_direction( SOUTH_EAST, "se" )

articles = ['a', 'an', 'the']

# changes "lock" to "a lock", "apple" to "an apple", etc.
# note that no article should be added to proper names; store
# a global list of these somewhere?  For now we'll just assume
# anything starting with upper case is proper.
def add_article ( name ):
   consonants = "bcdfghjklmnpqrstvwxyz"
   vowels = "aeiou"
   if name and (name[0] in vowels):
      article = "an "
   elif name and (name[0] in consonants):
      article = "a "
   else:
      article = ""
   return "%s%s" % (article, name)

def proper_list_from_dict( d ):
  names = d.keys()
  buf = []
  name_count = len(names)
  for (i,name) in enumerate(names):
    if i != 0:
      buf.append(", " if name_count > 2 else " ")
    if i == name_count-1 and name_count > 1:
      buf.append("and ")
    buf.append(add_article(name))
  return "".join(buf)

class Thing(object):
  # name: short name of this thing
  # description: full description
  # fixed: is it stuck or can it be taken

  def __init__( self, name, desc, fixed=False ):
    self.name = name
    self.description = desc
    self.fixed = fixed

  def describe( self ):
    return self.name

# A "location" is a place in the game.
class Location(object):
  # name: short name of this location
  # description: full description
  # contents: things that are in a location
  # exits: ways to get out of a location
  # first_time: is it the first time here?
  # actors: other actors in the location
  # world: the world

  def __init__( self, name, desc, world ):
    self.name = name
    self.description = desc.strip()
    self.contents = {}
    self.exits = {}
    self.first_time = True
    self.verbs = {}
    self.actors = set()
    self.world = world

  def put( self, thing ):
    self.contents[thing.name] = thing

  def describe( self, force=False ):
    desc = ""   # start with a blank string

    # add the description
    if self.first_time or force:
      desc += self.description
      self.first_time = False

    # any things here?
    if self.contents:
      # add a newline so that the list starts on it's own line
      desc += "\n"

      # try to make a readable list of the things
      contents_description = proper_list_from_dict(self.contents)
      # is it just one thing?
      if len(self.contents) == 1:
        desc += "There is %s here." % contents_description
      else:
        desc += "There are a few things here: %s." % contents_description

    if self.actors:
      desc += "\n"
      for a in self.actors:
        desc += add_article(a.describe()).capitalize() + " is here.\n"

    return desc

  def add_exit( self, con, way ):
    self.exits[ way ] = con

  def go( self, way ):
    if way in self.exits:
      c = self.exits[ way ]
      return c.point_b
    else:
      return None

  def debug( self ):
    for key in exits:
      print "exit:", directions[key],

  def add_verb( self, verb, f ):
    self.verbs[' '.join(verb.split())] = f

  def get_verb( self, verb ):
    c = ' '.join(verb.split())
    if c in self.verbs:
       return self.verbs[c]
    else:
      return None

# A "connection" connects point A to point B. Connections are
# always described from the point of view of point A.
class Connection(object):
  # name
  # point_a
  # point_b

  def __init__( self, pa, name, pb ):
    self.name = name
    self.point_a = pa
    self.point_b = pb

# An actor in the world
class Actor(object):
  # world
  # location
  # inventory
  # moved
  # verbs

  def __init__( self, w, n, hero = False ):
    self.world = w
    self.location = None
    self.inventory = {}
    self.verbs = {}
    self.name = n
    self.cap_name = n.capitalize()
    self.hero = hero
    if hero:
      self.isare = "are"
    else:
      self.isare = "is"

  # describe ourselves
  def describe( self ):
    return self.name

  # establish where we are "now"
  def set_location( self, loc ):
    if not self.hero and self.location:
      self.location.actors.remove( self )
    self.location = loc
    self.moved = True
    if not self.hero:
      self.location.actors.add( self )

  # move a thing from the current location to our inventory
  def act_take( self, noun=None ):
    t = self.location.contents.pop(noun, None)
    if t:
      self.inventory[noun] = t
      return True
    else:
      print "%s can't take the %s." % (self.cap_name, noun)
      return False

  # move a thing from our inventory to the current location
  def act_drop( self, noun=None ):
    if not noun:
      return False
    t = self.inventory.pop(noun, None)
    if t:
      self.location.contents[noun] = t
      return True
    else:
      print "%s %s not carrying %s." % (self.cap_name, self.isare, add_article(noun))
      return False

  def act_look( self, noun=None ):
    print self.location.describe( True )
    return True

  # list the things we're carrying
  def act_inventory( self, noun=None ):
    msg = '%s %s carrying ' % (self.cap_name, self.isare)
    if self.inventory.keys():
      msg += proper_list_from_dict( self.inventory )
    else:
      msg += 'nothing'
    msg += '.'
    print msg
    return True

  # check/clear moved status
  def check_if_moved( self ):
    status = self.moved
    self.moved = False
    return status

  # try to go in a given direction
  def go( self, d ):
    loc = self.location.go( d )
    if loc == None:
      print "Bonk! %s can't seem to go that way." % self.name
      return False
    else:
      # update where we are
      self.set_location( loc )
      return True

  # define action verbs
  def define_action( self, verb, func ):
    self.verbs[verb] = func

  # return True on success, False on failure and None if the command isn't found.
  def perform_action( self, verb, noun=None ):
    verbs = []
    for v in self.verbs:
      if v.startswith(verb):
        verbs.append(v)
    if len(verbs) == 1:
      return self.verbs[verbs[0]]( noun )
    else:
      return None

  # do something
  def simple_act( self, verb ):
    # try direction
    d = lookup_dir( verb )
    if d != NOT_DIRECTION:
      return self.go( d )
    verbs = []
    for v in self.verbs:
      if v.startswith(verb):
        verbs.append(v)
    # try prefix match
    return self.perform_action( verb )

  # do something to something
  def act( self, verb, noun ):
    # "go" is a special case
    if verb == 'go':
      return self.simple_act( noun )
    else:
      return self.perform_action( verb, noun )

  # do something and report if the command is not found.
  def do_act( self, verb, noun ):
    if self.act( verb, noun ) == None:
      print "Huh?"

  def add_verb( self, verb, f ):
    self.verbs[' '.join(verb.split())] = f

  def get_verb( self, verb ):
    c = ' '.join(verb.split())
    if c in self.verbs:
       return self.verbs[c]
    else:
      return None

class Hero(Actor):

  def __init__( self, w ):
    super(Hero, self).__init__(w, "you", True)
    # associate each of the known actions with functions
    self.verbs['take'] = self.act_take
    self.verbs['get'] = self.act_take
    self.verbs['drop'] = self.act_drop
    self.verbs['inventory'] = self.act_inventory
    self.verbs['look'] = self.act_look

  def add_verb( self, name, f ):
      self.verbs[name] = (lambda self: lambda *args : f(self, *args))(self)

# a World is how all the locations, things, and connections are organized
class World(object):
  # locations

  def __init__ ( self ):
    self.locations = {}
    self.turn_hooks = set()

  # make a connection between point A and point B
  def connect( self, point_a, name, point_b, way ):
    c = Connection( point_a, name, point_b )
    point_a.add_exit( c, way )
    return c

  # make a bidirectional between point A and point B
  def biconnect( self, point_a, point_b, name, ab_way, ba_way ):
    c1 = Connection( point_a, name, point_b )
    if isinstance(ab_way, (list, tuple)):
      for way in ab_way:
        point_a.add_exit( c1, way )
    else:
      point_a.add_exit( c1, ab_way )
    c2 = Connection( point_b, name, point_a )
    if isinstance(ba_way, (list, tuple)):
      for way in ba_way:
        point_b.add_exit( c2, way )
    else:
      point_b.add_exit( c2, ba_way )
    return c1, c2

  # add another location to the world
  def add_location( self, name, description ):
    l = Location( name, description, self )
    self.locations[name] = l
    return l

  # add an actor to the world
  def add_actor( self, name, loc ):
    a = Actor( self, name )
    a.set_location( loc )
    return a

  # a hero to the world
  def add_hero( self ):
    return Hero( self )

  def add_turn_hook( self, h ):
    self.turn_hooks.add( h )

  def call_turn_hooks( self ):
    for h in self.turn_hooks:
      h(self)

def do_say(s):
  print s
  return True

def say(s):
  return (lambda s: lambda *args: do_say(s))(s)

def run_game( hero ):
  while True:
    hero.world.call_turn_hooks()

    # if the hero moved, describe the room
    if hero.check_if_moved():
      print
      print "        --=( %s )=--" % hero.location.name
      where = hero.location.describe()
      if where:
        print where

    # get input from the user
    try:
      command = raw_input("> ")
    except EOFError:
      break
    if command == 'q' or command == 'quit':
       break
    words = command.split()
    if not words:
      continue

    f = hero.location.get_verb( words[0] )
    if f:
      if f( hero.location, words ):
        continue

    for a in hero.location.actors:
      f = a.get_verb( words[0] )
      if f:
        if f( a, words ):
          continue

    verb = words[0]
    # treat 'verb noun1 and noun2..' as 'verb noun1' then 'verb noun2'
    # treat 'verb noun1, noun2...' as 'verb noun1' then 'verb noun2'
    if len( words ) > 2:
      for noun in words[1:]:
        noun = noun.strip(',')
        if noun in articles: continue
        if noun == 'and': continue
        hero.do_act( verb, noun )
      continue

    # try to do what the user says
    if len( words ) == 2:
      # action object
      # e.g. take key
      verb, noun = words
      hero.do_act( verb, noun )
      continue

    assert len( words ) == 1
    # action (implied object/subject)
    # e.g. north
    hero.do_act( "go", verb )
<commit_msg>interm<commit_after>#
# adventure module
#

# A "direction" is all the ways you can describe going some way
#
# adventure module
#

# A "direction" is all the ways you can describe going some way
directions = {}
NORTH = 1
SOUTH = 2
EAST = 3
WEST = 4
UP = 5
DOWN = 6
RIGHT = 7
LEFT = 8
IN = 9
OUT = 10
FORWARD = 11
BACK = 12
NORTH_WEST = 13
NORTH_EAST = 14
SOUTH_WEST = 15
SOUTH_EAST = 16
NOT_DIRECTION = -1

# map direction names to direction numbers
def define_direction( number, name ):
  # check to see if we are trying to redefine an existing direction
  if name in directions:
    print name, "is already defined as,", directions[name]
  directions[name] = number

# see if a word is a defined direction
def lookup_dir( d ):
  if d in directions:
    return directions[d]
  else:
    return NOT_DIRECTION

define_direction( NORTH, "north" )
define_direction( NORTH, "n" )
define_direction( SOUTH, "south" )
define_direction( SOUTH, "s" )
define_direction( EAST, "east" )
define_direction( EAST, "e" )
define_direction( WEST, "west" )
define_direction( WEST, "w" )
define_direction( UP, "up" )
define_direction( UP, "u" )
define_direction( DOWN, "down" )
define_direction( DOWN, "d" )
define_direction( RIGHT, "right" )
define_direction( RIGHT, "r" )
define_direction( LEFT, "left" )
define_direction( LEFT, "l" )
define_direction( IN, "in" )
define_direction( OUT, "out" )
define_direction( FORWARD, "forward" )
define_direction( FORWARD, "fd" )
define_direction( FORWARD, "fwd" )
define_direction( FORWARD, "f" )
define_direction( BACK, "back" )
define_direction( BACK, "bk" )
define_direction( BACK, "b" )
define_direction( NORTH_WEST, "nw" )
define_direction( NORTH_EAST, "ne" )
define_direction( SOUTH_WEST, "sw" )
define_direction( SOUTH_EAST, "se" )

articles = ['a', 'an', 'the']

# changes "lock" to "a lock", "apple" to "an apple", etc.
# note that no article should be added to proper names; store
# a global list of these somewhere?  For now we'll just assume
# anything starting with upper case is proper.
def add_article ( name ):
   consonants = "bcdfghjklmnpqrstvwxyz"
   vowels = "aeiou"
   if name and (name[0] in vowels):
      article = "an "
   elif name and (name[0] in consonants):
      article = "a "
   else:
      article = ""
   return "%s%s" % (article, name)

def proper_list_from_dict( d ):
  names = d.keys()
  buf = []
  name_count = len(names)
  for (i,name) in enumerate(names):
    if i != 0:
      buf.append(", " if name_count > 2 else " ")
    if i == name_count-1 and name_count > 1:
      buf.append("and ")
    buf.append(add_article(name))
  return "".join(buf)

class Thing(object):
  # name: short name of this thing
  # description: full description
  # fixed: is it stuck or can it be taken

  def __init__( self, name, desc, fixed=False ):
    self.name = name
    self.description = desc
    self.fixed = fixed

  def describe( self ):
    return self.name

# A "location" is a place in the game.
class Location(object):
  # name: short name of this location
  # description: full description
  # contents: things that are in a location
  # exits: ways to get out of a location
  # first_time: is it the first time here?
  # actors: other actors in the location
  # world: the world

  def __init__( self, name, desc, world ):
    self.name = name
    self.description = desc.strip()
    self.contents = {}
    self.exits = {}
    self.first_time = True
    self.verbs = {}
    self.actors = set()
    self.world = world

  def put( self, thing ):
    self.contents[thing.name] = thing

  def describe( self, force=False ):
    desc = ""   # start with a blank string

    # add the description
    if self.first_time or force:
      desc += self.description
      self.first_time = False

    # any things here?
    if self.contents:
      # add a newline so that the list starts on it's own line
      desc += "\n"

      # try to make a readable list of the things
      contents_description = proper_list_from_dict(self.contents)
      # is it just one thing?
      if len(self.contents) == 1:
        desc += "There is %s here." % contents_description
      else:
        desc += "There are a few things here: %s." % contents_description

    if self.actors:
      desc += "\n"
      for a in self.actors:
        desc += add_article(a.describe()).capitalize() + " is here.\n"

    return desc

  def add_exit( self, con, way ):
    self.exits[ way ] = con

  def go( self, way ):
    if way in self.exits:
      c = self.exits[ way ]
      return c.point_b
    else:
      return None

  def debug( self ):
    for key in exits:
      print "exit:", directions[key],

  def add_verb( self, verb, f ):
    self.verbs[' '.join(verb.split())] = f

  def get_verb( self, verb ):
    c = ' '.join(verb.split())
    if c in self.verbs:
       return self.verbs[c]
    else:
      return None

# A "connection" connects point A to point B. Connections are
# always described from the point of view of point A.
class Connection(object):
  # name
  # point_a
  # point_b

  def __init__( self, pa, name, pb ):
    self.name = name
    self.point_a = pa
    self.point_b = pb

# An actor in the world
class Actor(object):
  # world
  # location
  # inventory
  # moved
  # verbs

  def __init__( self, w, n, hero = False ):
    self.world = w
    self.location = None
    self.inventory = {}
    self.verbs = {}
    self.name = n
    self.cap_name = n.capitalize()
    self.hero = hero
    if hero:
      self.isare = "are"
    else:
      self.isare = "is"

  # describe ourselves
  def describe( self ):
    return self.name

  # establish where we are "now"
  def set_location( self, loc ):
    if not self.hero and self.location:
      self.location.actors.remove( self )
    self.location = loc
    self.moved = True
    if not self.hero:
      self.location.actors.add( self )

  # move a thing from the current location to our inventory
  def act_take( self, noun=None ):
    t = self.location.contents.pop(noun, None)
    if t:
      self.inventory[noun] = t
      return True
    else:
      print "%s can't take the %s." % (self.cap_name, noun)
      return False

  # move a thing from our inventory to the current location
  def act_drop( self, noun=None ):
    if not noun:
      return False
    t = self.inventory.pop(noun, None)
    if t:
      self.location.contents[noun] = t
      return True
    else:
      print "%s %s not carrying %s." % (self.cap_name, self.isare, add_article(noun))
      return False

  def act_look( self, noun=None ):
    print self.location.describe( True )
    return True

  # list the things we're carrying
  def act_inventory( self, noun=None ):
    msg = '%s %s carrying ' % (self.cap_name, self.isare)
    if self.inventory.keys():
      msg += proper_list_from_dict( self.inventory )
    else:
      msg += 'nothing'
    msg += '.'
    print msg
    return True

  # check/clear moved status
  def check_if_moved( self ):
    status = self.moved
    self.moved = False
    return status

  # try to go in a given direction
  def go( self, d ):
    loc = self.location.go( d )
    if loc == None:
      print "Bonk! %s can't seem to go that way." % self.name
      return False
    else:
      # update where we are
      self.set_location( loc )
      return True

  # define action verbs
  def define_action( self, verb, func ):
    self.verbs[verb] = func

  # return True on success, False on failure and None if the command isn't found.
  def perform_action( self, verb, noun=None ):
    verbs = []
    for v in self.verbs:
      if v.startswith(verb):
        verbs.append(v)
    if len(verbs) == 1:
      return self.verbs[verbs[0]]( noun )
    else:
      return None

  # do something
  def simple_act( self, verb ):
    # try direction
    d = lookup_dir( verb )
    if d != NOT_DIRECTION:
      return self.go( d )
    verbs = []
    for v in self.verbs:
      if v.startswith(verb):
        verbs.append(v)
    # try prefix match
    return self.perform_action( verb )

  # do something to something
  def act( self, verb, noun ):
    # "go" is a special case
    if verb == 'go':
      return self.simple_act( noun )
    else:
      return self.perform_action( verb, noun )

  # do something and report if the command is not found.
  def do_act( self, verb, noun ):
    if self.act( verb, noun ) == None:
      print "Huh?"

  def add_verb( self, verb, f ):
    self.verbs[' '.join(verb.split())] = f

  def get_verb( self, verb ):
    c = ' '.join(verb.split())
    if c in self.verbs:
       return self.verbs[c]
    else:
      return None

class Hero(Actor):

  def __init__( self, w ):
    super(Hero, self).__init__(w, "you", True)
    # associate each of the known actions with functions
    self.verbs['take'] = self.act_take
    self.verbs['get'] = self.act_take
    self.verbs['drop'] = self.act_drop
    self.verbs['inventory'] = self.act_inventory
    self.verbs['look'] = self.act_look

  def add_verb( self, name, f ):
      self.verbs[name] = (lambda self: lambda *args : f(self, *args))(self)

# a World is how all the locations, things, and connections are organized
class World(object):
  # locations

  def __init__ ( self ):
    self.locations = {}
    self.turn_hooks = set()

  # make a connection between point A and point B
  def connect( self, point_a, name, point_b, way ):
    c = Connection( point_a, name, point_b )
    point_a.add_exit( c, way )
    return c

  # make a bidirectional between point A and point B
  def biconnect( self, point_a, point_b, name, ab_way, ba_way ):
    c1 = Connection( point_a, name, point_b )
    if isinstance(ab_way, (list, tuple)):
      for way in ab_way:
        point_a.add_exit( c1, way )
    else:
      point_a.add_exit( c1, ab_way )
    c2 = Connection( point_b, name, point_a )
    if isinstance(ba_way, (list, tuple)):
      for way in ba_way:
        point_b.add_exit( c2, way )
    else:
      point_b.add_exit( c2, ba_way )
    return c1, c2

  # add another location to the world
  def add_location( self, name, description ):
    l = Location( name, description, self )
    self.locations[name] = l
    return l

  # add an actor to the world
  def add_actor( self, name, loc ):
    a = Actor( self, name )
    a.set_location( loc )
    return a

  # a hero to the world
  def add_hero( self ):
    return Hero( self )

  def add_turn_hook( self, h ):
    self.turn_hooks.add( h )

  def call_turn_hooks( self ):
    for h in self.turn_hooks:
      h(self)

def do_say(s):
  print s
  return True

def say(s):
  return (lambda s: lambda *args: do_say(s))(s)

def run_game( hero ):
  while True:
    hero.world.call_turn_hooks()

    # if the hero moved, describe the room
    if hero.check_if_moved():
      print
      print "        --=( %s )=--" % hero.location.name
      where = hero.location.describe()
      if where:
        print where

    # get input from the user
    try:
      command = raw_input("> ")
    except EOFError:
      break
    if command == 'q' or command == 'quit':
       break
    words = command.split()
    if not words:
      continue

    f = hero.location.get_verb( words[0] )
    if f:
      if f( hero.location, words ):
        continue

    done = False  # sadly, python doesn't have break with a label
    for a in hero.location.actors:
      f = a.get_verb( words[0] )
      if f:
        if f( a, words ):
          done = True
          break
    if done:
      continue

    verb = words[0]
    # treat 'verb noun1 and noun2..' as 'verb noun1' then 'verb noun2'
    # treat 'verb noun1, noun2...' as 'verb noun1' then 'verb noun2'
    if len( words ) > 2:
      for noun in words[1:]:
        noun = noun.strip(',')
        if noun in articles: continue
        if noun == 'and': continue
        hero.do_act( verb, noun )
      continue

    # try to do what the user says
    if len( words ) == 2:
      # action object
      # e.g. take key
      verb, noun = words
      hero.do_act( verb, noun )
      continue

    assert len( words ) == 1
    # action (implied object/subject)
    # e.g. north
    hero.do_act( "go", verb )
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

import re
from datetime import datetime
import pytz
from functools import wraps
from neomodel import db as transaction
from py2neo.error import GraphError
from py2neo.cypher.error.schema import ConstraintViolation
from neomodel.exception import RequiredProperty
from neomodel.exception import UniqueProperty
from restapi.resources.exceptions import RestApiException
from restapi.resources.base import ExtendedApiResource
from commons import htmlcodes as hcodes

from commons.logs import get_logger
logger = get_logger(__name__)

__author__ = "Mattia D'Antonio (m.dantonio@cineca.it)"

class GraphBaseOperations(ExtendedApiResource):

    def initGraph(self):
        self.graph = self.global_get_service('neo4j')
        self._current_user = self.getLoggedUserInstance()

    def getSingleLinkedNode(self, relation):

        nodes = relation.all()
        if len(nodes) <= 0:
            return None
        return nodes[0]

    def getLoggedUserInstance(self):
        user = self.get_current_user()
        if user is None:
            return None
        try:
            return self.graph.User.nodes.get(email=user.email)
        except self.graph.User.DoesNotExist:
            return None

    def getNode(self, Model, accession, field='accession'):

        try:

            if field == 'accession':
                return Model.nodes.get(accession=accession)

            if field == 'id':
                return Model.nodes.get(id=accession)

            if field == 'taxon_id':
                return Model.nodes.get(taxon_id=accession)

            # if Model == self.graph.Organism:
            #     return Model.nodes.get(taxon_id=int(accession))

            return Model.nodes.get(accession=accession)
        except Model.DoesNotExist:
            return None

    def countNodes(self, type):
        query = "MATCH (a: " + type + ") RETURN count(a) as count"

        records = self.graph.cypher(query)
        for record in records:
            if (record is None):
                return 0
            if (record.count is None):
                return 0

        return record.count

    def getCurrentDate(self):
        return datetime.now(pytz.utc)

    # HANDLE INPUT PARAMETERS

    def readProperty(self, schema, values, checkRequired=True):

        properties = {}
        for field in schema:
            if 'islink' in field:
                continue

            k = field["key"]
            if k in values:
                properties[k] = values[k]

            # this field is missing but required!
            elif checkRequired and field["required"] == "true":
                raise myGraphError(
                    'Missing field: %s' % k,
                    status_code=hcodes.HTTP_BAD_REQUEST)

        return properties

    def updateProperties(self, instance, schema, properties):

        for field in schema:
            if 'islink' in field:
                continue
            key = field["key"]
            if key in properties:
                instance.__dict__[key] = properties[key]

    def parseAutocomplete(
            self, properties, key, id_key='value', split_char=None):
        value = properties.get(key, None)

        ids = []

        if value is None:
            return ids

        # Multiple autocomplete
        if type(value) is list:
            for v in value:
                if v is None:
                    return None
                if id_key in v:
                    ids.append(v[id_key])
                else:
                    ids.append(v)
            return ids

        # Single autocomplete
        if id_key in value:
            return [value[id_key]]

        # Command line input
        if split_char is None:
            return [value]

        return value.split(split_char)

class myGraphError(RestApiException):
    status_code = None

    def __init__(self, exception, status_code=hcodes.HTTP_BAD_NOTFOUND):
        super(myGraphError).__init__()
        self.status_code = status_code

def returnError(self, label, error, code=hcodes.HTTP_BAD_NOTFOUND):
    error = str(error)
    logger.error(error)
    return self.force_response(errors={label: error}, code=code)

def graph_transactions(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):

        try:

            logger.debug("Neomodel transaction BEGIN")
            transaction.begin()

            out = func(self, *args, **kwargs)

            logger.debug("Neomodel transaction COMMIT")
            transaction.commit()

            return out
        except Exception as e:
            logger.debug("Neomodel transaction ROLLBACK")
            try:
                # Starting from neo4j 2.3.0 ClientErrors automatically
                # rollback transactions and raise a 404 error:
                # HTTP DELETE returned response 404
                # https://github.com/neo4j/neo4j/issues/5806

                transaction.rollback()
            except Exception as rollback_exp:
                logger.warning(
                    "Exception raised during rollback: %s" % rollback_exp)
            raise e

    return wrapper

def catch_graph_exceptions(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):

        try:
            return func(self, *args, **kwargs)
        except (myGraphError) as e:
            if e.status_code == hcodes.HTTP_BAD_FORBIDDEN:
                label = 'Forbidden'
            elif e.status_code == hcodes.HTTP_BAD_NOTFOUND:
                label = 'Not found'
            else:
                label = 'Bad request'
            return returnError(self, label, e, code=e.status_code)

        except (UniqueProperty) as e:

            prefix = "Node [0-9]+ already exists with label"
            regExpr = "%s (.+) and property (.+)" % prefix
            m = re.search(regExpr, str(e))
            if m:
                node = m.group(1)
                prop = m.group(2)
                parsedError = "A %s already exist with %s" % (node, prop)
            else:
                parsedError = e

            return returnError(
                self, 'Duplicated property',
                parsedError, code=hcodes.HTTP_BAD_CONFLICT)
        except ConstraintViolation as e:
            return returnError(self, 'DB', e)
        except (GraphError) as e:
            # Also returned for duplicated fields...
            # UniqueProperty not catched?
            return returnError(self, 'DB', e)
        except (RequiredProperty) as e:
            return returnError(self, 'DB', e)

    return wrapper
<commit_msg>Added utility functions<commit_after># -*- coding: utf-8 -*-

import re
from datetime import datetime
import pytz
from functools import wraps
from neomodel import db as transaction
from py2neo.error import GraphError
from py2neo.cypher.error.schema import ConstraintViolation
from neomodel.exception import RequiredProperty
from neomodel.exception import UniqueProperty
from restapi.resources.exceptions import RestApiException
from restapi.resources.base import ExtendedApiResource
from commons import htmlcodes as hcodes

from commons.logs import get_logger
logger = get_logger(__name__)

__author__ = "Mattia D'Antonio (m.dantonio@cineca.it)"

class GraphBaseOperations(ExtendedApiResource):

    def initGraph(self):
        self.graph = self.global_get_service('neo4j')
        self._current_user = self.getLoggedUserInstance()

    def getSingleLinkedNode(self, relation):

        nodes = relation.all()
        if len(nodes) <= 0:
            return None
        return nodes[0]

    def getLoggedUserInstance(self):
        user = self.get_current_user()
        if user is None:
            return None
        try:
            return self.graph.User.nodes.get(email=user.email)
        except self.graph.User.DoesNotExist:
            return None

    def getNode(self, Model, accession, field='accession'):

        try:

            if field == 'accession':
                return Model.nodes.get(accession=accession)

            if field == 'id':
                return Model.nodes.get(id=accession)

            if field == 'taxon_id':
                return Model.nodes.get(taxon_id=accession)

            # if Model == self.graph.Organism:
            #     return Model.nodes.get(taxon_id=int(accession))

            return Model.nodes.get(accession=accession)
        except Model.DoesNotExist:
            return None

    def countNodes(self, type):
        query = "MATCH (a: " + type + ") RETURN count(a) as count"

        records = self.graph.cypher(query)
        for record in records:
            if (record is None):
                return 0
            if (record.count is None):
                return 0

        return record.count

    def getCurrentDate(self):
        return datetime.now(pytz.utc)

    # HANDLE INPUT PARAMETERS

    @staticmethod
    def createUniqueIndex(*var):

        separator = "#_#"
        return separator.join(var)

    def readProperty(self, schema, values, checkRequired=True):

        properties = {}
        for field in schema:
            if 'islink' in field:
                continue

            k = field["key"]
            if k in values:
                properties[k] = values[k]

            # this field is missing but required!
            elif checkRequired and field["required"] == "true":
                raise myGraphError(
                    'Missing field: %s' % k,
                    status_code=hcodes.HTTP_BAD_REQUEST)

        return properties

    def updateProperties(self, instance, schema, properties):

        for field in schema:
            if 'islink' in field:
                continue
            key = field["key"]
            if key in properties:
                instance.__dict__[key] = properties[key]

    def parseAutocomplete(
            self, properties, key, id_key='value', split_char=None):
        value = properties.get(key, None)

        ids = []

        if value is None:
            return ids

        # Multiple autocomplete
        if type(value) is list:
            for v in value:
                if v is None:
                    return None
                if id_key in v:
                    ids.append(v[id_key])
                else:
                    ids.append(v)
            return ids

        # Single autocomplete
        if id_key in value:
            return [value[id_key]]

        # Command line input
        if split_char is None:
            return [value]

        return value.split(split_char)

class myGraphError(RestApiException):
    status_code = None

    def __init__(self, exception, status_code=hcodes.HTTP_BAD_NOTFOUND):
        super(myGraphError).__init__()
        self.status_code = status_code

def returnError(self, label, error, code=hcodes.HTTP_BAD_NOTFOUND):
    error = str(error)
    logger.error(error)
    return self.force_response(errors={label: error}, code=code)

def graph_transactions(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):

        try:

            logger.debug("Neomodel transaction BEGIN")
            transaction.begin()

            out = func(self, *args, **kwargs)

            logger.debug("Neomodel transaction COMMIT")
            transaction.commit()

            return out
        except Exception as e:
            logger.debug("Neomodel transaction ROLLBACK")
            try:
                # Starting from neo4j 2.3.0 ClientErrors automatically
                # rollback transactions and raise a 404 error:
                # HTTP DELETE returned response 404
                # https://github.com/neo4j/neo4j/issues/5806

                transaction.rollback()
            except Exception as rollback_exp:
                logger.warning(
                    "Exception raised during rollback: %s" % rollback_exp)
            raise e

    return wrapper

def catch_graph_exceptions(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):

        try:
            return func(self, *args, **kwargs)
        except (myGraphError) as e:
            if e.status_code == hcodes.HTTP_BAD_FORBIDDEN:
                label = 'Forbidden'
            elif e.status_code == hcodes.HTTP_BAD_NOTFOUND:
                label = 'Not found'
            else:
                label = 'Bad request'
            return returnError(self, label, e, code=e.status_code)

        except (UniqueProperty) as e:

            prefix = "Node [0-9]+ already exists with label"
            regExpr = "%s (.+) and property (.+)" % prefix
            m = re.search(regExpr, str(e))
            if m:
                node = m.group(1)
                prop = m.group(2)
                parsedError = "A %s already exist with %s" % (node, prop)
            else:
                parsedError = e

            return returnError(
                self, 'Duplicated property',
                parsedError, code=hcodes.HTTP_BAD_CONFLICT)
        except ConstraintViolation as e:
            return returnError(self, 'DB', e)
        except (GraphError) as e:
            # Also returned for duplicated fields...
            # UniqueProperty not catched?
            return returnError(self, 'DB', e)
        except (RequiredProperty) as e:
            return returnError(self, 'DB', e)

    return wrapper
<|endoftext|>


<commit_before>from dragonfly import (Grammar, MappingRule, Choice, Text, Key, Function)
from dragonglue.command import send_command

grammar = Grammar("launch")

applications = {
	'sublime': 'sublime subl',
    'pycharm': 'pycharm /opt/pycharm/bin/pycharm.sh',
    'chrome': 'chromium /usr/bin/chromium-browser',
    'spotify': 'spotify /home/dan/bin/spotify',
}

# aliases
applications['charm'] = applications['pycharm']

def Command(cmd):
    def ex(application=''):
        # print 'execute', cmd + application
        send_command(cmd + application)

    return Function(ex)

launch_rule = MappingRule(
    name="launch",
    mapping={
        'Do run': Key('w-r'),

        'get <application>': Command('/home/dan/bin/get_app.sh '),

        'get (termie | terminal)': Command('xfce4-terminal --drop-down'),

        '(touch | refresh) multi-edit': Command('touch /home/dan/source/voice/natlink/commands/_multiedit.py'),
    },
    extras=[
    	Choice('application', applications)
    ]
)

grammar.add_rule(launch_rule)
grammar.load()

def unload():
    global grammar
    if grammar: grammar.unload()
    grammar = None
<commit_msg>get/launch applications using Linux keymap<commit_after>from dragonfly import (Grammar, MappingRule, Choice, Text, Key, Function)
from dragonglue.command import send_command

grammar = Grammar("launch")

applications = {
	'sublime': 'w-s',
    'pycharm': 'w-d',
    'chrome': 'w-f',
    'logs': 'w-j',
    'SQL': 'w-k',
    'IPython': 'w-l',
    'shell': 'w-semicolon',
    # 'spotify': 'spotify /home/dan/bin/spotify',
}

# aliases
applications['charm'] = applications['pycharm']

def Command(cmd):
    def ex(application=''):
        # print 'execute', cmd + application
        send_command(cmd + application)

    return Function(ex)

launch_rule = MappingRule(
    name="launch",
    mapping={
        'Do run': Key('w-r'),

        'get <application>': Key('%(application)s'),

        'get (termie | terminal)': Command('xfce4-terminal --drop-down'),

        '(touch | refresh) multi-edit': Command('touch /home/dan/source/voice/natlink/commands/_multiedit.py'),
    },
    extras=[
    	Choice('application', applications)
    ]
)

grammar.add_rule(launch_rule)
grammar.load()

def unload():
    global grammar
    if grammar: grammar.unload()
    grammar = None
<|endoftext|>


<commit_before>from django.test import TestCase as DjangoTestCase
import fudge
from django.db import models

# Backport override_settings from Django 1.4
try:
    from django.test.utils import override_settings
except ImportError:
    from .backports import override_settings

class ArmstrongTestCase(DjangoTestCase):
    def setUp(self):
        fudge.clear_expectations()
        fudge.clear_calls()

    if not hasattr(DjangoTestCase, 'settings'):
        # backported from Django 1.4
        def settings(self, **kwargs):
            """
            A context manager that temporarily sets a setting and reverts
            back to the original value when exiting the context.

            .. seealso: https://github.com/django/django/blob/0d670682952fae585ce5c5ec5dc335bd61d66bb2/django/test/testcases.py#L349-354
            """
            return override_settings(**kwargs)

    def assertRelatedTo(self, model, field_name, related_model, many=False):
        if many is False:
            through = models.ForeignKey
        else:
            through = models.ManyToManyField

        # sanity check
        self.assertModelHasField(model, field_name, through)

        field = model._meta.get_field_by_name(field_name)[0]
        self.assertEqual(field.rel.to, related_model)

    def assertModelHasField(self, model, field_name, field_class=None):
        msg = "%s does not have a field named %s" % (model.__class__.__name__,
                field_name)
        self.assertTrue(hasattr(model, field_name), msg=msg)
        field = model._meta.get_field_by_name(field_name)[0]
        if field_class is not None:
            msg = "%s.%s is not a %s" % (model.__class__.__name__, field_name,
                    field_class.__class__.__name__)
            self.assertTrue(isinstance(field, field_class), msg=msg)

    def assertNone(self, obj, **kwargs):
        self.assertTrue(obj is None, **kwargs)

    def assertIsA(self, obj, cls, **kwargs):
        self.assertTrue(isinstance(obj, cls), **kwargs)

    def assertDoesNotHave(self, obj, attr, **kwargs):
        self.assertFalse(hasattr(obj, attr), **kwargs)
<commit_msg>Use the native `assertIsNone()` http://docs.python.org/2.7/library/unittest.html#unittest.TestCase.assertIsNone<commit_after>from django.test import TestCase as DjangoTestCase
import fudge
from django.db import models

# Backport override_settings from Django 1.4
try:
    from django.test.utils import override_settings
except ImportError:
    from .backports import override_settings

class ArmstrongTestCase(DjangoTestCase):
    def setUp(self):
        fudge.clear_expectations()
        fudge.clear_calls()

    if not hasattr(DjangoTestCase, 'settings'):
        # backported from Django 1.4
        def settings(self, **kwargs):
            """
            A context manager that temporarily sets a setting and reverts
            back to the original value when exiting the context.

            .. seealso: https://github.com/django/django/blob/0d670682952fae585ce5c5ec5dc335bd61d66bb2/django/test/testcases.py#L349-354
            """
            return override_settings(**kwargs)

    def assertRelatedTo(self, model, field_name, related_model, many=False):
        if many is False:
            through = models.ForeignKey
        else:
            through = models.ManyToManyField

        # sanity check
        self.assertModelHasField(model, field_name, through)

        field = model._meta.get_field_by_name(field_name)[0]
        self.assertEqual(field.rel.to, related_model)

    def assertModelHasField(self, model, field_name, field_class=None):
        msg = "%s does not have a field named %s" % (model.__class__.__name__,
                field_name)
        self.assertTrue(hasattr(model, field_name), msg=msg)
        field = model._meta.get_field_by_name(field_name)[0]
        if field_class is not None:
            msg = "%s.%s is not a %s" % (model.__class__.__name__, field_name,
                    field_class.__class__.__name__)
            self.assertTrue(isinstance(field, field_class), msg=msg)

    def assertIsA(self, obj, cls, **kwargs):
        self.assertTrue(isinstance(obj, cls), **kwargs)

    def assertDoesNotHave(self, obj, attr, **kwargs):
        self.assertFalse(hasattr(obj, attr), **kwargs)
<|endoftext|>