<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
from weakref import ref

class SLLNode:
    """ Node model """
    __slots__ = ['next', 'value', 'weakref']

    def __init__(self, value=None, next=None, weakref=None):
        self.next = next
        self.value = value
        self.weakref = weakref

    def __call__(self):
        return self.value

    def __str__(self):
        return str(self.value)

    def __repr__(self):
        return str(self.value)

class SLList:
    """ SLList model """
    __slots__ = ['first', 'last', 'size']

    def __init__(self, iterable=None):
        self.first = None
        self.last = None
        self.size = 0
        if iterable:
            self.__extend(iterable)

    def __extend(self, iterable):
        for item in iterable:
            self.appendright(item)

    def __iter__(self):
        curr = self.first
        while curr:
            yield curr
            curr = curr.next

    def __str__(self):
        return str(list(self))

    def __getitem__(self, index):
        i = 0
        if index < 0 and index > self.size:
            raise IndexError("Not such index")
        curr = self.first
        while(curr != None and i < index):
            curr = curr.next
            i += 1
        return curr

    def __setitem__(self, index, value):
        node = self.__getitem__(index)
        if isinstance(value, SLLNode):
            value = value.value
        node.value = value

    def __get_prev(self, node):
        if not isinstance(node, SLLNode):
            raise TypeError("Object must be Node instance")
        if not self.first:
            raise TypeError("List is empty")
        if self.first == node:
            return None
        curr = self.first
        prev = None
        while(curr and curr != node):
            prev = curr
            curr = curr.next
        del curr
        return prev

    def appendleft(self, value):
        if isinstance(value, SLLNode):
            value = value.value

        head = self.first
        new_node = SLLNode(value=value, next=head, weakref=ref(self))
        self.first = new_node
        return new_node

    def append(self, value):
        return self.appendright(value)

    def appendright(self, value):
        if isinstance(value, SLLNode):
            value = value.value

        new_node = SLLNode(value=value, next=None, weakref=ref(self))
        if not self.first:
            self.first = new_node
        else:
            self.last.next = new_node
        self.last = new_node
        self.size += 1
        return new_node

    def popleft(self):
        if not self.first:
            raise RuntimeError("List is empty")
        del_node = self.first
        self.first = del_node.next
        if self.last == del_node:
            self.last = None
        self.size -= 1
        rval = del_node.value
        del del_node
        return rval

    def pop(self):
        return self.popright()

    def popright(self):
        if not self.first:
            raise RuntimeError("List is empty")
        del_node = self.last
        if self.first == del_node:
            self.last = None
            self.first = None
        else:
            prev = self.__get_prev(del_node)
            prev.next = None
            self.last = prev
        self.size -= 1
        rval = del_node.value
        del del_node
        return rval

    def remove(self, node):
        if not node.weakref == ref(self):
            raise RuntimeError("Node is not element of this list")
        prev = self.__get_prev(node)
        if not prev:
            self.popleft()
        else:
            prev.next = node.next
        rval = node.value
        del node
        return rval

if __name__ == '__main__':
    l = SLList(range(100, 115))
    print "Initialized list", l
    for i in range(0, 10):
        l.appendleft(i)
    print "After append left", l
    for i in range(0, 10):
        l.appendright(i)
    print "After append right", l
    for i in range(0, 10):
        l.popleft()
    print "After pop left", l
    for i in range(0, 10):
        l.popright()
    print "After pop right", l
<commit_msg>fixed bugs, c&p cmp method<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

class sllistnode(object):
    __slots__ = ('__next', '__value', '__owner')

    def __init__(self, value=None, next=None, owner=None):
        self.__next = next
        self.__value = value
        self.__owner = owner

    @property
    def next(self):
        return self.__next

    @property
    def value(self):
        return self.__value

    @property
    def owner(self):
        return self.__owner

    def __call__(self):
        return self.__value

    def __str__(self):
        return "sllistnode(%s)" % str(self.__value)

    def __repr__(self):
        return "<sllistnode(%s)>" % repr(self.__value)

class sllistiterator(object):
    __slots__ = ('__current_node', )

    def __init__(self, list):
        if not isinstance(list, sllist):
            raise TypeError('sllist argument expected')

        self.__current_node = list.first

    def next(self):
        if self.__current_node is None:
            raise StopIteration

        value = self.__current_node.value
        self.__current_node = self.__current_node.next

        return value

    def __iter__(self):
        return self

class sllist(object):
    __slots__ = ('__first', '__last', '__size', )

    def __init__(self, iterable=None):
        self.__first = None
        self.__last = None
        self.__size = 0
        if iterable:
            self.__extend(iterable)

    @property
    def first(self):
        return self.__first

    @property
    def last(self):
        return self.__last

    @property
    def size(self):
        return self.__size

    def __extend(self, iterable):
        for item in iterable:
            self.appendright(item)

    def __delitem__(self, index):
        to_del = self.__getitem__(index)
        self.remove(to_del)

    def __getitem__(self, index):
        if abs(index) >= self.__size:
            raise IndexError("list index out of range (%s) %s" % (index, self))
        i = 0
        if index < 0:
            index = self.__size + index
        if not self.__first:
            raise IndexError("list index out of range (%s) %s" % (index, self))
        curr = self.__first
        while(curr != None and i < index):
            curr = curr.next
            i += 1
        return curr

    def __len__(self):
        return self.__size

    def __setitem__(self, index, value):
        node = self.__getitem__(index)
        if isinstance(value, sllistnode):
            value = value.value
        node.value = value

    def __cmp__(self, other):
        result = len(self) - len(other)
        if result < 0:
            return -1
        elif result > 0:
            return 1

        for sval, oval in zip(self, other):
            result = cmp(sval, oval)
            if result != 0:
                return result

        return 0

    def __str__(self):
        if self.__first is not None:
            return 'sllist([' + ', '.join((str(x) for x in self)) + '])'
        else:
            return 'sllist()'

    def __repr__(self):
        if self.__first is not None:
            return 'sllist([' + ', '.join((repr(x) for x in self)) + '])'
        else:
            return 'sllist()'

    def __iter__(self):
        return sllistiterator(self)

    def __get_prev(self, node):
        if not isinstance(node, sllistnode):
            raise TypeError("Object must be Node instance")
        if not self.__first:
            raise IndexError("List is empty")
        if self.__first == node:
            return None
        curr = self.__first
        prev = None
        while(curr and curr != node):
            prev = curr
            curr = curr.next
        return prev

    def appendleft(self, value):
        if isinstance(value, sllistnode):
            value = value.value
        new_node = sllistnode(value=value, next=self.__first, owner=self)
        self.__first = new_node
        self.__size += 1
        return new_node

    def insert(self, value, before=None):
        if before is None:
            return self.appendright(value)
        else:
            return self.insertbefore(before, value)

    def insertafter(self, node, value):
        if not isinstance(node, sllistnode):
            raise TypeError("node must be instance of sllistnode")
        if isinstance(value, sllistnode):
            value = value.value
        new_node = sllistnode(value=value, next=None, owner=self)
        new_node._sllistnode__next = node.next
        node._sllistnode__next = new_node
        self.__size += 1
        return new_node

    def insertbefore(self, node, value):
        if not isinstance(node, sllistnode):
            raise TypeError("node must be instance of sllistnode")
        if isinstance(value, sllistnode):
            value = value.value
        new_node = sllistnode(value=value, next=None, owner=self)
        prev = self.__get_prev(node)
        if prev:
            prev._sllistnode__next = new_node
            new_node._sllistnode__next = node
        else:
            new_node._sllistnode__next = node
            self.__first = new_node
        self.__size += 1
        return new_node

    def append(self, value):
        return self.appendright(value)

    def appendright(self, value):
        if isinstance(value, sllistnode):
            value = value.value

        new_node = sllistnode(value=value, next=None, owner=self)
        if not self.__first:
            self.__first = new_node
        else:
            self.__last._sllistnode__next = new_node
        self.__last = new_node
        self.__size += 1
        return new_node

    def popleft(self):
        if not self.__first:
            raise RuntimeError("List is empty")
        del_node = self.__first
        self.__first = del_node.next
        if self.__last == del_node:
            self.__last = None
        self.__size -= 1
        return del_node.value

    def pop(self):
        return self.popright()

    def popright(self):
        if not self.__first:
            raise RuntimeError("List is empty")
        del_node = self.__last
        if self.__first == del_node:
            self.__last = None
            self.__first = None
        else:
            prev = self.__get_prev(del_node)
            prev._sllistnode__next = None
            self.__last = prev
        self.__size -= 1
        return del_node.value

    def remove(self, node):
        if not isinstance(node, sllistnode):
            raise TypeError("node must be a sllistnode")
        if self.__first is None:
            raise RuntimeError("List is empty")
        if node.owner != self:
            raise RuntimeError("Node is not element of this list")
        prev = self.__get_prev(node)
        if not prev:
            self.popleft()
        else:
            prev._sllistnode__next = node.next
            self.__size -= 1
        return node.value
<|endoftext|>


<commit_before>"""WSGI App Creator

This module is responsible for creating the basic Pylons WSGI application. It's generally
assumed that it will be called by Paste, though any WSGI application server could create
and call the WSGI app as well.

"""
import sys
import re
import inspect
import urllib

import paste.wsgiwrappers
import paste.httpexceptions as httpexceptions
from paste.registry import RegistryManager
from paste.wsgiwrappers import WSGIRequest

from routes import request_config

import pylons
import pylons.templating
from pylons.util import RequestLocal, class_name_from_module_name
from pylons.legacy import Myghty_Compat
from pylons.controllers import Controller, WSGIController

class PylonsBaseWSGIApp(object):
    """Basic Pylons WSGI Application

    This basic WSGI app is provided should a web developer want to
    get access to the most basic Pylons web application environment
    available. By itself, this Pylons web application does little more
    than dispatch to a controller and setup the context object, the
    request object, and the globals object.

    Additional functionality like sessions, and caching can be setup by
    altering the ``environ['pylons.environ_config']`` setting to indicate
    what key the ``session`` and ``cache`` functionality should come from.

    Resolving the URL and dispatching can be customized by sub-classing or
    "monkey-patching" this class. Subclassing is the preferred approach.

    """
    def __init__(self, mapper, package_name, globals, default_charset='UTF-8'):
        self.mapper = mapper
        self.globals = globals
        self.package_name = package_name
        self.default_charset = default_charset
        self.settings = dict(charset=default_charset, content_type='text/html')
        self.c = RequestLocal()
        config = globals.pylons_config

        # Create the redirect function we'll use and save it
        def redirect_to(url):
            raise httpexceptions.HTTPFound(url)
        self.redirect_to = redirect_to

        # Initialize Buffet and all our template engines, default engine is the
        # first in the template_engines list
        def_eng = config.template_engines.pop(0)
        self.buffet = pylons.templating.Buffet(def_eng['engine'],
            template_root=def_eng['template_root'], **def_eng['template_options'])
        for e in config.template_engines:
            self.buffet.prepare(e['engine'], template_root=e['template_root'],
                alias=e['alias'], **e['template_options'])

    def __call__(self, environ, start_response):
        self.setup_app_env(environ, start_response)
        if environ.get('paste.testing'):
            self.load_test_env(environ)

        # Change our HTTP_METHOD if _method is present, try GET first to avoid
        # parsing POST unless absolutely necessary.
        req = pylons.request.current_obj()
        old_method = None
        if req.GET.has_key('_method'):
            old_method = environ['REQUEST_METHOD']
            environ['REQUEST_METHOD'] = req.GET['_method']
        elif req.POST.has_key('_method'):
            old_method = environ['REQUEST_METHOD']
            environ['REQUEST_METHOD'] = req.POST['_method']

        controller = self.resolve(environ, start_response)
        if old_method: environ['REQUEST_METHOD'] = old_method
        response = self.dispatch(controller, environ, start_response)

        if environ.get('paste.testing') and hasattr(response, 'wsgi_response'):
            environ['paste.testing_variables']['response'] = response

        # Transform HttpResponse objects into WSGI response
        if hasattr(response, 'wsgi_response'):
            status, response_headers, content = response.wsgi_response()
            start_response(status, response_headers)
            return content
        elif response:
            return response

        # Apparently we returned absolutely nothing, use the response
        # object if in legacy mode, otherwise raise an exception
        if environ.get('pylons.legacy'):
            resp = pylons.helpers.response
            if hasattr(pylons.helpers.response, 'wsgicall'):
                # Legacy app using run_wsgi
                return resp.content
            status, response_headers, content = resp.wsgi_response()
            start_response(status, response_headers)
            return content
        else:
            raise Exception, "No content returned by controller: %s" % controller.__name__

    def setup_app_env(self, environ, start_response):
        """Setup and register all the Pylons objects with the registry"""
        req = WSGIRequest(environ)
        environ['paste.registry'].register(paste.wsgiwrappers.settings, self.settings)
        environ['paste.registry'].register(pylons.request, req)
        environ['paste.registry'].register(pylons.c, self.c)
        environ['paste.registry'].register(pylons.g, self.globals)
        environ['paste.registry'].register(pylons.buffet, self.buffet)
        pylons.h()
        self.c._clear()

        # Setup legacy globals
        if environ.get('pylons.legacy'):
            environ['paste.registry'].register(pylons.helpers.response, WSGIResponse())
            environ['paste.registry'].register(pylons.m, Myghty_Compat(environ, start_response))
            environ['paste.registry'].register(pylons.params, req.params)

        econf = environ['pylons.environ_config']
        if econf.get('session'):
            environ['paste.registry'].register(pylons.session, environ[econf['session']])
        if econf.get('cache'):
            environ['paste.registry'].register(pylons.cache, environ[econf['cache']])

    def resolve(self, environ, start_response):
        """Implements Routes-based dispatching"""
        config = request_config()
        config.mapper = self.mapper
        config.environ = environ
        config.redirect = self.redirect_to
        match = config.mapper_dict
        if not match:
            return None
        environ['pylons.routes_dict'] = match
        controller = match.get('controller')
        if not controller:
            return None

        # Pull the controllers class name, import controller
        # @@ TODO: Encapsulate in try/except to raise error if controller
        #          doesn't exist, or class in controller file doesn't exist.
        full_module_name = self.package_name + '.controllers.' \
            + controller.lower().replace('/', '.')

        __import__(full_module_name)
        module_name = full_module_name.split('.')[-1]
        class_name = class_name_from_module_name(module_name) + 'Controller'
        return getattr(sys.modules[full_module_name], class_name)

    def dispatch(self, controller, environ, start_response):
        """Dispatches to a controller, will instantiate the controller if
        necessary"""
        if not controller:
            raise httpexceptions.HTTPNotFound()
        match = environ['pylons.routes_dict']

        # Sanitaze keys
        # @@ TODO: This should be done in a lazy fashion
        for k,v in match.iteritems():
            if v:
                match[k] = urllib.unquote_plus(v)

        # Older subclass of Controller
        if inspect.isclass(controller) and not issubclass(controller, WSGIController) and \
                issubclass(controller, Controller):
            controller = controller()
            controller.start_response = start_response

            # @@ LEGACY: Attach c to controller
            if environ.get('pylons.legacy'):
                controller.c = pylons.c

            return controller(**match)

        # If the route included a path_info attribute, we'll assume it
        # should be pulled, otherwise we call the controller
        if match.get('path_info'):
            self.fixup_environ(environ, match)

        # If it's a class, instantiate it
        if not hasattr(controller, '__class__') or \
            getattr(controller, '__class__') == type:
            controller = controller()

        # Controller is assumed to handle a WSGI call
        return controller(environ, start_response)

    def fixup_environ(self, environ, dispatch):
        """Fixes the environ based on the Routes match"""
        oldpath = environ['PATH_INFO']
        newpath = dispatch.get('path_info') or ''
        environ['PATH_INFO'] = newpath
        if not environ['PATH_INFO'].startswith('/'):
            environ['PATH_INFO'] = '/' + environ['PATH_INFO']
        environ['SCRIPT_NAME'] += re.sub(r'^(.*?)/' + newpath + '$', r'\1', oldpath)
        if environ['SCRIPT_NAME'].endswith('/'):
            environ['SCRIPT_NAME'] = environ['SCRIPT_NAME'][:-1]

    def load_test_env(self, environ):
        """Sets up our Paste testing environment"""
        testenv = environ['paste.testing_variables']
        testenv['req'] = pylons.request.current_obj()
        testenv['c'] = pylons.c.current_obj()
        testenv['g'] = pylons.g.current_obj()
        econf = environ['pylons.environ_config']
        if econf.get('session'):
            testenv['session'] = environ[econf['session']]
        if econf.get('cache'):
            testenv['cache'] = environ[econf['cache']]

class PylonsApp(object):
    """Setup the Pylons default environment

    Pylons App sets up the basic Pylons app, and initializes the global
    object, sessions and caching. Sessions and caching can be overridden
    in the config object by supplying other keys to look for in the environ
    where objects for the session/cache will be. If they're set to none,
    then no session/cache objects will be available.

    """
    def __init__(self, config, default_charset='UTF-8'):
        self.config = config
        g = None
        try:
            package = __import__(config.package + '.lib.app_globals', globals(), locals(), ['Globals'])
        except ImportError:
            pass
        else:
            g = package.Globals(config.global_conf, config.app_conf, config=config)
            g.pylons_config = config

        # Create the base Pylons wsgi app
        app = PylonsBaseWSGIApp(config.map, config.package, g, default_charset)

        # Pull user-specified environ overrides, or just setup default
        # session and caching objects
        self.econf = econf = config.environ_config.copy()
        if not econf.has_key('session'):
            from beaker.session import SessionMiddleware
            econf['session'] = 'beaker.session'
            app = SessionMiddleware(app, config.global_conf,
                auto_register=True, **config.app_conf)

        if not econf.has_key('cache'):
            from beaker.cache import CacheMiddleware
            econf['cache'] = 'beaker.cache'
            app = CacheMiddleware(app, config.global_conf, **config.app_conf)

        self.globals = g
        self.app = app

    def __call__(self, environ, start_response):
        environ['pylons.environ_config'] = self.econf
        return self.app(environ, start_response)

WSGIResponse = None

class LegacyApp(object):
    def __init__(self, config):
        global WSGIResponse
        from paste.wsgiwrappers import WSGIResponse
        self.app = PylonsApp(config)
        self.globals = self.app.globals

    def __call__(self, environ, start_response):
        environ['pylons.legacy'] = True
        return self.app(environ, start_response)

def make_app(config):
    """ Legacy WSGI app creator"""
    papp = LegacyApp(config)
    from paste.deploy.config import ConfigMiddleware
    app = ConfigMiddleware(papp, {
        'default':config.global_conf,
        'app':config.app_conf,
        'app_conf':config.app_conf,
        'global_conf':config.global_conf
    })
    app = RegistryManager(app)
    app.globals = papp.globals
    return app
<commit_msg>[svn] typo<commit_after>"""WSGI App Creator

This module is responsible for creating the basic Pylons WSGI application. It's generally
assumed that it will be called by Paste, though any WSGI application server could create
and call the WSGI app as well.

"""
import sys
import re
import inspect
import urllib

import paste.wsgiwrappers
import paste.httpexceptions as httpexceptions
from paste.registry import RegistryManager
from paste.wsgiwrappers import WSGIRequest

from routes import request_config

import pylons
import pylons.templating
from pylons.util import RequestLocal, class_name_from_module_name
from pylons.legacy import Myghty_Compat
from pylons.controllers import Controller, WSGIController

class PylonsBaseWSGIApp(object):
    """Basic Pylons WSGI Application

    This basic WSGI app is provided should a web developer want to
    get access to the most basic Pylons web application environment
    available. By itself, this Pylons web application does little more
    than dispatch to a controller and setup the context object, the
    request object, and the globals object.

    Additional functionality like sessions, and caching can be setup by
    altering the ``environ['pylons.environ_config']`` setting to indicate
    what key the ``session`` and ``cache`` functionality should come from.

    Resolving the URL and dispatching can be customized by sub-classing or
    "monkey-patching" this class. Subclassing is the preferred approach.

    """
    def __init__(self, mapper, package_name, globals, default_charset='UTF-8'):
        self.mapper = mapper
        self.globals = globals
        self.package_name = package_name
        self.default_charset = default_charset
        self.settings = dict(charset=default_charset, content_type='text/html')
        self.c = RequestLocal()
        config = globals.pylons_config

        # Create the redirect function we'll use and save it
        def redirect_to(url):
            raise httpexceptions.HTTPFound(url)
        self.redirect_to = redirect_to

        # Initialize Buffet and all our template engines, default engine is the
        # first in the template_engines list
        def_eng = config.template_engines.pop(0)
        self.buffet = pylons.templating.Buffet(def_eng['engine'],
            template_root=def_eng['template_root'], **def_eng['template_options'])
        for e in config.template_engines:
            self.buffet.prepare(e['engine'], template_root=e['template_root'],
                alias=e['alias'], **e['template_options'])

    def __call__(self, environ, start_response):
        self.setup_app_env(environ, start_response)
        if environ.get('paste.testing'):
            self.load_test_env(environ)

        # Change our HTTP_METHOD if _method is present, try GET first to avoid
        # parsing POST unless absolutely necessary.
        req = pylons.request.current_obj()
        old_method = None
        if req.GET.has_key('_method'):
            old_method = environ['REQUEST_METHOD']
            environ['REQUEST_METHOD'] = req.GET['_method']
        elif req.POST.has_key('_method'):
            old_method = environ['REQUEST_METHOD']
            environ['REQUEST_METHOD'] = req.POST['_method']

        controller = self.resolve(environ, start_response)
        if old_method: environ['REQUEST_METHOD'] = old_method
        response = self.dispatch(controller, environ, start_response)

        if environ.get('paste.testing') and hasattr(response, 'wsgi_response'):
            environ['paste.testing_variables']['response'] = response

        # Transform HttpResponse objects into WSGI response
        if hasattr(response, 'wsgi_response'):
            status, response_headers, content = response.wsgi_response()
            start_response(status, response_headers)
            return content
        elif response:
            return response

        # Apparently we returned absolutely nothing, use the response
        # object if in legacy mode, otherwise raise an exception
        if environ.get('pylons.legacy'):
            resp = pylons.helpers.response
            if hasattr(pylons.helpers.response, 'wsgicall'):
                # Legacy app using run_wsgi
                return resp.content
            status, response_headers, content = resp.wsgi_response()
            start_response(status, response_headers)
            return content
        else:
            raise Exception, "No content returned by controller: %s" % controller.__name__

    def setup_app_env(self, environ, start_response):
        """Setup and register all the Pylons objects with the registry"""
        req = WSGIRequest(environ)
        environ['paste.registry'].register(paste.wsgiwrappers.settings, self.settings)
        environ['paste.registry'].register(pylons.request, req)
        environ['paste.registry'].register(pylons.c, self.c)
        environ['paste.registry'].register(pylons.g, self.globals)
        environ['paste.registry'].register(pylons.buffet, self.buffet)
        pylons.h()
        self.c._clear()

        # Setup legacy globals
        if environ.get('pylons.legacy'):
            environ['paste.registry'].register(pylons.helpers.response, WSGIResponse())
            environ['paste.registry'].register(pylons.m, Myghty_Compat(environ, start_response))
            environ['paste.registry'].register(pylons.params, req.params)

        econf = environ['pylons.environ_config']
        if econf.get('session'):
            environ['paste.registry'].register(pylons.session, environ[econf['session']])
        if econf.get('cache'):
            environ['paste.registry'].register(pylons.cache, environ[econf['cache']])

    def resolve(self, environ, start_response):
        """Implements Routes-based dispatching"""
        config = request_config()
        config.mapper = self.mapper
        config.environ = environ
        config.redirect = self.redirect_to
        match = config.mapper_dict
        if not match:
            return None
        environ['pylons.routes_dict'] = match
        controller = match.get('controller')
        if not controller:
            return None

        # Pull the controllers class name, import controller
        # @@ TODO: Encapsulate in try/except to raise error if controller
        #          doesn't exist, or class in controller file doesn't exist.
        full_module_name = self.package_name + '.controllers.' \
            + controller.lower().replace('/', '.')

        __import__(full_module_name)
        module_name = full_module_name.split('.')[-1]
        class_name = class_name_from_module_name(module_name) + 'Controller'
        return getattr(sys.modules[full_module_name], class_name)

    def dispatch(self, controller, environ, start_response):
        """Dispatches to a controller, will instantiate the controller if
        necessary"""
        if not controller:
            raise httpexceptions.HTTPNotFound()
        match = environ['pylons.routes_dict']

        # Sanitize keys
        # @@ TODO: This should be done in a lazy fashion
        for k,v in match.iteritems():
            if v:
                match[k] = urllib.unquote_plus(v)

        # Older subclass of Controller
        if inspect.isclass(controller) and not issubclass(controller, WSGIController) and \
                issubclass(controller, Controller):
            controller = controller()
            controller.start_response = start_response

            # @@ LEGACY: Attach c to controller
            if environ.get('pylons.legacy'):
                controller.c = pylons.c

            return controller(**match)

        # If the route included a path_info attribute, we'll assume it
        # should be pulled, otherwise we call the controller
        if match.get('path_info'):
            self.fixup_environ(environ, match)

        # If it's a class, instantiate it
        if not hasattr(controller, '__class__') or \
            getattr(controller, '__class__') == type:
            controller = controller()

        # Controller is assumed to handle a WSGI call
        return controller(environ, start_response)

    def fixup_environ(self, environ, dispatch):
        """Fixes the environ based on the Routes match"""
        oldpath = environ['PATH_INFO']
        newpath = dispatch.get('path_info') or ''
        environ['PATH_INFO'] = newpath
        if not environ['PATH_INFO'].startswith('/'):
            environ['PATH_INFO'] = '/' + environ['PATH_INFO']
        environ['SCRIPT_NAME'] += re.sub(r'^(.*?)/' + newpath + '$', r'\1', oldpath)
        if environ['SCRIPT_NAME'].endswith('/'):
            environ['SCRIPT_NAME'] = environ['SCRIPT_NAME'][:-1]

    def load_test_env(self, environ):
        """Sets up our Paste testing environment"""
        testenv = environ['paste.testing_variables']
        testenv['req'] = pylons.request.current_obj()
        testenv['c'] = pylons.c.current_obj()
        testenv['g'] = pylons.g.current_obj()
        econf = environ['pylons.environ_config']
        if econf.get('session'):
            testenv['session'] = environ[econf['session']]
        if econf.get('cache'):
            testenv['cache'] = environ[econf['cache']]

class PylonsApp(object):
    """Setup the Pylons default environment

    Pylons App sets up the basic Pylons app, and initializes the global
    object, sessions and caching. Sessions and caching can be overridden
    in the config object by supplying other keys to look for in the environ
    where objects for the session/cache will be. If they're set to none,
    then no session/cache objects will be available.

    """
    def __init__(self, config, default_charset='UTF-8'):
        self.config = config
        g = None
        try:
            package = __import__(config.package + '.lib.app_globals', globals(), locals(), ['Globals'])
        except ImportError:
            pass
        else:
            g = package.Globals(config.global_conf, config.app_conf, config=config)
            g.pylons_config = config

        # Create the base Pylons wsgi app
        app = PylonsBaseWSGIApp(config.map, config.package, g, default_charset)

        # Pull user-specified environ overrides, or just setup default
        # session and caching objects
        self.econf = econf = config.environ_config.copy()
        if not econf.has_key('session'):
            from beaker.session import SessionMiddleware
            econf['session'] = 'beaker.session'
            app = SessionMiddleware(app, config.global_conf,
                auto_register=True, **config.app_conf)

        if not econf.has_key('cache'):
            from beaker.cache import CacheMiddleware
            econf['cache'] = 'beaker.cache'
            app = CacheMiddleware(app, config.global_conf, **config.app_conf)

        self.globals = g
        self.app = app

    def __call__(self, environ, start_response):
        environ['pylons.environ_config'] = self.econf
        return self.app(environ, start_response)

WSGIResponse = None

class LegacyApp(object):
    def __init__(self, config):
        global WSGIResponse
        from paste.wsgiwrappers import WSGIResponse
        self.app = PylonsApp(config)
        self.globals = self.app.globals

    def __call__(self, environ, start_response):
        environ['pylons.legacy'] = True
        return self.app(environ, start_response)

def make_app(config):
    """ Legacy WSGI app creator"""
    papp = LegacyApp(config)
    from paste.deploy.config import ConfigMiddleware
    app = ConfigMiddleware(papp, {
        'default':config.global_conf,
        'app':config.app_conf,
        'app_conf':config.app_conf,
        'global_conf':config.global_conf
    })
    app = RegistryManager(app)
    app.globals = papp.globals
    return app
<|endoftext|>


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

import http.client
import urllib
import json
import hashlib

class OKCoinApi:
    """OKCoin and OKEX API interface.

    Developed according to the following manual:
    <https://www.okex.com/intro_apiOverview.html>.

    Inspired by the following example:
    <https://github.com/OKCoin/rest>, <https://github.com/OKCoin/rest/tree/master/python>.
    """

    def __init__(self, api_server: str, api_key: str, secret_key: str, timeout: float):
        assert(isinstance(api_server, str))
        assert(isinstance(api_key, str))
        assert(isinstance(secret_key, str))
        assert(isinstance(timeout, float))

        self.api_server = api_server
        self.api_key = api_key
        self.secret_key = secret_key
        self.timeout = timeout

    #Get OKCOIN spot market information
    def ticker(self, symbol):
        TICKER_RESOURCE = "/api/v1/ticker.do"
        params=''
        if symbol:
            params = 'symbol=%(symbol)s' %{'symbol':symbol}
        return self._http_get(TICKER_RESOURCE, params)

    #Obtain OKCOIN spot market depth information
    def depth(self, symbol):
        DEPTH_RESOURCE = "/api/v1/depth.do"
        params=''
        if symbol:
            params = 'symbol=%(symbol)s' %{'symbol':symbol}
        return self._http_get(DEPTH_RESOURCE, params)

    #Obtain OKCOIN spot historical transaction information
    def trades(self, symbol):
        TRADES_RESOURCE = "/api/v1/trades.do"
        params=''
        if symbol:
            params = 'symbol=%(symbol)s' %{'symbol':symbol}
        return self._http_get(TRADES_RESOURCE, params)

    #Get customer cash account information
    def userinfo(self):
        USERINFO_RESOURCE = "/api/v1/userinfo.do"
        params ={}
        params['api_key'] = self.api_key
        params['sign'] = self._build_my_sign(params)
        return self._http_post(USERINFO_RESOURCE, params)

    #Spot Trading
    def trade(self, symbol, tradeType, price='', amount=''):
        TRADE_RESOURCE = "/api/v1/trade.do"
        params = {
            'api_key':self.api_key,
            'symbol':symbol,
            'type':tradeType
        }
        if price:
            params['price'] = price
        if amount:
            params['amount'] = amount

        params['sign'] = self._build_my_sign(params)
        return self._http_post(TRADE_RESOURCE, params)

    #Spot bulk orders
    def batchTrade(self, symbol, tradeType, orders_data):
        BATCH_TRADE_RESOURCE = "/api/v1/batch_trade.do"
        params = {
            'api_key':self.api_key,
            'symbol':symbol,
            'type':tradeType,
            'orders_data':orders_data
        }
        params['sign'] = self._build_my_sign(params)
        return self._http_post(BATCH_TRADE_RESOURCE, params)

    #Spot cancel the order
    def cancelOrder(self, symbol, orderId):
        CANCEL_ORDER_RESOURCE = "/api/v1/cancel_order.do"
        params = {
             'api_key':self.api_key,
             'symbol':symbol,
             'order_id':orderId
        }
        params['sign'] = self._build_my_sign(params)
        return self._http_post(CANCEL_ORDER_RESOURCE, params)

    #Spot order information inquiry
    def orderinfo(self, symbol, orderId):
         ORDER_INFO_RESOURCE = "/api/v1/order_info.do"
         params = {
             'api_key':self.api_key,
             'symbol':symbol,
             'order_id':orderId
         }
         params['sign'] = self._build_my_sign(params)
         return self._http_post(ORDER_INFO_RESOURCE, params)

    #Spot bulk order information query
    def ordersinfo(self, symbol, orderId, tradeType):
         ORDERS_INFO_RESOURCE = "/api/v1/orders_info.do"
         params = {
             'api_key':self.api_key,
             'symbol':symbol,
             'order_id':orderId,
             'type':tradeType
         }
         params['sign'] = self._build_my_sign(params)
         return self._http_post(ORDERS_INFO_RESOURCE, params)

    #Spot to get historical order information
    def orderHistory(self, symbol, status, currentPage, pageLength):
           ORDER_HISTORY_RESOURCE = "/api/v1/order_history.do"
           params = {
              'api_key':self.api_key,
              'symbol':symbol,
              'status':status,
              'current_page':currentPage,
              'page_length':pageLength
           }
           params['sign'] = self._build_my_sign(params)
           return self._http_post(ORDER_HISTORY_RESOURCE, params)

    def _build_my_sign(self, params):
        sign = ''
        for key in sorted(params.keys()):
            sign += key + '=' + str(params[key]) + '&'
        data = sign + 'secret_key=' + self.secret_key
        return hashlib.md5(data.encode("utf8")).hexdigest().upper()

    def _http_get(self, resource, params=''):
        conn = http.client.HTTPSConnection(self.api_server, timeout=self.timeout)
        conn.request("GET", resource + '?' + params)
        response = conn.getresponse()
        data = response.read().decode('utf-8')
        return json.loads(data)

    def _http_post(self, resource, params):
        headers = {
            "Content-type": "application/x-www-form-urlencoded",
        }
        conn = http.client.HTTPSConnection(self.api_server, timeout=self.timeout)
        temp_params = urllib.parse.urlencode(params)
        conn.request("POST", resource, temp_params, headers)
        response = conn.getresponse()
        data = response.read().decode('utf-8')
        params.clear()
        conn.close()
        return data
<commit_msg>OKcoin API work in progress<commit_after># -*- coding: utf-8 -*-

import http.client
import urllib
import json
import hashlib

class OKCoinApi:
    """OKCoin and OKEX API interface.

    Developed according to the following manual:
    <https://www.okex.com/intro_apiOverview.html>.

    Inspired by the following example:
    <https://github.com/OKCoin/rest>, <https://github.com/OKCoin/rest/tree/master/python>.
    """

    def __init__(self, api_server: str, api_key: str, secret_key: str, timeout: float):
        assert(isinstance(api_server, str))
        assert(isinstance(api_key, str))
        assert(isinstance(secret_key, str))
        assert(isinstance(timeout, float))

        self.api_server = api_server
        self.api_key = api_key
        self.secret_key = secret_key
        self.timeout = timeout

    def ticker(self, symbol):
        return self._http_get("/api/v1/ticker.do", 'symbol=%(symbol)s' % {'symbol':symbol})

    def depth(self, symbol):
        return self._http_get("/api/v1/depth.do", 'symbol=%(symbol)s' % {'symbol':symbol})

    def trades(self, symbol):
        return self._http_get("/api/v1/trades.do", 'symbol=%(symbol)s' % {'symbol':symbol})

    def user_info(self):
        return self._http_post("/api/v1/userinfo.do", {})

    def place_order(self, symbol, tradeType, price='', amount=''):
        params = {
            'symbol':symbol,
            'type':tradeType
        }
        if price:
            params['price'] = price
        if amount:
            params['amount'] = amount

        return self._http_post("/api/v1/trade.do", params)

    def batch_place_order(self, symbol, trade_type, orders_data):
        params = {
            'symbol':symbol,
            'type':trade_type,
            'orders_data':orders_data
        }
        return self._http_post("/api/v1/batch_trade.do", params)

    def cancel_order(self, symbol, order_id):
        params = {
             'symbol':symbol,
             'order_id':order_id
        }
        return self._http_post("/api/v1/cancel_order.do", params)

    def orderinfo(self, symbol, order_id):
        params = {
         'symbol':symbol,
         'order_id':order_id
        }
        return self._http_post("/api/v1/order_info.do", params)

    def ordersinfo(self, symbol, order_id, trade_type):
        params = {
         'symbol':symbol,
         'order_id':order_id,
         'type':trade_type
        }
        return self._http_post("/api/v1/orders_info.do", params)

    def order_history(self, symbol, status, current_page, page_length):
        params = {
          'symbol':symbol,
          'status':status,
          'current_page':current_page,
          'page_length':page_length
        }
        return self._http_post("/api/v1/order_history.do", params)

    def _create_signature(self, params):
        sign = ''
        for key in sorted(params.keys()):
            sign += key + '=' + str(params[key]) + '&'
        data = sign + 'secret_key=' + self.secret_key
        return hashlib.md5(data.encode("utf8")).hexdigest().upper()

    def _http_get(self, resource: str, params: str):
        assert(isinstance(resource, str))
        assert(isinstance(params, str))

        conn = http.client.HTTPSConnection(self.api_server, timeout=self.timeout)
        conn.request("GET", resource + '?' + params)
        response = conn.getresponse()
        data = response.read().decode('utf-8')
        return json.loads(data)

    def _http_post(self, resource: str, params: dict):
        assert(isinstance(resource, str))
        assert(isinstance(params, dict))

        headers = {
            "Content-type": "application/x-www-form-urlencoded",
        }
        conn = http.client.HTTPSConnection(self.api_server, timeout=self.timeout)
        params['api_key'] = self.api_key
        params['sign'] = self._create_signature(params)
        temp_params = urllib.parse.urlencode(params)
        conn.request("POST", resource, temp_params, headers)
        response = conn.getresponse()
        data = response.read().decode('utf-8')
        params.clear()
        conn.close()
        return data
<|endoftext|>


<commit_before>"""Factories are responsible for decoding xml.etree Elements into pymm
Elements and encoding pymm Elements back to xml.etree Elements. Factories are
where to specify how the encoding and decoding of an element is handled. Attrib
encoding/decoding is handled here as well
"""
import xml.etree.ElementTree as ET
import warnings
import copy
import re
import types
from uuid import uuid4
from . import Elements

def decode(element):
    converter = ConversionHandler()
    return converter.convert_element_hierarchy(element, 'decode')

def encode(element):
    converter = ConversionHandler()
    return converter.convert_element_hierarchy(element, 'encode')

class ConversionHandler:

    def __init__(self):
        """Lock in set of factories for handling elements. If you
        create another element after instantiating ConversionHandler,
        get another instance to auto-generate a factory for that
        element. Otherwise, DefaultFactory will be used
        """
        self.factories = registry.get_factories()

    def find_encode_factory(self, element):
        for factory in reversed(self.factories):
            if factory.can_encode(element):
                return factory
        return DefaultFactory

    def find_decode_factory(self, element):
        """Return factory that can handle given element.
        Default to DefaultFactory
        """
        for factory in reversed(self.factories):
            if factory.can_decode(element):
                return factory
        return DefaultFactory

    def convert_element_hierarchy(self, element, convert):
        """encode or decode element and its hierarchy. Each element
        will be completely converted before its children begin the
        process
        """
        queue = [(None, [element])]  # parent, children
        root = None
        while queue:
            parent, children = queue.pop(0)
            if root is None and parent is not None:
                root = parent
            for child in children:
                if convert == 'encode':
                    factory_class = self.find_encode_factory(child)
                    factory = factory_class()
                    child, grandchildren = factory.encode(parent, child)
                elif convert == 'decode':
                    factory_class = self.find_decode_factory(child)
                    factory = factory_class()
                    child, grandchildren = factory.decode(parent, child)
                else:
                    raise ValueError('pass in "decode" or "encode"')
                # if convert fxn returns no decoded child, drop from hierarchy
                if child is not None:
                    queue.append((child, grandchildren))
        return root

class registry(type):
    """Metaclass to register all Factories created, and assist in
    creating new factories for unclaimed elements (elements without a
    corresponding factory
    """
    _factories = []
    verbose = False
    _skip_registration = ''

    @classmethod
    def get_factories(cls):
        factories = list(tuple(cls._factories))
        generated = cls.create_unclaimed_element_factories(factories)
        return factories + generated

    def __new__(mcs, clsname, bases, attr_dict):
        """create Factory-class, and register it in list of factories
        """
        FactoryClass = super().__new__(mcs, clsname, bases, attr_dict)
        # do not register factory if it was generated by this metaclass
        if clsname != mcs._skip_registration:
            mcs._factories.append(FactoryClass)
        return FactoryClass

    @classmethod
    def create_unclaimed_element_factories(cls, factories):
        """iterate all elements inheriting from Elements.BaseElement.
        For each element with no corresponding factory, create a factory
        to handle it, inheriting from closest-matching factory.
        Closest-matching factory is determined as the newest factory to
        use a decoding-element of which the unclaimed element is a
        subclass.

        Return list of all factories created in this way
        """
        generated = []
        for element in Elements.registry.get_elements():
            closest_match = DefaultFactory
            for factory in factories:
                if issubclass(element, factory.decoding_element):
                    closest_match = factory
                if factory.decoding_element == element:
                    break
            else:
                # create factory for unclaimed element
                if cls.verbose:
                    print(
                        'unclaimed element:', element,
                        '\n\t tag:', element.tag,
                        '\n\t identifier:', element.identifier,
                        '\n\t closest matching factory:', closest_match,
                    )
                element_name = getattr(element, '__name__', element.tag)
                name = element_name + '-Factory@' + uuid4().hex
                inherit_from = (closest_match,)
                variables = {'decoding_element': element}
                cls._skip_registration = name
                new_factory = type(name, inherit_from, variables)
                generated.append(new_factory)
        return generated

class DefaultElementFactory:
    """Expose methods to construct encoding / decoding element class
    given attrib and children. At this point in the conversion process,
    the attribs are converted but the children are not.
    It is the responsibility of this factory to add the converted
    element to it's parent.
    """

    def decode_element(
            self, parent, src_element, element_class, attrib, children):
        """create decoded element using element_class and decoded
        attrib. The children are not yet decoded, however.
        DO NOT ADD CHILDREN TO ELEMENT! The children are not yet
        decoded. Instead you should add the newly instantiated element
        to the parent's children list
        """
        element = element_class(**attrib)
        if parent is not None:
            parent.children.append(element)
        element.tag = getattr(src_element, 'tag', element_class.tag)
        element._text = getattr(src_element, 'text', '')
        element._tail = getattr(src_element, 'tail', '\n')
        return element

    def encode_element(
            self, parent, src_element, element_class, attrib, children):
        """create encoded element using element_class and pre-encoded
        arguments attrib & children. This is the function in which
        to create an xml.etree Element
        DO NOT ADD CHILDREN TO ELEMENT! the children are not yet
        encoded. Instead you should add the newly encoded element as a
        child to the parent
        """
        tag = getattr(src_element, 'tag', 'unknown_element')
        element = element_class(tag, **attrib)
        if parent is not None:
            parent.append(element)
        element.text = getattr(src_element, '_text', '')
        element.tail = getattr(src_element, '_tail', '\n')
        # add spacing if element has child (makes file more readable)
        if len(element) and not element.text:
            element.text = '\n'
        return element

class DefaultAttribFactory:
    """expose methods to encode/decode attrib"""

    def decode_attrib(self, attrib, src_element, dst_element_class):
        """Decode attrib (from etree element) to match the spec in
        pymm element. Warn user (but still allow attrib) if attrib
        key/value pair is not valid.
        """
        spec = dst_element_class.spec
        decoded_attrib = {}
        # decoding from et element: assume all keys and values are strings
        for key, value in attrib.items():
            key = self.stringify(key)
            value = self.stringify(value)
            value = self.decode_attrib_value(key, value, spec)
            decoded_attrib[key] = value
        return decoded_attrib

    def decode_attrib_value(self, key, value, spec):
        """Spec values are lists that contain expected attrib values OR
        expected type of value (such as bool, int, or a custom class).
        Convert to expected type or verify that value matches one of
        corresponding spec value. If spec does not contain key, return
        value unaltered. Generate warning if value matched none of the
        spec values and/or could not be cast to type specified
        """
        entries = spec.get(key)
        if entries is None:
            return value
        if not isinstance(entries, list):
            raise ValueError('spec value must be a list of choices/types')
        # break out of for loop if match found
        for entry in entries:
            if entry == value:
                break
            if isinstance(entry, type):  # bool, str, int, etc...
                # special handling for finding false bool
                if issubclass(entry, bool):
                    if value in ['0', 'false', 'False', 'FALSE']:
                        value = False
                        break
                try:
                    value = entry(value)  # decode value to new type
                    break
                except:
                    warnings.warn(
                        key + ': ' + value + 'not of type ' + str(entry)
                    )
                    continue  # try next entry
        else:
            warnings.warn(key + ': ' + value + ' does not match spec')
        return value

    def encode_attrib(self, attrib, src_element, dst_element_class):
        """using src_element (pymm element) spec, decode (again)
        attrib to expected type. Then cast each key: value pair to
        string. If a particular value in spec is None, the key: value
        will be dropped from the encoded attrib.

        :param mmElement - pymm element containing attrib to be
        encoded
        """
        attrib = {
            key: value for key, value in attrib.items() if \
            value is not None
        }
        spec = src_element.spec
        encoded_attrib = {}
        for key, value in attrib.items():
            if key in spec:
                value = self.decode_attrib_value(key, value, spec)
            value = self.stringify(value)
            key = self.stringify(key)
            encoded_attrib[key] = value
        return encoded_attrib

    def stringify(self, arg):
        """If possible, decode into string, else cast arg to string"""
        if isinstance(arg, str):
            return arg
        try:
            return arg.decode()
        except:
            return str(arg)

class DefaultGetAttributesFactory:
    """expose methods to get attrib and children from elements. This
    does NOT encode or decode the attrib or children, but instead
    simply returns the unaltered attribute (attrib or children)
    """

    def decode_getchildren(self, element):
        """return list of children from xml.etree element"""
        return list(element)

    def encode_getchildren(self, element):
        """return list of children from pymm element. It is recommended
        to return a copied list of children, so that any modification
        to the list does not change the original element's children
        """
        return list(element.children)

    def decode_getattrib(self, element):
        """return attrib dict from xml.etree element"""
        return dict(element.attrib)

    def encode_getattrib(self, element):
        """return attrib dict from pymm element"""
        return dict(element.attrib)

class DefaultChildFactory:
    """expose methods for retrieving list of children to encode/decode"""
    # order in which children will be written to file
    child_order = [
        Elements.BaseElement, Elements.ArrowLink, Elements.Cloud,
        Elements.Edge, Elements.Properties, Elements.MapStyles, Elements.Icon,
        Elements.AttributeLayout, Elements.Attribute, Elements.Hook,
        Elements.Font, Elements.StyleNode, Elements.RichContent, Elements.Node
    ]
    # order of nth to last for children. First node listed will be last child.
    reverse_child_order = []

class DefaultFactory(
        DefaultAttribFactory, DefaultElementFactory,
        DefaultGetAttributesFactory, metaclass=registry):
    """Factory with default methods for encoding and decoding between
    xml.ElementTree and pymm
    """
    decoding_element = Elements.BaseElement
    encoding_element = ET.Element

    def decode(self, parent, src_element):
        """control decode order from from xml.etree element to pymm
        element. Typical decoding order looks like:
        get_attrib, decode_attrib, get_children, decode_element
        """
        dst_element = self.decoding_element
        unaltered_attrib = self.decode_getattrib(src_element)
        attrib = self.decode_attrib(unaltered_attrib, src_element, dst_element)
        children = self.decode_getchildren(src_element)
        element = self.decode_element(
            parent, src_element, dst_element, attrib, children
        )
        return element, children

    def encode(self, parent, src_element):
        """control encode order from pymm element to xml.etree element.
        Typical encoding order looks like:
        get_children, get_attrib, encode_attrib, decode_element
        """
        dst_element = self.encoding_element
        children = self.encode_getchildren(src_element)
        unaltered_attrib = self.encode_getattrib(src_element)
        attrib = self.encode_attrib(unaltered_attrib, src_element, dst_element)
        element = self.encode_element(
            parent, src_element, dst_element, attrib, children
        )
        return element, children

    @classmethod
    def can_decode(cls, element):
        """return False is element.tag does not equal decoding
        element's tag.
        If decoding_element has identifier, only
        return True if all key/value pairs of identifier regex match
        attrib key/value pair
        """
        if element.tag != cls.decoding_element.tag:
            return False
        for key_id, val_id in cls.decoding_element.identifier.items():
            # return False if identifying key/val is not found in attrib
            for key, val in element.attrib.items():
                if re.fullmatch(key_id, key) and re.fullmatch(val_id, val):
                    break
            else:
                return False
        return True

    @classmethod
    def can_encode(cls, element):
        if isinstance(element, cls.decoding_element):
            return True
        return False

class NodeFactory(DefaultFactory):
    decoding_element = Elements.Node
    child_order = [
        Elements.BaseElement, Elements.ArrowLink, Elements.Cloud,
        Elements.Edge, Elements.Font, Elements.Hook, Elements.Properties,
        Elements.RichContent, Elements.Icon, Elements.Node,
        Elements.AttributeLayout, Elements.Attribute
    ]

    def decode_attrib(self, attrib, src_element, dst_element_class):
        """Replace undesired parts of attrib with desired parts.
        specifically: look for occasional LOCALIZED_TEXT attrib which
        is supposed to be TEXT
        """
        swapout = [('TEXT', 'LOCALIZED_TEXT')]
        for desired, undesired in swapout:
            if desired not in attrib and undesired in attrib:
                attrib[desired] = attrib[undesired]
                del attrib[undesired]
        return super().decode_attrib(attrib, src_element, dst_element_class)

    def encode_getchildren(self, element):
        """add attributes into children"""
        children = super().encode_getchildren(element)
        for name, value in element.items():
            child = Elements.Attribute(NAME=name, VALUE=value)
            children.append(child)
        return children

class MapFactory(DefaultFactory):
    decoding_element = Elements.Map

    def encode_element(
            self, parent, src_element, element_class, attrib, children):
        element = super().encode_element(
            parent, src_element, element_class, attrib, children)
        comment = ET.Comment(
            'To view this file, download free mind mapping software '
            + 'Freeplane from http://freeplane.sourceforge.net'
        )
        comment.tail = '\n'
        element.append(comment)
        return element

class AttributeFactory(DefaultFactory):
    """Attribute is a visual 2-wide cell beneath a node. It has a name
    and value. We want to instead push this into the parent node as if
    it were a dictionary: parent[name] = value
    """
    decoding_element = Elements.Attribute

    def decode_element(
            self, parent, src_element, element_class, attrib, children):
        if not isinstance(parent, Elements.Node):
            return super().encode_element(
                parent, src_element, element_class, attrib, children)
        if 'NAME' in attrib and 'VALUE' in attrib:
            name = attrib['NAME']
            value = attrib['VALUE']
            parent[name] = value
        return None  # stop decoding this element and its children

class RichContentFactory(DefaultFactory):
    decoding_element = Elements.RichContent

    def disabled_decode_element(
            self, parent, src_element, dst_element_class, attrib, children):
        html = ''
        for html_element in children:
            html_string = ET.tostring(html_element)
            if not isinstance(html_string, str):
                # I have once got back <class 'bytes'> when the string was a
                # binary string. weird...
                html_string = html_string.decode('ascii')
            html += html_string
        parent.text = html
        return None

    def disabled_encode_element(
            self, parent, src_element, dst_element_class, attrib, children):
        """until parent node creates a RichContent child, this will
        never trigger
        """
        element = dst_element_class()
        element.append(ET.fromstring(parent.text))
        parent.append(element)
        element.text = '\n'
        return element

def sanity_check(pymm_element):
    """checks for common errors in pymm element and issues warnings
    for out-of-spec attrib
    """
    unchecked = [pymm_element]
    while unchecked:
        elem = unchecked.pop(0)
        unchecked.extend(elem.children)
        attrib = elem.attrib
        for key, allowed_values in elem.spec.items():
            if key in attrib:
                attribute = attrib[key]
                for allowed in allowed_values:
                    if attribute == allowed or isinstance(attribute, allowed):
                        break
                    # allow attribute if spec contains a function
                    if isinstance(allowed, types.BuiltinMethodType) or \
                            isinstance(allowed, types.LambdaType) or \
                            isinstance(allowed, types.MethodType) or \
                            isinstance(allowed, types.FunctionType) or \
                            isinstance(allowed, types.BuiltinFunctionType):
                        break
                else:
                    warnings.warn(
                        'out-of-spec attribute "' + str(attribute) +
                        ' in element: ' + str(elem.tag)
                    )
<commit_msg>fix critical factory can_encode(): check class equality<commit_after>"""Factories are responsible for decoding xml.etree Elements into pymm
Elements and encoding pymm Elements back to xml.etree Elements. Factories are
where to specify how the encoding and decoding of an element is handled. Attrib
encoding/decoding is handled here as well
"""
import xml.etree.ElementTree as ET
import warnings
import copy
import re
import types
from uuid import uuid4
from . import Elements

def decode(element):
    converter = ConversionHandler()
    return converter.convert_element_hierarchy(element, 'decode')

def encode(element):
    converter = ConversionHandler()
    return converter.convert_element_hierarchy(element, 'encode')

class ConversionHandler:

    def __init__(self):
        """Lock in set of factories for handling elements. If you
        create another element after instantiating ConversionHandler,
        get another instance to auto-generate a factory for that
        element. Otherwise, DefaultFactory will be used
        """
        self.factories = registry.get_factories()

    def find_encode_factory(self, element):
        for factory in reversed(self.factories):
            if factory.can_encode(element):
                return factory
        return DefaultFactory

    def find_decode_factory(self, element):
        """Return factory that can handle given element.
        Default to DefaultFactory
        """
        for factory in reversed(self.factories):
            if factory.can_decode(element):
                return factory
        return DefaultFactory

    def convert_element_hierarchy(self, element, convert):
        """encode or decode element and its hierarchy. Each element
        will be completely converted before its children begin the
        process
        """
        queue = [(None, [element])]  # parent, children
        root = None
        while queue:
            parent, children = queue.pop(0)
            if root is None and parent is not None:
                root = parent
            for child in children:
                if convert == 'encode':
                    factory_class = self.find_encode_factory(child)
                    factory = factory_class()
                    child, grandchildren = factory.encode(parent, child)
                elif convert == 'decode':
                    factory_class = self.find_decode_factory(child)
                    factory = factory_class()
                    child, grandchildren = factory.decode(parent, child)
                else:
                    raise ValueError('pass in "decode" or "encode"')
                # if convert fxn returns no decoded child, drop from hierarchy
                if child is not None:
                    queue.append((child, grandchildren))
        return root

class registry(type):
    """Metaclass to register all Factories created, and assist in
    creating new factories for unclaimed elements (elements without a
    corresponding factory
    """
    _factories = []
    verbose = False
    _skip_registration = ''

    @classmethod
    def get_factories(cls):
        factories = list(tuple(cls._factories))
        generated = cls.create_unclaimed_element_factories(factories)
        return factories + generated

    def __new__(mcs, clsname, bases, attr_dict):
        """create Factory-class, and register it in list of factories
        """
        FactoryClass = super().__new__(mcs, clsname, bases, attr_dict)
        # do not register factory if it was generated by this metaclass
        if clsname != mcs._skip_registration:
            mcs._factories.append(FactoryClass)
        return FactoryClass

    @classmethod
    def create_unclaimed_element_factories(cls, factories):
        """iterate all elements inheriting from Elements.BaseElement.
        For each element with no corresponding factory, create a factory
        to handle it, inheriting from closest-matching factory.
        Closest-matching factory is determined as the newest factory to
        use a decoding-element of which the unclaimed element is a
        subclass.

        Return list of all factories created in this way
        """
        generated = []
        for element in Elements.registry.get_elements():
            closest_match = DefaultFactory
            for factory in factories:
                if issubclass(element, factory.decoding_element):
                    closest_match = factory
                if factory.decoding_element == element:
                    break
            else:
                # create factory for unclaimed element
                if cls.verbose:
                    print(
                        'unclaimed element:', element,
                        '\n\t tag:', element.tag,
                        '\n\t identifier:', element.identifier,
                        '\n\t closest matching factory:', closest_match,
                    )
                element_name = getattr(element, '__name__', element.tag)
                name = element_name + '-Factory@' + uuid4().hex
                inherit_from = (closest_match,)
                variables = {'decoding_element': element}
                cls._skip_registration = name
                new_factory = type(name, inherit_from, variables)
                generated.append(new_factory)
        return generated

class DefaultElementFactory:
    """Expose methods to construct encoding / decoding element class
    given attrib and children. At this point in the conversion process,
    the attribs are converted but the children are not.
    It is the responsibility of this factory to add the converted
    element to it's parent.
    """

    def decode_element(
            self, parent, src_element, element_class, attrib, children):
        """create decoded element using element_class and decoded
        attrib. The children are not yet decoded, however.
        DO NOT ADD CHILDREN TO ELEMENT! The children are not yet
        decoded. Instead you should add the newly instantiated element
        to the parent's children list
        """
        element = element_class(**attrib)
        if parent is not None:
            parent.children.append(element)
        element.tag = getattr(src_element, 'tag', element_class.tag)
        element._text = getattr(src_element, 'text', '')
        element._tail = getattr(src_element, 'tail', '\n')
        return element

    def encode_element(
            self, parent, src_element, element_class, attrib, children):
        """create encoded element using element_class and pre-encoded
        arguments attrib & children. This is the function in which
        to create an xml.etree Element
        DO NOT ADD CHILDREN TO ELEMENT! the children are not yet
        encoded. Instead you should add the newly encoded element as a
        child to the parent
        """
        tag = getattr(src_element, 'tag', 'unknown_element')
        element = element_class(tag, **attrib)
        if parent is not None:
            parent.append(element)
        element.text = getattr(src_element, '_text', '')
        element.tail = getattr(src_element, '_tail', '\n')
        # add spacing if element has child (makes file more readable)
        if len(element) and not element.text:
            element.text = '\n'
        return element

class DefaultAttribFactory:
    """expose methods to encode/decode attrib"""

    def decode_attrib(self, attrib, src_element, dst_element_class):
        """Decode attrib (from etree element) to match the spec in
        pymm element. Warn user (but still allow attrib) if attrib
        key/value pair is not valid.
        """
        spec = dst_element_class.spec
        decoded_attrib = {}
        # decoding from et element: assume all keys and values are strings
        for key, value in attrib.items():
            key = self.stringify(key)
            value = self.stringify(value)
            value = self.decode_attrib_value(key, value, spec)
            decoded_attrib[key] = value
        return decoded_attrib

    def decode_attrib_value(self, key, value, spec):
        """Spec values are lists that contain expected attrib values OR
        expected type of value (such as bool, int, or a custom class).
        Convert to expected type or verify that value matches one of
        corresponding spec value. If spec does not contain key, return
        value unaltered. Generate warning if value matched none of the
        spec values and/or could not be cast to type specified
        """
        entries = spec.get(key)
        if entries is None:
            return value
        if not isinstance(entries, list):
            raise ValueError('spec value must be a list of choices/types')
        # break out of for loop if match found
        for entry in entries:
            if entry == value:
                break
            if isinstance(entry, type):  # bool, str, int, etc...
                # special handling for finding false bool
                if issubclass(entry, bool):
                    if value in ['0', 'false', 'False', 'FALSE']:
                        value = False
                        break
                try:
                    value = entry(value)  # decode value to new type
                    break
                except:
                    warnings.warn(
                        key + ': ' + value + 'not of type ' + str(entry)
                    )
                    continue  # try next entry
        else:
            warnings.warn(key + ': ' + value + ' does not match spec')
        return value

    def encode_attrib(self, attrib, src_element, dst_element_class):
        """using src_element (pymm element) spec, decode (again)
        attrib to expected type. Then cast each key: value pair to
        string. If a particular value in spec is None, the key: value
        will be dropped from the encoded attrib.

        :param mmElement - pymm element containing attrib to be
        encoded
        """
        attrib = {
            key: value for key, value in attrib.items() if \
            value is not None
        }
        spec = src_element.spec
        encoded_attrib = {}
        for key, value in attrib.items():
            if key in spec:
                value = self.decode_attrib_value(key, value, spec)
            value = self.stringify(value)
            key = self.stringify(key)
            encoded_attrib[key] = value
        return encoded_attrib

    def stringify(self, arg):
        """If possible, decode into string, else cast arg to string"""
        if isinstance(arg, str):
            return arg
        try:
            return arg.decode()
        except:
            return str(arg)

class DefaultGetAttributesFactory:
    """expose methods to get attrib and children from elements. This
    does NOT encode or decode the attrib or children, but instead
    simply returns the unaltered attribute (attrib or children)
    """

    def decode_getchildren(self, element):
        """return list of children from xml.etree element"""
        return list(element)

    def encode_getchildren(self, element):
        """return list of children from pymm element. It is recommended
        to return a copied list of children, so that any modification
        to the list does not change the original element's children
        """
        return list(element.children)

    def decode_getattrib(self, element):
        """return attrib dict from xml.etree element"""
        return dict(element.attrib)

    def encode_getattrib(self, element):
        """return attrib dict from pymm element"""
        return dict(element.attrib)

class DefaultChildFactory:
    """expose methods for retrieving list of children to encode/decode"""
    # order in which children will be written to file
    child_order = [
        Elements.BaseElement, Elements.ArrowLink, Elements.Cloud,
        Elements.Edge, Elements.Properties, Elements.MapStyles, Elements.Icon,
        Elements.AttributeLayout, Elements.Attribute, Elements.Hook,
        Elements.Font, Elements.StyleNode, Elements.RichContent, Elements.Node
    ]
    # order of nth to last for children. First node listed will be last child.
    reverse_child_order = []

class DefaultFactory(
        DefaultAttribFactory, DefaultElementFactory,
        DefaultGetAttributesFactory, metaclass=registry):
    """Factory with default methods for encoding and decoding between
    xml.ElementTree and pymm
    """
    decoding_element = Elements.BaseElement
    encoding_element = ET.Element

    def decode(self, parent, src_element):
        """control decode order from from xml.etree element to pymm
        element. Typical decoding order looks like:
        get_attrib, decode_attrib, get_children, decode_element
        """
        dst_element = self.decoding_element
        unaltered_attrib = self.decode_getattrib(src_element)
        attrib = self.decode_attrib(unaltered_attrib, src_element, dst_element)
        children = self.decode_getchildren(src_element)
        element = self.decode_element(
            parent, src_element, dst_element, attrib, children
        )
        return element, children

    def encode(self, parent, src_element):
        """control encode order from pymm element to xml.etree element.
        Typical encoding order looks like:
        get_children, get_attrib, encode_attrib, decode_element
        """
        dst_element = self.encoding_element
        children = self.encode_getchildren(src_element)
        unaltered_attrib = self.encode_getattrib(src_element)
        attrib = self.encode_attrib(unaltered_attrib, src_element, dst_element)
        element = self.encode_element(
            parent, src_element, dst_element, attrib, children
        )
        return element, children

    @classmethod
    def can_decode(cls, element):
        """return False is element.tag does not equal decoding
        element's tag.
        If decoding_element has identifier, only
        return True if all key/value pairs of identifier regex match
        attrib key/value pair
        """
        if element.tag != cls.decoding_element.tag:
            return False
        for key_id, val_id in cls.decoding_element.identifier.items():
            # return False if identifying key/val is not found in attrib
            for key, val in element.attrib.items():
                if re.fullmatch(key_id, key) and re.fullmatch(val_id, val):
                    break
            else:
                return False
        return True

    @classmethod
    def can_encode(cls, element):
        if element.__class__ == cls.decoding_element:
            return True
        return False

class NodeFactory(DefaultFactory):
    decoding_element = Elements.Node
    child_order = [
        Elements.BaseElement, Elements.ArrowLink, Elements.Cloud,
        Elements.Edge, Elements.Font, Elements.Hook, Elements.Properties,
        Elements.RichContent, Elements.Icon, Elements.Node,
        Elements.AttributeLayout, Elements.Attribute
    ]

    def decode_attrib(self, attrib, src_element, dst_element_class):
        """Replace undesired parts of attrib with desired parts.
        specifically: look for occasional LOCALIZED_TEXT attrib which
        is supposed to be TEXT
        """
        swapout = [('TEXT', 'LOCALIZED_TEXT')]
        for desired, undesired in swapout:
            if desired not in attrib and undesired in attrib:
                attrib[desired] = attrib[undesired]
                del attrib[undesired]
        return super().decode_attrib(attrib, src_element, dst_element_class)

    def encode_getchildren(self, element):
        """add attributes into children"""
        children = super().encode_getchildren(element)
        for name, value in element.items():
            child = Elements.Attribute(NAME=name, VALUE=value)
            children.append(child)
        return children

class MapFactory(DefaultFactory):
    decoding_element = Elements.Map

    def encode_element(
            self, parent, src_element, element_class, attrib, children):
        element = super().encode_element(
            parent, src_element, element_class, attrib, children)
        comment = ET.Comment(
            'To view this file, download free mind mapping software '
            + 'Freeplane from http://freeplane.sourceforge.net'
        )
        comment.tail = '\n'
        element.append(comment)
        return element

class AttributeFactory(DefaultFactory):
    """Attribute is a visual 2-wide cell beneath a node. It has a name
    and value. We want to instead push this into the parent node as if
    it were a dictionary: parent[name] = value
    """
    decoding_element = Elements.Attribute

    def decode_element(
            self, parent, src_element, element_class, attrib, children):
        if not isinstance(parent, Elements.Node):
            return super().encode_element(
                parent, src_element, element_class, attrib, children)
        if 'NAME' in attrib and 'VALUE' in attrib:
            name = attrib['NAME']
            value = attrib['VALUE']
            parent[name] = value
        return None  # stop decoding this element and its children

class RichContentFactory(DefaultFactory):
    decoding_element = Elements.RichContent

    def disabled_decode_element(
            self, parent, src_element, dst_element_class, attrib, children):
        html = ''
        for html_element in children:
            html_string = ET.tostring(html_element)
            if not isinstance(html_string, str):
                # I have once got back <class 'bytes'> when the string was a
                # binary string. weird...
                html_string = html_string.decode('ascii')
            html += html_string
        parent.text = html
        return None

    def disabled_encode_element(
            self, parent, src_element, dst_element_class, attrib, children):
        """until parent node creates a RichContent child, this will
        never trigger
        """
        element = dst_element_class()
        element.append(ET.fromstring(parent.text))
        parent.append(element)
        element.text = '\n'
        return element

def sanity_check(pymm_element):
    """checks for common errors in pymm element and issues warnings
    for out-of-spec attrib
    """
    unchecked = [pymm_element]
    while unchecked:
        elem = unchecked.pop(0)
        unchecked.extend(elem.children)
        attrib = elem.attrib
        for key, allowed_values in elem.spec.items():
            if key in attrib:
                attribute = attrib[key]
                for allowed in allowed_values:
                    if attribute == allowed or isinstance(attribute, allowed):
                        break
                    # allow attribute if spec contains a function
                    if isinstance(allowed, types.BuiltinMethodType) or \
                            isinstance(allowed, types.LambdaType) or \
                            isinstance(allowed, types.MethodType) or \
                            isinstance(allowed, types.FunctionType) or \
                            isinstance(allowed, types.BuiltinFunctionType):
                        break
                else:
                    warnings.warn(
                        'out-of-spec attribute "' + str(attribute) +
                        ' in element: ' + str(elem.tag)
                    )
<|endoftext|>


<commit_before>from model import Model, Wire, Port, InPort, OutPort
from simulate import SimulationTool
from translate import VerilogTranslationTool
from visualize import VisualizationTool

__all__ = ['Model',
           'Wire',
           'Port',
           'InPort',
           'OutPort',
           'SimulationTool',
           'VerilogTranslationTool',
           'VisualizationTool'
          ]

<commit_msg>[pymtl] fixed __init__ to export funcs in pymtl api<commit_after>from model import Model, Wire, Port, InPort, OutPort
from model import posedge_clk, combinational, connect
from simulate import SimulationTool
from translate import VerilogTranslationTool
from visualize import VisualizationTool

__all__ = ['Model',
           'Wire',
           'Port',
           'InPort',
           'OutPort',
           'posedge_clk',
           'combinational',
           'connect',
           'SimulationTool',
           'VerilogTranslationTool',
           'VisualizationTool'
          ]

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""PyMzn is a Python library that wraps and enhances the MiniZinc tools for
modelling and solving constraint programs. It is built on top of the MiniZinc
toolkit and provides a number of off-the-shelf functions to readily solve
problems encoded in MiniZinc and parse the solutions into Python objects."""

from .log import *
from .config import config
from .dzn import *
from .mzn import *

__all__ = ['config'] + log.__all__ + dzn.__all__ + mzn.__all__

__version__ = '0.17.1'

def main():
    import ast
    import argparse
    from textwrap import dedent

    def _minizinc(**_args):
        print(minizinc(
        _args['mzn'], *_args['dzn_files'],
        **{k: v for k, v in _args.items() if k not in ['mzn', 'dzn_files']}
    ))

    def _config(key, value=None, **__):
        if value is None:
            print('{} : {}'.format(key, config.get(key)))
        else:
            config.set(key, value)
            config.dump()

    desc = dedent('''\
        PyMzn is a Python library that wraps and enhances the MiniZinc tools for
        modelling and solving constraint programs. It is built on top of the
        MiniZinc toolkit and provides a number of off-the-shelf functions to
        readily solve problems encoded in MiniZinc and parse the solutions into
        Python objects.
    ''')

    fmt = argparse.ArgumentDefaultsHelpFormatter
    parser = argparse.ArgumentParser(description=desc, formatter_class=fmt)
    parser.add_argument(
        '--version', action='version',
        version='PyMzn version: {}'.format(__version__)
    )
    parser.add_argument(
        '-v', '--verbose', action='store_true',
        help='display informative messages on standard output'
    )

    # minizinc
    parser.add_argument(
        'mzn', help='the mzn file to solve'
    )
    parser.add_argument(
        'dzn_files', nargs='*', help='additional dzn files'
    )
    parser.add_argument(
        '--data', type=ast.literal_eval, help='additional inline data'
    )
    parser.add_argument(
        '-a', '--all-solutions', action='store_true',
        help='wheter to return all solutions (if supported by the solver)'
    )
    parser.add_argument(
        '-S', '--solver', help='name of the solver'
    )
    parser.add_argument(
        '-s', '--solver-args', type=ast.literal_eval, default={},
        help='arguments to pass to the solver'
    )
    parser.add_argument(
        '-k', '--keep', action='store_true',
        help='whether to keep generated files'
    )
    parser.add_argument(
        '-I', '--include', dest='path', action='append',
        help='directory the standard library'
    )
    parser.set_defaults(func=_minizinc)

    # config
    subparsers = parser.add_subparsers()
    config_parser = subparsers.add_parser(
        'config', help='config pymzn variables'
    )
    config_parser.add_argument(
        'key', help='the property to get/set'
    )
    config_parser.add_argument(
        'value', nargs='?', help='the value(s) to set'
    )
    config_parser.set_defaults(func=_config)

    args = parser.parse_args()

    debug(args.verbose)
    args.func(**{**vars(args), **args.solver_args})

if __name__ == '__main__':
    main()

<commit_msg>pymzn: add delete option to main config<commit_after># -*- coding: utf-8 -*-
"""PyMzn is a Python library that wraps and enhances the MiniZinc tools for
modelling and solving constraint programs. It is built on top of the MiniZinc
toolkit and provides a number of off-the-shelf functions to readily solve
problems encoded in MiniZinc and parse the solutions into Python objects."""

from .log import *
from .config import config
from .dzn import *
from .mzn import *

__all__ = ['config'] + log.__all__ + dzn.__all__ + mzn.__all__

__version__ = '0.17.1'

def main():
    import ast
    import argparse
    from textwrap import dedent

    def _minizinc(**_args):
        print(minizinc(
        _args['mzn'], *_args['dzn_files'],
        **{k: v for k, v in _args.items() if k not in ['mzn', 'dzn_files']}
    ))

    def _config(key, value=None, delete=False, **__):
        if delete:
            del config[key]
            config.dump()
        elif value is None:
            print('{} : {}'.format(key, config.get(key)))
        else:
            config[key] = value
            config.dump()

    desc = dedent('''\
        PyMzn is a Python library that wraps and enhances the MiniZinc tools for
        modelling and solving constraint programs. It is built on top of the
        MiniZinc toolkit and provides a number of off-the-shelf functions to
        readily solve problems encoded in MiniZinc and parse the solutions into
        Python objects.
    ''')

    fmt = argparse.ArgumentDefaultsHelpFormatter
    parser = argparse.ArgumentParser(description=desc, formatter_class=fmt)
    parser.add_argument(
        '--version', action='version',
        version='PyMzn version: {}'.format(__version__)
    )
    parser.add_argument(
        '-v', '--verbose', action='store_true',
        help='display informative messages on standard output'
    )

    # minizinc
    parser.add_argument(
        'mzn', help='the mzn file to solve'
    )
    parser.add_argument(
        'dzn_files', nargs='*', help='additional dzn files'
    )
    parser.add_argument(
        '--data', type=ast.literal_eval, help='additional inline data'
    )
    parser.add_argument(
        '-a', '--all-solutions', action='store_true',
        help='wheter to return all solutions (if supported by the solver)'
    )
    parser.add_argument(
        '-S', '--solver', help='name of the solver'
    )
    parser.add_argument(
        '-s', '--solver-args', type=ast.literal_eval, default={},
        help='arguments to pass to the solver'
    )
    parser.add_argument(
        '-k', '--keep', action='store_true',
        help='whether to keep generated files'
    )
    parser.add_argument(
        '-I', '--include', dest='path', action='append',
        help='directory the standard library'
    )
    parser.set_defaults(func=_minizinc)

    # config
    subparsers = parser.add_subparsers()
    config_parser = subparsers.add_parser(
        'config', help='config pymzn variables'
    )
    config_parser.add_argument(
        'key', help='the property to get/set'
    )
    config_parser.add_argument(
        '-d', '--delete', action='store_true', help='delete a key'
    )
    config_parser.add_argument(
        'value', nargs='?', help='the value(s) to set'
    )
    config_parser.set_defaults(func=_config)

    args = parser.parse_args()

    debug(args.verbose)
    args.func(**{**vars(args), **args.solver_args})

if __name__ == '__main__':
    main()

<|endoftext|>