<commit_before>import json
from abc import ABCMeta
from concurrent.futures import ThreadPoolExecutor
from enum import Enum

import tornado
import tornado.web
from torngithub import json_decode

from user_account_helpers import *

MAX_WORKERS = 16

class Endpoint(Enum):
    """
    An Enum to distinguish push from pull APIs.
    Push APIs need to validate the user's API key.
    """

    PUSH_API = 1
    PULL_API = 2

class BaseHandler(tornado.web.RequestHandler):
    """
    A handler that all Brainspell handlers should extend.

    All class names should be CamelCase.

    JSON endpoints should:
    1) be named [*]EndpointHandler,
    2) specify the "parameters" dictionary,
    3) override the "process" function, and
    4) specify the "endpoint_type" using the Endpoint enum.

    The resulting API endpoint will be the hyphenated form of the name.
    e.g., SplitTableEndpointHandler => /json/split-table

    You can view the parameters for any JSON endpoint at /json/*/help.
    e.g., /json/split-table/help

    Specifying the "parameters" dictionary:

    parameters ::= {
        parameter_name: {
            "type": parseFn
        }
        ...
    }

    where "type" is a key mapped to a function that can be used to parse
    a string into the desired type. e.g.,
    parseFn ::= str | int | float | json.loads | ...

    If a parameter is optional, you can indicate that by including a default value:

    parameters ::= {
        parameter_name: {
            "type": int,
            "default": 0
        }
        ...
    }

    The "process" function:

    "process" function signature:
    def process(self, response, args)

    By default, "response" is a dictionary that contains a key
    called "success" with a value of 1. The process function should
    mutate the "response" dictionary as necessary and return it (unless
    it is an asynchronous endpoint, described below).

    "args" is a dictionary with parameter values, such that the keys
    are those specified in the "parameters" dictionary.

    The "endpoint_type" enum:

    endpoint_type ::= Endpoint.PULL_API | Endpoint.PUSH_API

    If "endpoint_type" is set to Endpoint.PUSH_API, then there
    will be one additional required parameter: the "key" parameter,
    which is the user's API key. This key will be automatically validated
    before the "process" function is called, and it will be included in
    the "args" dict.

    Asynchronous endpoints:
    If your endpoint is going to block the main thread for a reasonable
    period of time, please make it asynchronous. It's as easy as setting
    the "asynchronous" boolean, decorating your "process" function with
    @tornado.gen.coroutine, and calling self.finish_async when your
    function finishes execution (MANDATORY). Then, any blocking code
    should be decorated with @run_on_executor.

    asynchronous :: True | False

    @run_on_executor
    def blocker(self):
        # blocking code here
        ...

    @tornado.gen.coroutine
    def process(self, response, args):
        blocked_result = yield self.blocker()
        ...
        self.finish_async(response)

    Web interface handlers should be named [*]Handler, and use the
    "render_with_user_info" function (rather than self.render).

    The following variables will be included for use by the Tornado
    HTML template:
    - "github_name"
    - "github_username"
    - "github_avatar"
    - "github_access_token"
    - "api_key"
    """

    parameters = None
    endpoint_type = None
    process = None

    asynchronous = False
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)

    def get_safe_arguments(self, arguments_dict, accessor):
        """ Enforce type safety; do not verify API key. """

        args = {}
        for k in self.parameters:
            if k not in arguments_dict:
                if "default" not in self.parameters[k]:
                    return {
                        "success": 0,
                        "description": "Missing required parameter: " + k
                    }
                else:
                    args[k] = self.parameters[k]["type"](
                        self.parameters[k]["default"])
            else:
                try:
                    args[k] = self.parameters[k]["type"](accessor(k))
                except BaseException:
                    return {
                        "success": 0,
                        "description": "Bad input for argument (type " +
                        self.parameters[k]["type"].__name__ +
                        "): " +
                        k
                    }

        if self.endpoint_type == Endpoint.PUSH_API or (
                "key" in self.request.arguments):
            try:
                args["key"] = str(accessor("key"))
            except BaseException:
                args["key"] = ""

        return {
            "success": 1,
            "args": args
        }

    @tornado.gen.coroutine
    @tornado.web.asynchronous
    def get(self):
        """
        Provide a guarantee for a valid API key on PUSH endpoints,
        documentation at /help, and type-checked arguments.
        """

        assert self.endpoint_type, "You must indicate what type of endpoint this is by setting the endpoint_type variable."
        self.set_header("Content-Type", "application/json")

        assert self.parameters is not None, "You haven't indicated the parameters for this endpoint."

        # provide help documentation
        components = [x for x in self.request.path.split("/") if x]
        if len(components) >= 3 and components[2] == "help":
            formatted_parameters = {}
            for p in self.parameters:
                formatted_parameters[p] = {}
                if "default" not in self.parameters[p]:
                    formatted_parameters[p]["required"] = True
                else:
                    formatted_parameters[p]["required"] = False
                    formatted_parameters[p]["default"] = self.parameters[p]["default"]
                type_name = self.parameters[p]["type"].__name__
                if type_name == "loads":  # account for loads function
                    type_name = "json"
                formatted_parameters[p]["type"] = type_name
                if "description" in self.parameters[p]:
                    formatted_parameters[p]["description"] = self.parameters[p]["description"]
            if self.endpoint_type == Endpoint.PUSH_API:
                formatted_parameters["key"] = {}
                formatted_parameters["key"]["required"] = True
                formatted_parameters["key"]["type"] = str.__name__
            self.finish_async({
                "success": 1,
                "parameters": formatted_parameters
            })
        else:
            # type check arguments
            argsDict = self.get_safe_arguments(
                self.request.arguments, self.get_argument)
            if argsDict["success"] == 1:
                # validate API key if push endpoint
                if self.endpoint_type == Endpoint.PULL_API or (
                    self.endpoint_type == Endpoint.PUSH_API and valid_api_key(
                        argsDict["args"]["key"])):
                    response = {"success": 1}
                    if not self.asynchronous:
                        response = self.process(response, argsDict["args"])
                        self.finish_async(response)
                    else:
                        self.process(response, argsDict["args"])
                else:
                    self.finish_async(
                        {"success": 0, "description": "That API key is not valid."})
            else:
                # print the error message from argument parsing
                self.finish_async(argsDict)

    post = get

    def finish_async(self, response):
        """ Write the response dictionary, and finish this asynchronous call. """

        self.write(json.dumps(response))
        self.finish()

    def render_with_user_info(self, url, params={}):
        """
        Render a Tornado HTML template, automatically
        appending user information.
        Do NOT mutate the params dict.
        """

        login_dict = {
            "github_name": self.get_current_github_name(),
            "github_username": self.get_current_github_username(),
            "github_avatar": self.get_current_github_avatar(),
            "github_access_token": self.get_current_github_access_token(),
            "api_key": self.get_current_api_key()
        }
        for k in params:
            # rather than passing both dicts, make it 3.4 compatible by merging
            login_dict[k] = params[k]
        self.render(url, **login_dict)

    def __get_current_github_object__(self):
        """
        Return an object representing the user's name, avatar, and
        access_token, or None is the user is not logged in.
        Technically a "private" method; please use the get_current_* methods.
        """

        try:
            return json_decode(self.get_secure_cookie("user"))
        except BaseException:
            return None

    def get_current_github_name(self):
        """ Get the user's name from GitHub. """

        github_user_object = self.__get_current_github_object__()
        if github_user_object:
            return github_user_object["name"]
        return ""

    def get_current_github_username(self):
        """
        Get the user's GitHub username. Guaranteed to exist iff logged in.
        """

        github_user_object = self.__get_current_github_object__()
        if github_user_object:
            return github_user_object["login"]
        return ""

    def get_current_github_avatar(self):
        """ Get the user's avatar from GitHub. """

        github_user_object = self.__get_current_github_object__()
        if github_user_object:
            return github_user_object["avatar_url"]
        return ""

    def get_current_github_access_token(self):
        """
        Get the user's access token from GitHub. Guaranteed to exist iff logged in.
        """

        github_user_object = self.__get_current_github_object__()
        if github_user_object:
            return github_user_object["access_token"]
        return ""

    def get_current_api_key(self):
        """
        Get the user's API key. Guaranteed to exist iff logged in.
        """

        return self.get_secure_cookie("api_key")

    def set_default_headers(self):
        """
        Set the headers to allow JS API requests. Potentially a security concern.
        """

        origin = self.request.headers.get('Origin')
        if origin:
            self.set_header('Access-Control-Allow-Origin', origin)
        self.set_header('Access-Control-Allow-Credentials', 'true')

class AbstractEndpoint(metaclass=ABCMeta):
    """ An abstract class to enforce the structure of API endpoints. """

    def register(subclass):
        """
        Enforce the API specification described in BaseHandler.
        Called by the "brainspell" module on all API endpoints.
        """

        assert subclass.endpoint_type, "The class " + subclass.__name__ + \
            " does not indicate what type of endpoint it is (using the endpoint_type variable). Please reimplement the class to conform to this specification."
        assert subclass.process, "The class " + subclass.__name__ + \
            " does not override the \"process\" function. Please reimplement the class to conform to this specification."
        assert subclass.parameters is not None, "The class " + subclass.__name__ + \
            " does not specify its parameters. Please reimplement the class to conform to this specification."
<commit_msg>set HTTP status codes<commit_after>import json
from abc import ABCMeta
from concurrent.futures import ThreadPoolExecutor
from enum import Enum

import tornado
import tornado.web
from torngithub import json_decode

from user_account_helpers import *

MAX_WORKERS = 16

class Endpoint(Enum):
    """
    An Enum to distinguish push from pull APIs.
    Push APIs need to validate the user's API key.
    """

    PUSH_API = 1
    PULL_API = 2

class BaseHandler(tornado.web.RequestHandler):
    """
    A handler that all Brainspell handlers should extend.

    All class names should be CamelCase.

    JSON endpoints should:
    1) be named [*]EndpointHandler,
    2) specify the "parameters" dictionary,
    3) override the "process" function, and
    4) specify the "endpoint_type" using the Endpoint enum.

    The resulting API endpoint will be the hyphenated form of the name.
    e.g., SplitTableEndpointHandler => /json/split-table

    You can view the parameters for any JSON endpoint at /json/*/help.
    e.g., /json/split-table/help

    Specifying the "parameters" dictionary:

    parameters ::= {
        parameter_name: {
            "type": parseFn
        }
        ...
    }

    where "type" is a key mapped to a function that can be used to parse
    a string into the desired type. e.g.,
    parseFn ::= str | int | float | json.loads | ...

    If a parameter is optional, you can indicate that by including a default value:

    parameters ::= {
        parameter_name: {
            "type": int,
            "default": 0
        }
        ...
    }

    The "process" function:

    "process" function signature:
    def process(self, response, args)

    By default, "response" is a dictionary that contains a key
    called "success" with a value of 1. The process function should
    mutate the "response" dictionary as necessary and return it (unless
    it is an asynchronous endpoint, described below).

    "args" is a dictionary with parameter values, such that the keys
    are those specified in the "parameters" dictionary.

    The "endpoint_type" enum:

    endpoint_type ::= Endpoint.PULL_API | Endpoint.PUSH_API

    If "endpoint_type" is set to Endpoint.PUSH_API, then there
    will be one additional required parameter: the "key" parameter,
    which is the user's API key. This key will be automatically validated
    before the "process" function is called, and it will be included in
    the "args" dict.

    Asynchronous endpoints:
    If your endpoint is going to block the main thread for a reasonable
    period of time, please make it asynchronous. It's as easy as setting
    the "asynchronous" boolean, decorating your "process" function with
    @tornado.gen.coroutine, and calling self.finish_async when your
    function finishes execution (MANDATORY). Then, any blocking code
    should be decorated with @run_on_executor.

    asynchronous :: True | False

    @run_on_executor
    def blocker(self):
        # blocking code here
        ...

    @tornado.gen.coroutine
    def process(self, response, args):
        blocked_result = yield self.blocker()
        ...
        self.finish_async(response)

    Web interface handlers should be named [*]Handler, and use the
    "render_with_user_info" function (rather than self.render).

    The following variables will be included for use by the Tornado
    HTML template:
    - "github_name"
    - "github_username"
    - "github_avatar"
    - "github_access_token"
    - "api_key"
    """

    parameters = None
    endpoint_type = None
    process = None

    asynchronous = False
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)

    def get_safe_arguments(self, arguments_dict, accessor):
        """ Enforce type safety; do not verify API key. """

        args = {}
        for k in self.parameters:
            if k not in arguments_dict:
                if "default" not in self.parameters[k]:
                    return {
                        "success": 0,
                        "description": "Missing required parameter: " + k
                    }
                else:
                    args[k] = self.parameters[k]["type"](
                        self.parameters[k]["default"])
            else:
                try:
                    args[k] = self.parameters[k]["type"](accessor(k))
                except BaseException:
                    return {
                        "success": 0,
                        "description": "Bad input for argument (type " +
                        self.parameters[k]["type"].__name__ +
                        "): " +
                        k
                    }

        if self.endpoint_type == Endpoint.PUSH_API or (
                "key" in self.request.arguments):
            try:
                args["key"] = str(accessor("key"))
            except BaseException:
                args["key"] = ""

        return {
            "success": 1,
            "args": args
        }

    @tornado.gen.coroutine
    @tornado.web.asynchronous
    def get(self):
        """
        Provide a guarantee for a valid API key on PUSH endpoints,
        documentation at /help, and type-checked arguments.
        """

        assert self.endpoint_type, "You must indicate what type of endpoint this is by setting the endpoint_type variable."
        self.set_header("Content-Type", "application/json")

        assert self.parameters is not None, "You haven't indicated the parameters for this endpoint."

        # provide help documentation
        components = [x for x in self.request.path.split("/") if x]
        if len(components) >= 3 and components[2] == "help":
            formatted_parameters = {}
            for p in self.parameters:
                formatted_parameters[p] = {}
                if "default" not in self.parameters[p]:
                    formatted_parameters[p]["required"] = True
                else:
                    formatted_parameters[p]["required"] = False
                    formatted_parameters[p]["default"] = self.parameters[p]["default"]
                type_name = self.parameters[p]["type"].__name__
                if type_name == "loads":  # account for loads function
                    type_name = "json"
                formatted_parameters[p]["type"] = type_name
                if "description" in self.parameters[p]:
                    formatted_parameters[p]["description"] = self.parameters[p]["description"]
            if self.endpoint_type == Endpoint.PUSH_API:
                formatted_parameters["key"] = {}
                formatted_parameters["key"]["required"] = True
                formatted_parameters["key"]["type"] = str.__name__
            self.finish_async({
                "success": 1,
                "parameters": formatted_parameters
            })
        else:
            # type check arguments
            argsDict = self.get_safe_arguments(
                self.request.arguments, self.get_argument)
            if argsDict["success"] == 1:
                # validate API key if push endpoint
                if self.endpoint_type == Endpoint.PULL_API or (
                    self.endpoint_type == Endpoint.PUSH_API and valid_api_key(
                        argsDict["args"]["key"])):
                    response = {"success": 1}
                    if not self.asynchronous:
                        response = self.process(response, argsDict["args"])
                        self.finish_async(response)
                    else:
                        self.process(response, argsDict["args"])
                else:
                    self.set_status(401)  # unauthorized
                    self.finish_async(
                        {"success": 0, "description": "That API key is not valid."}, True)
            else:
                # print the error message from argument parsing
                self.set_status(400)  # bad request
                self.finish_async(argsDict, True)

    post = get

    def finish_async(self, response, status_set=False):
        """ Write the response dictionary, and finish this asynchronous call. """
        if not status_set:
            if isinstance(response, dict):
                if "success" in response:
                    if response["success"] != 1:
                        self.set_status(422)  # unprocessable entity
        self.write(json.dumps(response))
        self.finish()

    def render_with_user_info(self, url, params={}):
        """
        Render a Tornado HTML template, automatically
        appending user information.
        Do NOT mutate the params dict.
        """

        login_dict = {
            "github_name": self.get_current_github_name(),
            "github_username": self.get_current_github_username(),
            "github_avatar": self.get_current_github_avatar(),
            "github_access_token": self.get_current_github_access_token(),
            "api_key": self.get_current_api_key()
        }
        for k in params:
            # rather than passing both dicts, make it 3.4 compatible by merging
            login_dict[k] = params[k]
        self.render(url, **login_dict)

    def __get_current_github_object__(self):
        """
        Return an object representing the user's name, avatar, and
        access_token, or None is the user is not logged in.
        Technically a "private" method; please use the get_current_* methods.
        """

        try:
            return json_decode(self.get_secure_cookie("user"))
        except BaseException:
            return None

    def get_current_github_name(self):
        """ Get the user's name from GitHub. """

        github_user_object = self.__get_current_github_object__()
        if github_user_object:
            return github_user_object["name"]
        return ""

    def get_current_github_username(self):
        """
        Get the user's GitHub username. Guaranteed to exist iff logged in.
        """

        github_user_object = self.__get_current_github_object__()
        if github_user_object:
            return github_user_object["login"]
        return ""

    def get_current_github_avatar(self):
        """ Get the user's avatar from GitHub. """

        github_user_object = self.__get_current_github_object__()
        if github_user_object:
            return github_user_object["avatar_url"]
        return ""

    def get_current_github_access_token(self):
        """
        Get the user's access token from GitHub. Guaranteed to exist iff logged in.
        """

        github_user_object = self.__get_current_github_object__()
        if github_user_object:
            return github_user_object["access_token"]
        return ""

    def get_current_api_key(self):
        """
        Get the user's API key. Guaranteed to exist iff logged in.
        """

        return self.get_secure_cookie("api_key")

    def set_default_headers(self):
        """
        Set the headers to allow JS API requests. Potentially a security concern.
        """

        origin = self.request.headers.get('Origin')
        if origin:
            self.set_header('Access-Control-Allow-Origin', origin)
        self.set_header('Access-Control-Allow-Credentials', 'true')

class AbstractEndpoint(metaclass=ABCMeta):
    """ An abstract class to enforce the structure of API endpoints. """

    def register(subclass):
        """
        Enforce the API specification described in BaseHandler.
        Called by the "brainspell" module on all API endpoints.
        """

        assert subclass.endpoint_type, "The class " + subclass.__name__ + \
            " does not indicate what type of endpoint it is (using the endpoint_type variable). Please reimplement the class to conform to this specification."
        assert subclass.process, "The class " + subclass.__name__ + \
            " does not override the \"process\" function. Please reimplement the class to conform to this specification."
        assert subclass.parameters is not None, "The class " + subclass.__name__ + \
            " does not specify its parameters. Please reimplement the class to conform to this specification."
<|endoftext|>


<commit_before>"""
FinalProject.py
Author: Avery Wallis
Sources:

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, LineAsset, PolygonAsset

red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
orange = Color(0xffa500, 1.0)
skin =Color(0xFCD15B, 1.0)
wall=Color(0xE8E8E8, 1.0)
orange=Color(0xFFa500,1.0)
plat=Color(0xB9BDBB,1.0)
gooy=Color(0xCDF238,1.0)
white=Color(0xFFFFFF,1.0)
darkblue=Color(0x052099,1.0)

thinline= LineStyle(1, black)
thickline= LineStyle(5, black)
thickishline= LineStyle(2.5, black)
noline=LineStyle(0, black)
portalline=LineStyle(1, blue)
portalline2=LineStyle(1, orange)

wall=RectangleAsset(500,500, noline, wall)
blueportal=EllipseAsset(27, 60, noline, blue)
orangeportal=EllipseAsset(27, 60, noline, orange)
innerportal=EllipseAsset(24, 57, noline, white)
exit=CircleAsset(70, thinline, plat)
exit2=CircleAsset(20, thinline, plat)
plat=RectangleAsset(250, 50, noline, plat)
doorline=LineAsset(0, 120, thinline)
goo=PolygonAsset([(0,500),(800,500),(800,600,),(0,600)],noline,gooy)

class Chell(Sprite):
    asset = ImageAsset("images/Chell.png"

    def __init__(self, position):
        super().__init__(Chell.asset, position)

class PortalGame(App):
    def __init__(self, width, height):
        super().__init__(width, height)
    Sprite(wall, (400,20))
    Sprite(wall, (100,20))
    Sprite(exit, (800,100))
    Sprite(exit2, (800, 100))
    Sprite(doorline, (800, 30))
    Sprite(plat, (100,400))
    Sprite(plat, (650, 150))
    Sprite(orangeportal, (700,90))
    Sprite(innerportal, (700,90))
    Sprite(blueportal, (200,340))
    Sprite(innerportal, (200,340))
    Sprite(goo, (100,0))
myapp = PortalGame(1000,1000)
myapp.run()<commit_msg>Updated from Brython Server: 4/18/2016 2:28:09 PM<commit_after>"""
FinalProject.py
Author: Avery Wallis
Sources:

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, LineAsset, PolygonAsset

red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
orange = Color(0xffa500, 1.0)
skin =Color(0xFCD15B, 1.0)
wall=Color(0xE8E8E8, 1.0)
orange=Color(0xFFa500,1.0)
plat=Color(0xB9BDBB,1.0)
gooy=Color(0xCDF238,1.0)
white=Color(0xFFFFFF,1.0)
darkblue=Color(0x052099,1.0)

thinline= LineStyle(1, black)
thickline= LineStyle(5, black)
thickishline= LineStyle(2.5, black)
noline=LineStyle(0, black)
portalline=LineStyle(1, blue)
portalline2=LineStyle(1, orange)

wall=RectangleAsset(500,500, noline, wall)
blueportal=EllipseAsset(27, 60, noline, blue)
orangeportal=EllipseAsset(27, 60, noline, orange)
innerportal=EllipseAsset(24, 57, noline, white)
exit=CircleAsset(70, thinline, plat)
exit2=CircleAsset(20, thinline, plat)
plat=RectangleAsset(250, 50, noline, plat)
doorline=LineAsset(0, 120, thinline)
goo=PolygonAsset([(0,500),(800,500),(800,600,),(0,600)],noline,gooy)

class Chell(Sprite):
    asset = ImageAsset("images/Chell.png")

    def __init__(self, position):
        super().__init__(Chell.asset, position)

class PortalGame(App):
    def __init__(self, width, height):
        super().__init__(width, height)
    Sprite(wall, (400,20))
    Sprite(wall, (100,20))
    Sprite(exit, (800,100))
    Sprite(exit2, (800, 100))
    Sprite(doorline, (800, 30))
    Sprite(plat, (100,400))
    Sprite(plat, (650, 150))
    Sprite(orangeportal, (700,90))
    Sprite(innerportal, (700,90))
    Sprite(blueportal, (200,340))
    Sprite(innerportal, (200,340))
    Sprite(goo, (100,0))
myapp = PortalGame(1000,1000)
myapp.run()<|endoftext|>


<commit_before>
##
# Environments

def dev_unix():
    # Name env:
    config.env = 'dev-unix'
    #
    config(
        tomcat="/usr/share/tomcat6",
        tomcat_webapps="$(tomcat)/webapps",
        tomcat_start='$(tomcat)/bin/catalina.sh start',
        tomcat_stop='$(tomcat)/bin/catalina.sh stop',
    )
    # Machines:
    config(
        host_map={
            'localhost': ['127.0.0.1'],
        },
        dist_dir='/opt/_workapps/rinfo/rinfo_dist',
        rinfo_dir='/opt/_workapps/rinfo',
        rinfo_rdf_repo_dir='/opt/_workapps/rinfo/aduna',
    )

def staging():
    # Name env:
    config.env = 'stg'
    # SuSE layout:
    config(
        tomcat="/usr/share/tomcat6",
        tomcat_webapps="$(tomcat)/webapps",
        tomcat_start='dtomcat6 start',
        tomcat_stop='dtomcat6 stop',
    )
    # Machines:
    config(
        fab_user='rinfo',
        host_map={
            'localhost': ['127.0.0.1'],
            'main': ['rinfo-main.statskontoret.se'],
            'service': ['rinfo-service.statskontoret.se'],
            'testsources': ['rinfo-sources.statskontoret.se'],
        },
        dist_dir='rinfo_dist',
        rinfo_dir='/opt/rinfo',
        rinfo_rdf_repo_dir='/opt/rinfo/rdf',
    )

def production():
    # Name env:
    config.env = 'prod'
    # TODO:
    raise NotImplementedError

##
# Service targets

_needs_env = requires(
        'host_map', 'dist_dir', 'tomcat',
        provided_by=[dev_unix, staging, production])

@_needs_env
def localhost():
    config.fab_hosts = config.host_map['localhost']

@_needs_env
def main():
    config.fab_hosts = config.host_map['main']
    config.app_name = 'rinfo-main'
    config.rinfo_main_store = "/opt/rinfo/store"

@_needs_env
def service():
    config.fab_hosts = config.host_map['service']
    config.app_name = 'rinfo-service'

@_needs_env
def testsources():
    config.fab_hosts = config.host_map['testsources']
    config.app_name = 'rinfo-depot'
    config.test_store = "/opt/testsources/depots"

##
# Shared diagnostics

_needs_target = requires(
        'fab_hosts', 'dist_dir', 'tomcat', 'app_name',
        provided_by=[main, service, testsources])

@_needs_target
def list_dist(ls=""):
    if ls: ls = "-"+ls
    run("ls %s $(dist_dir)/" % ls)

@_needs_target
def clean_dist():
    run("rm $(dist_dir)/*", fail='warn')

@_needs_target
def tail():
    sudo("tail -f $(tomcat)/logs/catalina.out")

@_needs_target
def restart():
    sudo("$(tomcat_stop)", fail='warn')
    sudo("$(tomcat_start)")

@_needs_target
def war_props(war="ROOT"):
    run("unzip -p $(tomcat_webapps)/%s.war "
            "WEB-INF/classes/$(app_name).properties" % war)

<commit_msg>extended env-config a bit<commit_after>
##
# Environments

def dev_unix():
    # Name env:
    config.env = 'dev-unix'
    #
    config(
        tomcat="/usr/share/tomcat6",
        tomcat_webapps="$(tomcat)/webapps",
        tomcat_start='$(tomcat)/bin/catalina.sh start',
        tomcat_stop='$(tomcat)/bin/catalina.sh stop',
    )
    # Machines:
    config(
        host_map={
            'main': ['localhost'],
            'service': ['localhost'],
            'testsources': ['localhost'],
        },
        store_map={
            'main': "/opt/_workapps/rinfo/depots/rinfo",
            'testsources': "/opt/_workapps/rinfo/depots",
        },
        dist_dir='/opt/_workapps/rinfo/rinfo_dist',
        rinfo_dir='/opt/_workapps/rinfo',
        rinfo_rdf_repo_dir='/opt/_workapps/rinfo/aduna',
    )

def staging():
    # Name env:
    config.env = 'stg'
    # SuSE layout:
    config(
        tomcat="/usr/share/tomcat6",
        tomcat_webapps="$(tomcat)/webapps",
        tomcat_start='dtomcat6 start',
        tomcat_stop='dtomcat6 stop',
    )
    # Machines:
    config(
        fab_user='rinfo',
        host_map={
            'main': ['rinfo-main.statskontoret.se'],
            'service': ['rinfo-service.statskontoret.se'],
            'testsources': ['rinfo-sources.statskontoret.se'],
        },
        store_map={
            'main': "/opt/rinfo/store",
            'testsources': "/opt/testsources/depots",
        },
        dist_dir='rinfo_dist',
        rinfo_dir='/opt/rinfo',
        rinfo_rdf_repo_dir='/opt/rinfo/rdf',
    )

def production():
    # Name env:
    config.env = 'prod'
    # TODO:
    raise NotImplementedError

##
# Service targets

_needs_env = requires(
        'host_map', 'dist_dir', 'tomcat',
        provided_by=[dev_unix, staging, production])

@_needs_env
def main():
    config.fab_hosts = config.host_map['main']
    config.rinfo_main_store = config.store_map['main']
    config.app_name = 'rinfo-main'

@_needs_env
def service():
    config.fab_hosts = config.host_map['service']
    config.app_name = 'rinfo-service'

@_needs_env
def testsources():
    config.fab_hosts = config.host_map['testsources']
    config.test_store = config.store_map['testsources'] #+ "/example.org"
    config.app_name = 'rinfo-depot'

##
# Shared diagnostics

_needs_target = requires(
        'fab_hosts', 'dist_dir', 'tomcat', 'app_name',
        provided_by=[main, service, testsources])

@_needs_target
def list_dist(ls=""):
    if ls: ls = "-"+ls
    run("ls %s $(dist_dir)/" % ls)

@_needs_target
def clean_dist():
    run("rm $(dist_dir)/*", fail='warn')

@_needs_target
def tail():
    sudo("tail -f $(tomcat)/logs/catalina.out")

@_needs_target
def restart():
    sudo("$(tomcat_stop)", fail='warn')
    sudo("$(tomcat_start)")

@_needs_target
def war_props(war="ROOT"):
    run("unzip -p $(tomcat_webapps)/%s.war "
            "WEB-INF/classes/$(app_name).properties" % war)

<|endoftext|>


<commit_before>import tornado.web
import os
import pytest
import brainspell
import models
import search
import selenium
from selenium import webdriver

application = brainspell.make_app()

"""Configuring SauceLabs for Selenium Testing"""
capabilities = {}
username = os.environ["SAUCE_USERNAME"]
access_key = os.environ["SAUCE_ACCESS_KEY"]
capabilities["tunnel-identifier"] = os.environ["TRAVIS_JOB_NUMBER"]
hub_url = "%s:%s@localhost:4445" % (username, access_key)
capabilities["build"] = os.environ["TRAVIS_BUILD_NUMBER"]
capabilities["tags"] = [os.environ["TRAVIS_PYTHON_VERSION"], "CI"]
capabilities["browserName"] = "firefox"
driver = webdriver.Remote(desired_capabilities=capabilities, command_executor="http://%s/wd/hub" % hub_url)

"""
TODO: need to make tests for:
1) user creation
2) user login
3) adding and deleting a row of coordinates
4) splitting, flagging a table
5) voting on table and article tags
6) setting the authors for an article
7) saving to a brainspell.org collection, and to a GitHub collection
"""
# Asserts search results appearing for commonly found target
def test_search():
    assert len(search.formatted_search("brain", 0)) > 0

#Asserts Procfile in proper place. (Required for Heroku build)
def test_procfile():
    f = open("../Procfile", "r")
    contents = f.read()
    filename = contents.replace("web: python3 json_api/", "").replace("\n", "")
    assert filename in os.listdir()

def test_row_add(): #Using selenium testing
    driver.get("https://brainspell.herokuapp.com")
    assert "Brainspell" in driver.title #Checks website title is accurate
    driver.get("https://brainspell.herokuapp.com/view-article?id=00000000")
    meshButtons = driver.find_elements_by_class_name("dropbtn")
    assert meshButtons != None #Ensure Mesh terms are included

# TODO: What does this test do?
@pytest.fixture
def app():
    return application

# TODO: What does this test do?
@pytest.mark.gen_test
def test_front_page(http_client, base_url):
    response = yield http_client.fetch(base_url)
    assert response.code == 200

<commit_msg>Updated selenium testing to make sure each page actually exists and tests some funtionality on view article page<commit_after>import tornado.web
import os
import pytest
import brainspell
import models
import search
import selenium
from selenium import webdriver

application = brainspell.make_app()

"""Configuring SauceLabs for Selenium Testing"""
capabilities = {}
username = os.environ["SAUCE_USERNAME"]
access_key = os.environ["SAUCE_ACCESS_KEY"]
capabilities["tunnel-identifier"] = os.environ["TRAVIS_JOB_NUMBER"]
hub_url = "%s:%s@localhost:4445" % (username, access_key)
capabilities["build"] = os.environ["TRAVIS_BUILD_NUMBER"]
capabilities["tags"] = [os.environ["TRAVIS_PYTHON_VERSION"], "CI"]
capabilities["browserName"] = "firefox"
driver = webdriver.Remote(desired_capabilities=capabilities, command_executor="http://%s/wd/hub" % hub_url)

"""
TODO: need to make tests for:
1) user creation
2) user login
3) adding and deleting a row of coordinates
4) splitting, flagging a table
5) voting on table and article tags
6) setting the authors for an article
7) saving to a brainspell.org collection, and to a GitHub collection
"""
# Asserts search results appearing for commonly found target
def test_search():
    assert len(search.formatted_search("brain", 0)) > 0

#Asserts Procfile in proper place. (Required for Heroku build)
def test_procfile():
    f = open("../Procfile", "r")
    contents = f.read()
    filename = contents.replace("web: python3 json_api/", "").replace("\n", "")
    assert filename in os.listdir()

def test_existence(): #Using selenium testing
    driver.get("https://brainspell.herokuapp.com")
    assert "Brainspell" in driver.title #Checks website title is accurate

    #Ensuring elements of view article page are all present
    driver.get("https://brainspell.herokuapp.com/view-article?id=00000000")
    meshButtons = driver.find_elements_by_class_name("dropbtn")
    assert meshButtons != None #Ensure Mesh terms are included
    table = driver.find_elements_by_class_name("experiment-table-row")
    assert table != None

    #Click and vote on a MeSH tag
    buttons = driver.find_elements_by_class_name("dropbtn")
    buttons[0].click()
    assert "modal-body" in driver.page_source
    driver.find_element_by_id("closer").click()

    #Test search page
    driver.get("https://brainspell.herokuapp.com/search?q=brain&req=t")
    items = driver.find_elements_by_class_name("must-login")
    assert len(items) > 9

    #Make sure showing the widget doesn't break regardless of article
    driver.find_element_by_id("widgetOption").click()

# TODO: What does this test do?
@pytest.fixture
def app():
    return application

# TODO: What does this test do?
@pytest.mark.gen_test
def test_front_page(http_client, base_url):
    response = yield http_client.fetch(base_url)
    assert response.code == 200

<|endoftext|>


<commit_before>"""
FinalProject.py
Author: Avery Wallis
Sources: Hayden Hatfield,

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, LineAsset
from ggame import ImageAsset, PolygonAsset

red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
orange = Color(0xffa500, 1.0)
skin =Color(0xFCD15B, 1.0)
wall=Color(0xE8E8E8, 1.0)
orange=Color(0xFFa500,1.0)
plat=Color(0xB9BDBB,1.0)
gooy=Color(0xCDF238,1.0)
white=Color(0xFFFFFF,1.0)
darkblue=Color(0x052099,1.0)

thinline= LineStyle(1, black)
thickline= LineStyle(5, black)
thickishline= LineStyle(2.5, black)
noline=LineStyle(0, black)
portalline=LineStyle(1, blue)
portalline2=LineStyle(1, orange)

wall=RectangleAsset(500,500, noline, wall)
blueportal=EllipseAsset(27, 60, noline, blue)
orangeportal=EllipseAsset(27, 60, noline, orange)
innerportal=EllipseAsset(24, 57, noline, white)
exit=CircleAsset(70, thinline, plat)
exit2=CircleAsset(20, thinline, plat)
plat=RectangleAsset(250, 50, noline, plat)
doorline=LineAsset(0, 120, thinline)
goo=PolygonAsset([(0,500),(800,500),(800,600,),(0,600)],noline,gooy)

class Chell(Sprite):
    asset = ImageAsset("images/Chell1.png")
    def __init__(self, position):
        super().__init__(Chell.asset, position)
        self.visible = True
        self.x = 250
        self.y = 250
        self.click = 0
        self.mright = 0
        self.mleft = 0
        self.alt = 0
        self.image = 0
        self.scale = .25
        PortalGame.listenKeyEvent("keydown", "d", self.rightOn)
        PortalGame.listenKeyEvent("keyup", "d", self.rightOff)
        PortalGame.listenKeyEvent("keydown", "a", self.leftOn)
        PortalGame.listenKeyEvent("keyup", "a", self.leftOff)
        PortalGame.listenMouseEvent("click", self.ClickOn)
        PortalGame.listenKeyEvent("keydown", "alt", self.altOn)
        PortalGame.listenKeyEvent("keyup", "alt", self.altOff)

    def step(self):
        if self.click == 1 and self.alt != 1:
            OrangePortal((self.cox-60,self.coy-70))
            self.click = 0
            self.alt = 0
        if self.click == 1 and self.alt == 1:
            BluePortal((self.cox-60,self.coy-70))
            self.click = 0
            self.alt = 0

        if self.mright == 1:
            self.x += .75
            self.y = self.y
        if self.mright == 0:
            self.x =self.x
            self.y=self.y
        if self.mleft == 1:
            self.x += -.75
            self.y = self.y
        if self.mleft == 0:
            self.x = self.x
            self.y = self.y

    def ClickOn(self,event):
        self.click = 1
        self.cox = event.x
        self.coy = event.y
    def rightOn(self,event):
        self.mright = 1
    def rightOff(self,event):
        self.mright = 0
    def leftOn(self,event):
        self.mleft = 1
    def leftOff(self,event):
        self.mleft = 0
    def altOn(self,event):
        self.alt = 1
    def altOff(self,event):
        self.alt = 0

class BluePortal(Sprite):
    asset = ImageAsset("images/Blue_Portal.png")
    def __init__(self, position):
        super().__init__(BluePortal.asset, position)
        self.visible = True
        self.scale = .25

    def step(self):
        self.x = self.x
        self.y = self.y

class OrangePortal(Sprite):
    asset = ImageAsset("images/portal___orange_portal_by_maxiesnax-d5pcfmj.png")
    def __init__(self, position):
        super().__init__(OrangePortal.asset, position)
        self.scale = .25
        self.center = (0,0)
        self.image = 0
        self.des = 0

    def step(self):
        self.x = self.x
        self.y = self.y
        self.des = 1
        if self.des == 1:
            self.destroy
        else:
            self.x = self.x
            self.y = self.y

class PortalGame(App):
    def __init__(self, width, height):
        super().__init__(width, height)
        Sprite(wall, (400,20))
        Sprite(wall, (100,20))
        Sprite(exit, (800,100))
        Sprite(exit2, (800, 100))
        Sprite(doorline, (800, 30))
        Sprite(plat, (100,400))
        Sprite(plat, (650, 150))
        Sprite(goo, (100,0))
        Chell((0,0))

    def step(self):
        for chell in self.getSpritesbyClass(Chell):
            chell.step()

myapp = PortalGame(1000,750)
myapp.run()<commit_msg>Updated from Brython Server: 4/21/2016 2:18:30 PM<commit_after>"""
FinalProject.py
Author: Avery Wallis
Sources: Hayden Hatfield,

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, LineAsset
from ggame import ImageAsset, PolygonAsset

red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
orange = Color(0xffa500, 1.0)
skin =Color(0xFCD15B, 1.0)
wall=Color(0xE8E8E8, 1.0)
orange=Color(0xFFa500,1.0)
plat=Color(0xB9BDBB,1.0)
gooy=Color(0xCDF238,1.0)
white=Color(0xFFFFFF,1.0)
darkblue=Color(0x052099,1.0)

thinline= LineStyle(1, black)
thickline= LineStyle(5, black)
thickishline= LineStyle(2.5, black)
noline=LineStyle(0, black)
portalline=LineStyle(1, blue)
portalline2=LineStyle(1, orange)

wall=RectangleAsset(500,500, noline, wall)
blueportal=EllipseAsset(27, 60, noline, blue)
orangeportal=EllipseAsset(27, 60, noline, orange)
innerportal=EllipseAsset(24, 57, noline, white)
exit=CircleAsset(70, thinline, plat)
exit2=CircleAsset(20, thinline, plat)
plat=RectangleAsset(250, 50, noline, plat)
doorline=LineAsset(0, 120, thinline)
goo=PolygonAsset([(0,500),(800,500),(800,600,),(0,600)],noline,gooy)

class Chell(Sprite):
    asset = ImageAsset("images/Chell1.png")
    def __init__(self, position):
        super().__init__(Chell.asset, position)
        self.visible = True
        self.x = 250
        self.y = 250
        self.click = 0
        self.mright = 0
        self.mleft = 0
        self.alt = 0
        self.image = 0
        self.scale = .25
        PortalGame.listenKeyEvent("keydown", "d", self.rightOn)
        PortalGame.listenKeyEvent("keyup", "d", self.rightOff)
        PortalGame.listenKeyEvent("keydown", "a", self.leftOn)
        PortalGame.listenKeyEvent("keyup", "a", self.leftOff)
        PortalGame.listenMouseEvent("click", self.ClickOn)
        PortalGame.listenKeyEvent("keydown", "alt", self.altOn)
        PortalGame.listenKeyEvent("keyup", "alt", self.altOff)

    def step(self):
        if self.click == 1 and self.alt != 1:
            OrangePortal((self.cox-60,self.coy-70))
            self.click = 0
            self.alt = 0
        if self.click == 1 and self.alt == 1:
            BluePortal.step
            BluePortal((self.cox-60,self.coy-70))
            self.click = 0
            self.alt = 0

        if self.mright == 1:
            self.x += .75
            self.y = self.y
        if self.mright == 0:
            self.x =self.x
            self.y=self.y
        if self.mleft == 1:
            self.x += -.75
            self.y = self.y
        if self.mleft == 0:
            self.x = self.x
            self.y = self.y

    def ClickOn(self,event):
        self.click = 1
        self.cox = event.x
        self.coy = event.y
    def rightOn(self,event):
        self.mright = 1
    def rightOff(self,event):
        self.mright = 0
    def leftOn(self,event):
        self.mleft = 1
    def leftOff(self,event):
        self.mleft = 0
    def altOn(self,event):
        self.alt = 1
    def altOff(self,event):
        self.alt = 0

class BluePortal(Sprite):
    asset = ImageAsset("images/Blue_Portal.png")
    def __init__(self, position):
        super().__init__(BluePortal.asset, position)
        self.visible = True
        self.scale = .25

    def step(self):
        self.x = self.x
        self.y = self.y

class OrangePortal(Sprite):
    asset = ImageAsset("images/portal___orange_portal_by_maxiesnax-d5pcfmj.png")
    def __init__(self, position):
        super().__init__(OrangePortal.asset, position)
        self.scale = .25
        self.center = (0,0)
        self.image = 0
        self.des = 0

    def step(self):
        self.x = self.x
        self.y = self.y
        self.des = 1
        if self.des == 1:
            self.destroy
        else:
            self.x = self.x
            self.y = self.y

class PortalGame(App):
    def __init__(self, width, height):
        super().__init__(width, height)
        Sprite(wall, (400,20))
        Sprite(wall, (100,20))
        Sprite(exit, (800,100))
        Sprite(exit2, (800, 100))
        Sprite(doorline, (800, 30))
        Sprite(plat, (100,400))
        Sprite(plat, (650, 150))
        Sprite(goo, (100,0))
        Chell((0,0))

    def step(self):
        for chell in self.getSpritesbyClass(Chell):
            chell.step()

myapp = PortalGame(1000,750)
myapp.run()<|endoftext|>


<commit_before>"""Predefined validators."""
import re

from six.moves import reduce

from .errors import ValidationError
from . import utilities

class Min(object):

    """Validator for minimum value."""

    def __init__(self, minimum_value, exclusive=False):
        """Init.

        :param minimum_value: Minimum value for validator.
        :param bool exclusive: If `True`, then validated value must be strongly
            lower than given threshold.

        """
        self.minimum_value = minimum_value
        self.exclusive = exclusive

    def validate(self, value):
        """Validate value."""
        if self.exclusive:
            if value <= self.minimum_value:
                tpl = "'{value}' is lower or equal than minimum ('{min}')."
                raise ValidationError(
                    tpl.format(value=value, min=self.minimum_value))
        else:
            if value < self.minimum_value:
                raise ValidationError(
                    "'{value}' is lower than minimum ('{min}').".format(
                        value=value, min=self.minimum_value))

    def modify_schema(self, field_schema):
        """Modify field schema."""
        field_schema['minimum'] = self.minimum_value
        if self.exclusive:
            field_schema['exclusiveMinimum'] = True

class Max(object):

    """Validator for maximum value."""

    def __init__(self, maximum_value, exclusive=False):
        """Init.

        :param maximum_value: Maximum value for validator.
        :param bool exclusive: If `True`, then validated value must be strongly
            bigger than given threshold.

        """
        self.maximum_value = maximum_value
        self.exclusive = exclusive

    def validate(self, value):
        """Validate value."""
        if self.exclusive:
            if value >= self.maximum_value:
                tpl = "'{val}' is bigger or equal than maximum ('{max}')."
                raise ValidationError(
                    tpl.format(val=value, max=self.maximum_value))
        else:
            if value > self.maximum_value:
                raise ValidationError(
                    "'{value}' is bigger than maximum ('{max}').".format(
                        value=value, max=self.maximum_value))

    def modify_schema(self, field_schema):
        """Modify field schema."""
        field_schema['maximum'] = self.maximum_value
        if self.exclusive:
            field_schema['exclusiveMaximum'] = True

class Regex(object):

    """Validator for regular expressions."""

    FLAGS = {
        'ignorecase': re.I,
        'multiline': re.M,
    }

    def __init__(self, pattern, **flags):
        """Init.

        Note, that if given pattern is ECMA regex, given flags will be
        **completely ignored** and taken from given regex.

        :param string pattern: Pattern of regex.
        :param bool flags: Flags used for the regex matching.
            Allowed flag names are in the `FLAGS` attribute. The flag value
            does not matter as long as it evaluates to True.
            Flags with False values will be ignored.
            Invalid flags will be ignored.

        """
        if utilities.is_ecma_regex(pattern):
            result = utilities.convert_ecma_regex_to_python(pattern)
            self.pattern, self.flags = result
        else:
            self.pattern = pattern
            self.flags = [self.FLAGS[key] for key, value in flags.items()
                          if key in self.FLAGS and value]

    def validate(self, value):
        """Validate value."""
        flags = self._calculate_flags()

        try:
            result = re.search(self.pattern, value, flags)
        except TypeError as te:
            raise ValidationError(*te.args)

        if not result:
            raise ValidationError(
                'Value "{value}" did not match pattern "{pattern}".'.format(
                    value=value, pattern=self.pattern
                ))

    def _calculate_flags(self):
        return reduce(lambda x, y: x | y, self.flags, 0)

    def modify_schema(self, field_schema):
        """Modify field schema."""
        field_schema['pattern'] = utilities.convert_python_regex_to_ecma(
            self.pattern, self.flags)

class Length(object):

    """Validator for length."""

    def __init__(self, minimum_value=None, maximum_value=None):
        """Init.

        Note that if no `minimum_value` neither `maximum_value` will be
        specified, `ValueError` will be raised.

        :param int minimum_value: Minimum value (optional).
        :param int maximum_value: Maximum value (optional).

        """
        if minimum_value is None and maximum_value is None:
            raise ValueError(
                "Either 'minimum_value' or 'maximum_value' must be specified.")

        self.minimum_value = minimum_value
        self.maximum_value = maximum_value

    def validate(self, value):
        """Validate value."""
        len_ = len(value)

        if self.minimum_value is not None and len_ < self.minimum_value:
            tpl = "Value '{val}' length is lower than allowed minimum '{min}'."
            raise ValidationError(tpl.format(
                val=value, min=self.minimum_value
            ))

        if self.minimum_value is not None and len_ > self.maximum_value:
            raise ValidationError(
                "Value '{val}' length is bigger than "
                "allowed maximum '{max}'.".format(
                    val=value,
                    max=self.maximum_value,
                ))

    def modify_schema(self, field_schema):
        """Modify field schema."""
        if self.minimum_value:
            field_schema['minLength'] = self.minimum_value

        if self.maximum_value:
            field_schema['maxLength'] = self.maximum_value

class Enum(object):

    """Validator for enums."""

    def __init__(self, *choices):
        """Init.

        :param [] choices: Valid choices for the field.
        """

        self.choices = list(choices)

    def validate(self, value):
        if value not in self.choices:
            tpl = "Value '{val}' is not a valid choice."
            raise ValidationError(tpl.format(val=value))

    def modify_schema(self, field_schema):
        field_schema['enum'] = self.choices
<commit_msg>Fixed the validation bug, now all tests are passing<commit_after>"""Predefined validators."""
import re

from six.moves import reduce

from .errors import ValidationError
from . import utilities

class Min(object):

    """Validator for minimum value."""

    def __init__(self, minimum_value, exclusive=False):
        """Init.

        :param minimum_value: Minimum value for validator.
        :param bool exclusive: If `True`, then validated value must be strongly
            lower than given threshold.

        """
        self.minimum_value = minimum_value
        self.exclusive = exclusive

    def validate(self, value):
        """Validate value."""
        if self.exclusive:
            if value <= self.minimum_value:
                tpl = "'{value}' is lower or equal than minimum ('{min}')."
                raise ValidationError(
                    tpl.format(value=value, min=self.minimum_value))
        else:
            if value < self.minimum_value:
                raise ValidationError(
                    "'{value}' is lower than minimum ('{min}').".format(
                        value=value, min=self.minimum_value))

    def modify_schema(self, field_schema):
        """Modify field schema."""
        field_schema['minimum'] = self.minimum_value
        if self.exclusive:
            field_schema['exclusiveMinimum'] = True

class Max(object):

    """Validator for maximum value."""

    def __init__(self, maximum_value, exclusive=False):
        """Init.

        :param maximum_value: Maximum value for validator.
        :param bool exclusive: If `True`, then validated value must be strongly
            bigger than given threshold.

        """
        self.maximum_value = maximum_value
        self.exclusive = exclusive

    def validate(self, value):
        """Validate value."""
        if self.exclusive:
            if value >= self.maximum_value:
                tpl = "'{val}' is bigger or equal than maximum ('{max}')."
                raise ValidationError(
                    tpl.format(val=value, max=self.maximum_value))
        else:
            if value > self.maximum_value:
                raise ValidationError(
                    "'{value}' is bigger than maximum ('{max}').".format(
                        value=value, max=self.maximum_value))

    def modify_schema(self, field_schema):
        """Modify field schema."""
        field_schema['maximum'] = self.maximum_value
        if self.exclusive:
            field_schema['exclusiveMaximum'] = True

class Regex(object):

    """Validator for regular expressions."""

    FLAGS = {
        'ignorecase': re.I,
        'multiline': re.M,
    }

    def __init__(self, pattern, **flags):
        """Init.

        Note, that if given pattern is ECMA regex, given flags will be
        **completely ignored** and taken from given regex.

        :param string pattern: Pattern of regex.
        :param bool flags: Flags used for the regex matching.
            Allowed flag names are in the `FLAGS` attribute. The flag value
            does not matter as long as it evaluates to True.
            Flags with False values will be ignored.
            Invalid flags will be ignored.

        """
        if utilities.is_ecma_regex(pattern):
            result = utilities.convert_ecma_regex_to_python(pattern)
            self.pattern, self.flags = result
        else:
            self.pattern = pattern
            self.flags = [self.FLAGS[key] for key, value in flags.items()
                          if key in self.FLAGS and value]

    def validate(self, value):
        """Validate value."""
        flags = self._calculate_flags()

        try:
            result = re.search(self.pattern, value, flags)
        except TypeError as te:
            raise ValidationError(*te.args)

        if not result:
            raise ValidationError(
                'Value "{value}" did not match pattern "{pattern}".'.format(
                    value=value, pattern=self.pattern
                ))

    def _calculate_flags(self):
        return reduce(lambda x, y: x | y, self.flags, 0)

    def modify_schema(self, field_schema):
        """Modify field schema."""
        field_schema['pattern'] = utilities.convert_python_regex_to_ecma(
            self.pattern, self.flags)

class Length(object):

    """Validator for length."""

    def __init__(self, minimum_value=None, maximum_value=None):
        """Init.

        Note that if no `minimum_value` neither `maximum_value` will be
        specified, `ValueError` will be raised.

        :param int minimum_value: Minimum value (optional).
        :param int maximum_value: Maximum value (optional).

        """
        if minimum_value is None and maximum_value is None:
            raise ValueError(
                "Either 'minimum_value' or 'maximum_value' must be specified.")

        self.minimum_value = minimum_value
        self.maximum_value = maximum_value

    def validate(self, value):
        """Validate value."""
        len_ = len(value)

        if self.minimum_value is not None and len_ < self.minimum_value:
            tpl = "Value '{val}' length is lower than allowed minimum '{min}'."
            raise ValidationError(tpl.format(
                val=value, min=self.minimum_value
            ))

        if self.maximum_value is not None and len_ > self.maximum_value:
            raise ValidationError(
                "Value '{val}' length is bigger than "
                "allowed maximum '{max}'.".format(
                    val=value,
                    max=self.maximum_value,
                ))

    def modify_schema(self, field_schema):
        """Modify field schema."""
        if self.minimum_value:
            field_schema['minLength'] = self.minimum_value

        if self.maximum_value:
            field_schema['maxLength'] = self.maximum_value

class Enum(object):

    """Validator for enums."""

    def __init__(self, *choices):
        """Init.

        :param [] choices: Valid choices for the field.
        """

        self.choices = list(choices)

    def validate(self, value):
        if value not in self.choices:
            tpl = "Value '{val}' is not a valid choice."
            raise ValidationError(tpl.format(val=value))

    def modify_schema(self, field_schema):
        field_schema['enum'] = self.choices
<|endoftext|>


<commit_before>__title__ = "sewer"
__description__ = "Sewer is a programmatic Lets Encrypt(ACME) client"
__url__ = "https://github.com/komuW/sewer"
__version__ = "0.2.1"
__author__ = "komuW"
__author_email__ = "komuw05@gmail.com"
__license__ = "MIT"
<commit_msg>bump up version<commit_after>__title__ = "sewer"
__description__ = "Sewer is a programmatic Lets Encrypt(ACME) client"
__url__ = "https://github.com/komuW/sewer"
__version__ = "0.2.2"
__author__ = "komuW"
__author_email__ = "komuw05@gmail.com"
__license__ = "MIT"
<|endoftext|>


<commit_before>import datetime
import hashlib
import os
import re
import sys
import tempfile
import textwrap
import traceback
import types

from .utils import get_shotgun

def guess_user_id():
    login = os.getlogin()
    sg = get_shotgun()
    human = sg.find_one('HumanUser', [('email', 'starts_with', login + '@')])
    return human and human['id']

def exception_uuid(exc_type, exc_value, exc_traceback):
    """Calculate a 32-bit UUID for a given exception.

    Useful for looking for an existing ticket coresponding to a given exception.
    Takes into account the type of exception, and the name of every file and
    function in the traceback, along with the source code from those lines.

    This should remain consistant until a file or function is renamed, the
    source changed on the precise lines in the traceback, or the evaluation path
    changes.

    :return: Hex ``str`` of length 8.

    """
    hasher = hashlib.sha256(str(exc_type))
    for file_name, line_no, func_name, source in traceback.extract_tb(exc_traceback):
        hasher.update('\n' + file_name + ':' + func_name + ':' + (source or ''))
    return hasher.hexdigest()[:8]

def get_ticket_for_exception(exc_type=None, exc_value=None, exc_traceback=None, title=None):
    """Get (or create) a ticket for the given exception.

    Uses :func:`exception_uuid` to identify existing tickets by looking for the
    tag in square brackets in the title. E.g. ``Something happened. [deadbeef]``.

    :param str title: Title to use if creating a new ticket. Defaults to the
        exception type and value.
    :returns: The ID of the ticket.

    """
    if exc_type and exc_value and exc_traceback:
        mini_uuid = exception_uuid(exc_type, exc_value, exc_traceback)
    else:
        mini_uuid = None

    # Get the Shotgun and Project.
    # TODO: Somehow pass this in later.
    shotgun = get_shotgun()
    project = dict(type='Project', id=74)

    # Look for an existing ticket, or create a new one.
    if mini_uuid:
        ticket = shotgun.find_one('Ticket', [('title', 'contains', '[%s]' % mini_uuid)])
    else:
        ticket = None
    if ticket is None:

        if title is None:
            if exc_type and exc_value:
                title = '%s: %s' % (exc_type.__name__, exc_value)
            else:
                title = 'New Ticket'

        uuid_tag = ' [%s]' % mini_uuid if mini_uuid else ''

        # Automatically truncate to 255 escaped chars. Remember that the uuid
        # tag will consume 11, and another 3 for ellipsis, and a guess as to
        # how many due to the string escaping.
        if len(title.encode('string-escape')) + len(uuid_tag) > 255:
            title = title[:
                255
                - (len(title.encode('string-escape')) - len(title))
                - len(uuid_tag)
                - 3
            ] + '...'
        title = '%s%s' % (title, uuid_tag)

        ticket = shotgun.create('Ticket', dict(
            title=title,
            sg_status_list='rev', # Pending Review.
            project=project,
        ))

    return ticket['id']

def reply_to_ticket(ticket_id, content, user_id=None):
    """Create a structured reply to a ticket.

    :param int ticket_id: The ticket to reply to.
    :param content: ``str``, ``dict``, or iterator of ``(title, content``) pairs.
    :returns: ``(reply_id, reply_content)``.

    """

    user_comment = None
    exc_type = None

    if isinstance(content, dict):
        content = sorted(content.iteritems())

    if not isinstance(content, basestring):
        parts = []
        for heading, part in content:

            # This one gets special cased into a Reply.
            if heading.lower() == 'user comment':
                user_comment = part

            # Mappings.
            if isinstance(part, dict):
                parts.append((heading, '\n'.join('%s = %r' % x
                    for x in sorted(part.iteritems())
                )))

            # Iterators.
            elif isinstance(part, (list, tuple)):

                # Exceptions.
                if (len(part) == 3 and
                    issubclass(part[0], Exception) and
                    isinstance(part[1], Exception) and
                    isinstance(part[2], types.TracebackType)
                ):
                    exc_type = part[0]
                    parts.append((heading, '\n'.join(traceback.format_exception(*part)).rstrip()))

                # Iterators.
                else:
                    parts.append((heading, '\n'.join('- %r' % x for x in part)))

            # The rest.
            else:
                parts.append((heading, str(part)))

        # Join the parts.
        content = '\n\n'.join('%s\n%s\n%s' % (heading, '=' * len(heading), part) for heading, part in parts)

    # Get the Shotgun and Project.
    # TODO: Somehow pass this in later.
    shotgun = get_shotgun()

    # Convert requested user ID to a login.
    if user_id:
        user = shotgun.find_one('HumanUser', [('id', 'is', user_id)], ['login'])
        if user:
            shotgun.config.sudo_as_login = user['login']

    # Make sure we do have a login.
    if not shotgun.config.sudo_as_login:
        user = shotgun.find_one('HumanUser', [('email', 'starts_with', os.getlogin() + '@')], ['login'])
        if user:
            shotgun.config.sudo_as_login = user['login']

    reply = None

    if user_comment:
        reply = shotgun.create('Reply', {
            'content': user_comment,
            'entity': {'type': 'Ticket', 'id': ticket_id},
        })

    if content.strip():
        with tempfile.NamedTemporaryFile(suffix='ticket-%d-reply.txt' % ticket_id) as fh:
            fh.write(content)
            fh.flush()
            shotgun.upload('Ticket', ticket_id, fh.name, 'attachments',
               display_name='Ticket-%d.%s.%s.txt' % (
                    ticket_id,
                    exc_type.__name__ if exc_type else 'details',
                    datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
                ),
            )

    return reply and reply['id'], content

def attach_to_ticket(ticket_id, attachment):
    """Attach a file to a ticket."""
    shotgun = get_shotgun()
    shotgun.upload('Ticket', ticket_id, attachment, 'attachments')

if __name__ == '__main__':

    try:
        raise ValueError('this is a test')
    except:
        ticket_id = get_ticket_for_exception(*sys.exc_info(), title='Testing Ticket Submittion')
        print 'Ticket ID', ticket_id
        reply_id, _ = reply_to_ticket(ticket_id, {
            'User Comment': 'This is just a test',
            'Exception': sys.exc_info(),
        })
        print 'Reply ID', reply_id
<commit_msg>Pull ticket project/tool from siteconfig<commit_after>import datetime
import hashlib
import os
import re
import sys
import tempfile
import textwrap
import traceback
import types

import siteconfig

from .utils import get_shotgun

def guess_user_id():
    login = os.getlogin()
    sg = get_shotgun()
    human = sg.find_one('HumanUser', [('email', 'starts_with', login + '@')])
    return human and human['id']

def exception_uuid(exc_type, exc_value, exc_traceback):
    """Calculate a 32-bit UUID for a given exception.

    Useful for looking for an existing ticket coresponding to a given exception.
    Takes into account the type of exception, and the name of every file and
    function in the traceback, along with the source code from those lines.

    This should remain consistant until a file or function is renamed, the
    source changed on the precise lines in the traceback, or the evaluation path
    changes.

    :return: Hex ``str`` of length 8.

    """
    hasher = hashlib.sha256(str(exc_type))
    for file_name, line_no, func_name, source in traceback.extract_tb(exc_traceback):
        hasher.update('\n' + file_name + ':' + func_name + ':' + (source or ''))
    return hasher.hexdigest()[:8]

def get_ticket_for_exception(exc_type=None, exc_value=None, exc_traceback=None, title=None):
    """Get (or create) a ticket for the given exception.

    Uses :func:`exception_uuid` to identify existing tickets by looking for the
    tag in square brackets in the title. E.g. ``Something happened. [deadbeef]``.

    :param str title: Title to use if creating a new ticket. Defaults to the
        exception type and value.
    :returns: The ID of the ticket.

    """
    if exc_type and exc_value and exc_traceback:
        mini_uuid = exception_uuid(exc_type, exc_value, exc_traceback)
    else:
        mini_uuid = None

    # Get the Shotgun.
    shotgun = get_shotgun()

    # Look for an existing ticket, or create a new one.
    if mini_uuid:
        ticket = shotgun.find_one('Ticket', [('title', 'contains', '[%s]' % mini_uuid)])
        if ticket:
            return ticket['id']

    if title is None:
        if exc_type and exc_value:
            title = '%s: %s' % (exc_type.__name__, exc_value)
        else:
            title = 'New Ticket'

    uuid_tag = ' [%s]' % mini_uuid if mini_uuid else ''

    # Automatically truncate to 255 escaped chars. Remember that the uuid
    # tag will consume 11, and another 3 for ellipsis, and a guess as to
    # how many due to the string escaping.
    if len(title.encode('string-escape')) + len(uuid_tag) > 255:
        title = title[:
            255
            - (len(title.encode('string-escape')) - len(title))
            - len(uuid_tag)
            - 3
        ] + '...'
    title = '%s%s' % (title, uuid_tag)

    # Lookup where we are storing this ticket.
    project_id = siteconfig.get('SGACTIONS_TICKET_PROJECT')
    if not project_id:
        raise ValueError('SGACTIONS_TICKET_PROJECT must be set via siteconfig')
    tool_id = siteconfig.get('SGACTIONS_TICKET_TOOL')

    ticket = shotgun.create('Ticket', dict(
        title=title,
        sg_status_list='rev', # Pending Review.
        project={'type': 'Project', 'id': project_id},
        sg_tool={'type': 'Tool', 'id': tool_id} if tool_id else None,
    ))

    return ticket['id']

def reply_to_ticket(ticket_id, content, user_id=None):
    """Create a structured reply to a ticket.

    :param int ticket_id: The ticket to reply to.
    :param content: ``str``, ``dict``, or iterator of ``(title, content``) pairs.
    :returns: ``(reply_id, reply_content)``.

    """

    user_comment = None
    exc_type = None

    if isinstance(content, dict):
        content = sorted(content.iteritems())

    if not isinstance(content, basestring):
        parts = []
        for heading, part in content:

            # This one gets special cased into a Reply.
            if heading.lower() == 'user comment':
                user_comment = part

            # Mappings.
            if isinstance(part, dict):
                parts.append((heading, '\n'.join('%s = %r' % x
                    for x in sorted(part.iteritems())
                )))

            # Iterators.
            elif isinstance(part, (list, tuple)):

                # Exceptions.
                if (len(part) == 3 and
                    issubclass(part[0], Exception) and
                    isinstance(part[1], Exception) and
                    isinstance(part[2], types.TracebackType)
                ):
                    exc_type = part[0]
                    parts.append((heading, '\n'.join(traceback.format_exception(*part)).rstrip()))

                # Iterators.
                else:
                    parts.append((heading, '\n'.join('- %r' % x for x in part)))

            # The rest.
            else:
                parts.append((heading, str(part)))

        # Join the parts.
        content = '\n\n'.join('%s\n%s\n%s' % (heading, '=' * len(heading), part) for heading, part in parts)

    # Get the Shotgun and Project.
    # TODO: Somehow pass this in later.
    shotgun = get_shotgun()

    # Convert requested user ID to a login.
    if user_id:
        user = shotgun.find_one('HumanUser', [('id', 'is', user_id)], ['login'])
        if user:
            shotgun.config.sudo_as_login = user['login']

    # Make sure we do have a login.
    if not shotgun.config.sudo_as_login:
        user = shotgun.find_one('HumanUser', [('email', 'starts_with', os.getlogin() + '@')], ['login'])
        if user:
            shotgun.config.sudo_as_login = user['login']

    reply = None

    if user_comment:
        reply = shotgun.create('Reply', {
            'content': user_comment,
            'entity': {'type': 'Ticket', 'id': ticket_id},
        })

    if content.strip():
        with tempfile.NamedTemporaryFile(suffix='ticket-%d-reply.txt' % ticket_id) as fh:
            fh.write(content)
            fh.flush()
            shotgun.upload('Ticket', ticket_id, fh.name, 'attachments',
               display_name='Ticket-%d.%s.%s.txt' % (
                    ticket_id,
                    exc_type.__name__ if exc_type else 'details',
                    datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
                ),
            )

    return reply and reply['id'], content

def attach_to_ticket(ticket_id, attachment):
    """Attach a file to a ticket."""
    shotgun = get_shotgun()
    shotgun.upload('Ticket', ticket_id, attachment, 'attachments')

if __name__ == '__main__':

    try:
        raise ValueError('this is a test')
    except:
        ticket_id = get_ticket_for_exception(*sys.exc_info(), title='Testing Ticket Submittion')
        print 'Ticket ID', ticket_id
        reply_id, _ = reply_to_ticket(ticket_id, {
            'User Comment': 'This is just a test',
            'Exception': sys.exc_info(),
        })
        print 'Reply ID', reply_id
<|endoftext|>


<commit_before><commit_msg>implement 'method' in QuadTree.querypt<commit_after><|endoftext|>


<commit_before>#!/usr/bin/env python3
#
# This file is part of Maker Keeper Framework.
#
# Copyright (C) 2017 reverendus
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import argparse
import time

from api import Address, Transfer
from api.otc import SimpleMarket
from api.numeric import Ray
from api.numeric import Wad
from api.sai import Tub, Lpc
from api.token import ERC20Token
from api.transact import Invocation, TxManager
from keepers import Keeper
from keepers.arbitrage.conversion import LpcTakeAltConversion
from keepers.arbitrage.conversion import LpcTakeRefConversion
from keepers.arbitrage.conversion import OasisTakeConversion
from keepers.arbitrage.conversion import TubBoomConversion
from keepers.arbitrage.conversion import TubBustConversion
from keepers.arbitrage.conversion import TubExitConversion
from keepers.arbitrage.conversion import TubJoinConversion
from keepers.arbitrage.opportunity import OpportunityFinder
from keepers.arbitrage.transfer_formatter import TransferFormatter

class SaiArbitrage(Keeper):
    def args(self, parser: argparse.ArgumentParser):
        parser.add_argument("--frequency", help="Monitoring frequency in seconds (default: 5)", default=5, type=float)
        parser.add_argument("--minimum-profit", help="Minimum profit in SAI from one arbitrage operation (default: 0.01)", default=0.01, type=float)
        parser.add_argument("--maximum-engagement", help="Maximum engagement in SAI in one arbitrage operation (default: 1000)", default=1000, type=float)

    def init(self):
        self.tub_address = Address(self.config.get_contract_address("saiTub"))
        self.tap_address = Address(self.config.get_contract_address("saiTap"))
        self.top_address = Address(self.config.get_contract_address("saiTop"))
        self.tub = Tub(web3=self.web3, address_tub=self.tub_address, address_tap=self.tap_address, address_top=self.top_address)
        self.lpc_address = Address(self.config.get_contract_address("saiLpc"))
        self.lpc = Lpc(web3=self.web3, address=self.lpc_address)
        self.otc_address = Address(self.config.get_contract_address("otc"))
        self.otc = SimpleMarket(web3=self.web3, address=self.otc_address)

        self.skr = ERC20Token(web3=self.web3, address=self.tub.skr())
        self.sai = ERC20Token(web3=self.web3, address=self.tub.sai())
        self.gem = ERC20Token(web3=self.web3, address=self.tub.gem())
        ERC20Token.register_token(self.tub.skr(), 'SKR')
        ERC20Token.register_token(self.tub.sai(), 'SAI')
        ERC20Token.register_token(self.tub.gem(), 'WETH')

        self.tx_manager_address = Address(self.config.get_contract_address("txManager"))
        if self.tx_manager_address:
            self.tx_manager = TxManager(web3=self.web3, address=self.tx_manager_address)
        else:
            self.tx_manager = None

        self.base_token = self.sai
        self.minimum_profit = Wad.from_number(self.arguments.minimum_profit)
        self.maximum_engagement = Wad.from_number(self.arguments.maximum_engagement)

    def run(self):
        self.print_balances()
        self.setup_allowances()
        while True:
            self.execute_best_opportunity_available()
            time.sleep(self.arguments.frequency)

    def print_balances(self):
        def balances():
            for token in [self.sai, self.skr, self.gem]:
                yield f"{token.balance_of(self.our_address)} {token.name()}"
        print(f"Keeper balances are {', '.join(balances())}.")

    def setup_allowances(self):
        """Approve all components that need to access our balances"""
        self.setup_tub_allowances()
        self.setup_lpc_allowances()
        self.setup_otc_allowances()

    def setup_tub_allowances(self):
        """Approve Tub components so we can call join()/exit() and boom()/bust()"""
        self.setup_allowance(self.gem, self.tub.jar(), 'Tub.jar')
        self.setup_allowance(self.skr, self.tub.jar(), 'Tub.jar')
        self.setup_allowance(self.skr, self.tub.pit(), 'Tub.pit')
        self.setup_allowance(self.sai, self.tub.pit(), 'Tub.pit')

    def setup_lpc_allowances(self):
        """Approve the Lpc so we can exchange WETH and SAI using it"""
        self.setup_allowance(self.gem, self.lpc.address, 'Lpc')
        self.setup_allowance(self.sai, self.lpc.address, 'Lpc')

    def setup_otc_allowances(self):
        """Approve OasisDEX so we can exchange all three tokens (WETH, SAI and SKR)"""
        self.setup_allowance(self.gem, self.otc.address, 'OasisDEX')
        self.setup_allowance(self.sai, self.otc.address, 'OasisDEX')
        self.setup_allowance(self.skr, self.otc.address, 'OasisDEX')

    def setup_allowance(self, token: ERC20Token, spender_address: Address, spender_name: str):
        if token.allowance_of(self.our_address, spender_address) < Wad(2 ** 128 - 1):
            print(f"  Approving {spender_name} ({spender_address}) to access our {token.name()} balance directly...")
            if not token.approve(spender_address):
                print(f"  Approval failed!")
                exit(-1)

        if self.tx_manager:
            if token.allowance_of(self.tx_manager.address, spender_address) < Wad(2 ** 128 - 1):
                print(f"  Approving {spender_name} ({spender_address}) to access our {token.name()} balance via txManager...")
                invocation = Invocation(address=token.address, calldata=token.approve_calldata(spender_address))
                if not self.tx_manager.execute([], [invocation]):
                    print(f"  Approval failed!")
                    exit(-1)

    def tub_conversions(self):
        return [TubJoinConversion(self.tub),
                TubExitConversion(self.tub),
                TubBoomConversion(self.tub),
                TubBustConversion(self.tub)]

    def lpc_conversions(self):
        return [LpcTakeRefConversion(self.lpc),
                LpcTakeAltConversion(self.lpc)]

    def otc_offers(self, tokens):
        offers = [self.otc.get_offer(offer_id + 1) for offer_id in range(self.otc.get_last_offer_id())]
        offers = [offer for offer in offers if offer is not None]
        return [offer for offer in offers if offer.sell_which_token in tokens and offer.buy_which_token in tokens]

    def otc_conversions(self, tokens):
        return list(map(lambda offer: OasisTakeConversion(self.otc, offer), self.otc_offers(tokens)))

    def all_conversions(self):
        return self.tub_conversions() + self.lpc_conversions() + \
               self.otc_conversions([self.sai.address, self.skr.address, self.gem.address])

    def execute_best_opportunity_available(self):
        """Find the best arbitrage opportunity present and execute it."""
        opportunity = self.best_opportunity(self.profitable_opportunities())
        if opportunity:
            self.print_opportunity(opportunity)
            if self.tx_manager:
                self.execute_opportunity_in_one_transaction(opportunity)
            else:
                self.execute_opportunity_step_by_step(opportunity)

    def profitable_opportunities(self):
        """Identify all profitable arbitrage opportunities within given limits."""
        entry_amount = Wad.min(self.base_token.balance_of(self.our_address), self.maximum_engagement)
        opportunity_finder = OpportunityFinder(conversions=self.all_conversions())
        opportunities = opportunity_finder.find_opportunities(self.base_token.address, entry_amount)
        opportunities = filter(lambda op: op.total_rate() > Ray.from_number(1.000001), opportunities)
        opportunities = filter(lambda op: op.net_profit(self.base_token.address) > self.minimum_profit, opportunities)
        opportunities = sorted(opportunities, key=lambda op: op.net_profit(self.base_token.address), reverse=True)
        return opportunities

    def best_opportunity(self, opportunities):
        """Pick the best opportunity, or return None if no profitable opportunities."""
        return opportunities[0] if len(opportunities) > 0 else None

    def print_opportunity(self, opportunity):
        """Print the details of the opportunity."""
        print(f"")
        print(f"Opportunity with net_profit={opportunity.net_profit(self.base_token.address)} {self.base_token.name()}")
        for index, conversion in enumerate(opportunity.conversions, start=1):
            print(f"Step {index}/{len(opportunity.conversions)}:")
            print(f"  Exchange {conversion.source_amount} {ERC20Token.token_name_by_address(conversion.source_token)} "
                  f"to {conversion.target_amount} {ERC20Token.token_name_by_address(conversion.target_token)}")
            print(f"  Using {conversion.name()}")
            print(f"  {conversion}")

    def execute_opportunity_step_by_step(self, opportunity):
        """Execute the opportunity step-by-step."""
        all_transfers = []
        for index, conversion in enumerate(opportunity.conversions, start=1):
            print(f"Executing step {index}/{len(opportunity.conversions)}... ", end='', flush=True)
            receipt = conversion.execute()
            if receipt is None:
                print(f"FAILED!")
                print(f"")
                print(f"Interrupting the process... Will start over from scratch in the next iteration.")
                return
            else:
                print(f"ok (tx_hash={receipt.transaction_hash})")
                all_transfers += receipt.transfers
                outgoing = TransferFormatter().format(filter(Transfer.outgoing(self.our_address), receipt.transfers))
                incoming = TransferFormatter().format(filter(Transfer.incoming(self.our_address), receipt.transfers))
                print(f"  Exchanged {outgoing} to {incoming}")
        print(f"All steps executed successfully.")
        print(f"The profit we made is {TransferFormatter().format_net(all_transfers, self.our_address)}.")
        self.print_balances()

    def execute_opportunity_in_one_transaction(self, opportunity):
        """Execute the opportunity in one transaction, using the `tx_manager`."""
        print(f"Executing all steps in one transaction... ", end='', flush=True)

        invocations = list(map(lambda conv: Invocation(conv.address(), conv.calldata()), opportunity.conversions))
        receipt = self.tx_manager.execute([self.sai.address, self.skr.address, self.gem.address], invocations)
        if receipt:
            print(f"ok (tx_hash={receipt.transaction_hash})")
            print(f"The profit we made is {TransferFormatter().format_net(receipt.transfers, self.our_address)}.")
        else:
            print(f"FAILED!")
            exit(-1) #TODO while we debug

if __name__ == '__main__':
    SaiArbitrage().start()
<commit_msg>Passing the `TxManager` address as a commandline parameter<commit_after>#!/usr/bin/env python3
#
# This file is part of Maker Keeper Framework.
#
# Copyright (C) 2017 reverendus
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import argparse
import time
from typing import List

from api import Address, Transfer
from api.numeric import Ray
from api.numeric import Wad
from api.otc import SimpleMarket
from api.sai import Tub, Lpc
from api.token import ERC20Token
from api.transact import Invocation, TxManager
from keepers import Keeper
from keepers.arbitrage.conversion import Conversion
from keepers.arbitrage.conversion import LpcTakeAltConversion, LpcTakeRefConversion
from keepers.arbitrage.conversion import OasisTakeConversion
from keepers.arbitrage.conversion import TubBoomConversion, TubBustConversion, TubExitConversion, TubJoinConversion
from keepers.arbitrage.opportunity import OpportunityFinder
from keepers.arbitrage.transfer_formatter import TransferFormatter

class SaiArbitrage(Keeper):
    def args(self, parser: argparse.ArgumentParser):
        parser.add_argument("--frequency", help="Monitoring frequency in seconds (default: 5)", default=5, type=float)
        parser.add_argument("--minimum-profit", help="Minimum profit in SAI from one arbitrage operation (default: 0.01)", default=0.01, type=float)
        parser.add_argument("--maximum-engagement", help="Maximum engagement in SAI in one arbitrage operation (default: 1000)", default=1000, type=float)
        parser.add_argument("--tx-manager", help="Address of the TxManager to use for multi-step arbitrage", type=str)

    def init(self):
        self.tub_address = Address(self.config.get_contract_address("saiTub"))
        self.tap_address = Address(self.config.get_contract_address("saiTap"))
        self.top_address = Address(self.config.get_contract_address("saiTop"))
        self.tub = Tub(web3=self.web3, address_tub=self.tub_address, address_tap=self.tap_address, address_top=self.top_address)
        self.lpc_address = Address(self.config.get_contract_address("saiLpc"))
        self.lpc = Lpc(web3=self.web3, address=self.lpc_address)
        self.otc_address = Address(self.config.get_contract_address("otc"))
        self.otc = SimpleMarket(web3=self.web3, address=self.otc_address)

        self.skr = ERC20Token(web3=self.web3, address=self.tub.skr())
        self.sai = ERC20Token(web3=self.web3, address=self.tub.sai())
        self.gem = ERC20Token(web3=self.web3, address=self.tub.gem())
        ERC20Token.register_token(self.tub.skr(), 'SKR')
        ERC20Token.register_token(self.tub.sai(), 'SAI')
        ERC20Token.register_token(self.tub.gem(), 'WETH')

        self.base_token = self.sai
        self.minimum_profit = Wad.from_number(self.arguments.minimum_profit)
        self.maximum_engagement = Wad.from_number(self.arguments.maximum_engagement)

        if self.arguments.tx_manager:
            self.tx_manager_address = Address(self.arguments.tx_manager)
            self.tx_manager = TxManager(web3=self.web3, address=self.tx_manager_address)
        else:
            self.tx_manager_address = None
            self.tx_manager = None

    def run(self):
        self.setup_allowances()
        self.print_balances()
        while True:
            self.execute_best_opportunity_available()
            time.sleep(self.arguments.frequency)

    def print_balances(self):
        def balances():
            for token in [self.sai, self.skr, self.gem]:
                yield f"{token.balance_of(self.our_address)} {token.name()}"
        print(f"Keeper balances are {', '.join(balances())}.")

    def setup_allowances(self):
        """Approve all components that need to access our balances"""
        self.setup_tub_allowances()
        self.setup_lpc_allowances()
        self.setup_otc_allowances()

    def setup_tub_allowances(self):
        """Approve Tub components so we can call join()/exit() and boom()/bust()"""
        self.setup_allowance(self.gem, self.tub.jar(), 'Tub.jar')
        self.setup_allowance(self.skr, self.tub.jar(), 'Tub.jar')
        self.setup_allowance(self.skr, self.tub.pit(), 'Tub.pit')
        self.setup_allowance(self.sai, self.tub.pit(), 'Tub.pit')

    def setup_lpc_allowances(self):
        """Approve the Lpc so we can exchange WETH and SAI using it"""
        self.setup_allowance(self.gem, self.lpc.address, 'Lpc')
        self.setup_allowance(self.sai, self.lpc.address, 'Lpc')

    def setup_otc_allowances(self):
        """Approve OasisDEX so we can exchange all three tokens (WETH, SAI and SKR)"""
        self.setup_allowance(self.gem, self.otc.address, 'OasisDEX')
        self.setup_allowance(self.sai, self.otc.address, 'OasisDEX')
        self.setup_allowance(self.skr, self.otc.address, 'OasisDEX')

    def setup_allowance(self, token: ERC20Token, spender_address: Address, spender_name: str):
        if token.allowance_of(self.our_address, spender_address) < Wad(2 ** 128 - 1):
            print(f"Approving {spender_name} ({spender_address}) to access our {token.name()} balance directly...")
            if not token.approve(spender_address):
                print(f"Approval failed!")
                exit(-1)

        if self.tx_manager and token.allowance_of(self.tx_manager.address, spender_address) < Wad(2 ** 128 - 1):
            print(f"Approving {spender_name} ({spender_address}) to access our {token.name()} balance indirectly...")
            invocation = Invocation(address=token.address, calldata=token.approve_calldata(spender_address))
            if not self.tx_manager.execute([], [invocation]):
                print(f"Approval failed!")
                exit(-1)

    def tub_conversions(self) -> List[Conversion]:
        return [TubJoinConversion(self.tub),
                TubExitConversion(self.tub),
                TubBoomConversion(self.tub),
                TubBustConversion(self.tub)]

    def lpc_conversions(self) -> List[Conversion]:
        return [LpcTakeRefConversion(self.lpc),
                LpcTakeAltConversion(self.lpc)]

    def otc_offers(self, tokens):
        offers = [self.otc.get_offer(offer_id + 1) for offer_id in range(self.otc.get_last_offer_id())]
        offers = [offer for offer in offers if offer is not None]
        return [offer for offer in offers if offer.sell_which_token in tokens and offer.buy_which_token in tokens]

    def otc_conversions(self, tokens) -> List[Conversion]:
        return list(map(lambda offer: OasisTakeConversion(self.otc, offer), self.otc_offers(tokens)))

    def all_conversions(self):
        return self.tub_conversions() + self.lpc_conversions() + \
               self.otc_conversions([self.sai.address, self.skr.address, self.gem.address])

    def execute_best_opportunity_available(self):
        """Find the best arbitrage opportunity present and execute it."""
        opportunity = self.best_opportunity(self.profitable_opportunities())
        if opportunity:
            self.print_opportunity(opportunity)
            self.execute_opportunity(opportunity)

    def profitable_opportunities(self):
        """Identify all profitable arbitrage opportunities within given limits."""
        entry_amount = Wad.min(self.base_token.balance_of(self.our_address), self.maximum_engagement)
        opportunity_finder = OpportunityFinder(conversions=self.all_conversions())
        opportunities = opportunity_finder.find_opportunities(self.base_token.address, entry_amount)
        opportunities = filter(lambda op: op.total_rate() > Ray.from_number(1.000001), opportunities)
        opportunities = filter(lambda op: op.net_profit(self.base_token.address) > self.minimum_profit, opportunities)
        opportunities = sorted(opportunities, key=lambda op: op.net_profit(self.base_token.address), reverse=True)
        return opportunities

    def best_opportunity(self, opportunities):
        """Pick the best opportunity, or return None if no profitable opportunities."""
        return opportunities[0] if len(opportunities) > 0 else None

    def print_opportunity(self, opportunity):
        """Print the details of the opportunity."""
        print(f"")
        print(f"Opportunity with net_profit={opportunity.net_profit(self.base_token.address)} {self.base_token.name()}")
        for index, conversion in enumerate(opportunity.conversions, start=1):
            print(f"Step {index}/{len(opportunity.conversions)}:")
            print(f"  Exchange {conversion.source_amount} {ERC20Token.token_name_by_address(conversion.source_token)} "
                  f"to {conversion.target_amount} {ERC20Token.token_name_by_address(conversion.target_token)}")
            print(f"  Using {conversion.name()}")
            print(f"  {conversion}")

    def execute_opportunity(self, opportunity):
        """Execute the opportunity either in one Ethereum transaction or step-by-step.
        Depending on whether `tx_manager` is available."""
        if self.tx_manager:
            self.execute_opportunity_in_one_transaction(opportunity)
        else:
            self.execute_opportunity_step_by_step(opportunity)

    def execute_opportunity_step_by_step(self, opportunity):
        """Execute the opportunity step-by-step."""
        all_transfers = []
        for index, conversion in enumerate(opportunity.conversions, start=1):
            print(f"Executing step {index}/{len(opportunity.conversions)}... ", end='', flush=True)
            receipt = conversion.execute()
            if receipt is None:
                print(f"FAILED!")
                print(f"")
                print(f"Interrupting the process... Will start over from scratch in the next iteration.")
                return
            else:
                print(f"ok (tx_hash={receipt.transaction_hash})")
                all_transfers += receipt.transfers
                outgoing = TransferFormatter().format(filter(Transfer.outgoing(self.our_address), receipt.transfers))
                incoming = TransferFormatter().format(filter(Transfer.incoming(self.our_address), receipt.transfers))
                print(f"  Exchanged {outgoing} to {incoming}")
        print(f"All steps executed successfully.")
        print(f"The profit we made is {TransferFormatter().format_net(all_transfers, self.our_address)}.")
        self.print_balances()

    def execute_opportunity_in_one_transaction(self, opportunity):
        """Execute the opportunity in one transaction, using the `tx_manager`."""
        print(f"Executing all steps in one transaction... ", end='', flush=True)

        invocations = list(map(lambda conv: Invocation(conv.address(), conv.calldata()), opportunity.conversions))
        receipt = self.tx_manager.execute([self.sai.address, self.skr.address, self.gem.address], invocations)
        if receipt:
            print(f"ok (tx_hash={receipt.transaction_hash})")
            print(f"The profit we made is {TransferFormatter().format_net(receipt.transfers, self.our_address)}.")
        else:
            print(f"FAILED!")
            exit(-1) #TODO while we debug

if __name__ == '__main__':
    SaiArbitrage().start()
<|endoftext|>