try:
    from urllib.parse import urlencode
except ImportError:
    # Python 2
    from urllib import urlencode
from morepath.path import register_path, get_arguments
from morepath.converter import Converter, IDENTITY_CONVERTER, ConverterRegistry
import morepath
from morepath import setup
from morepath import generic
from morepath.publish import consume as traject_consume
import webob


def setup_module(module):
    morepath.disable_implicit()


def consume(mount, path, parameters=None):
    if parameters:
        path += '?' + urlencode(parameters, True)
    request = mount.request(webob.Request.blank(path).environ)
    return traject_consume(request, mount), request


class Root(object):
    pass


class Model(object):
    pass


def test_register_path():
    config = setup()

    class App(morepath.App):
        testing_config = config

    root = Root()

    def get_model(id):
        model = Model()
        model.id = id
        return model

    config.commit()

    registry = App.config.registry

    register_path(registry, Root, '', lambda m: {},
                  None, None, None, False,
                  lambda: root)
    register_path(registry, Model, '{id}', lambda model: {'id': model.id},
                  None, None, None, False, get_model)

    app = App()

    obj, request = consume(app, 'a')
    assert obj.id == 'a'
    model = Model()
    model.id = 'b'
    assert generic.path(model, lookup=app.lookup) == ('b', {})


def test_register_path_with_parameters():
    config = setup()

    class App(morepath.App):
        testing_config = config

    root = Root()

    def get_model(id, param='default'):
        model = Model()
        model.id = id
        model.param = param
        return model

    config.commit()

    registry = App.config.registry

    register_path(registry, Root, '', lambda m: {}, None, None, None, False,
                  lambda: root)
    register_path(registry, Model, '{id}',
                  lambda model: {'id': model.id, 'param': model.param},
                  None, None, None, False, get_model)

    mount = App()

    obj, request = consume(mount, 'a')
    assert obj.id == 'a'
    assert obj.param == 'default'

    obj, request = consume(mount, 'a', {'param': 'value'})
    assert obj.id == 'a'
    assert obj.param == 'value'

    model = Model()
    model.id = 'b'
    model.param = 'other'
    assert generic.path(model, lookup=mount.lookup) == (
        'b', {'param': ['other']})


def test_traject_path_with_leading_slash():
    config = setup()

    class App(morepath.App):
        testing_config = config

    root = Root()

    def get_model(id):
        model = Model()
        model.id = id
        return model

    config.commit()

    registry = App.config.registry

    register_path(registry, Root, '', lambda m: {}, None, None, None, False,
                  lambda: root)
    register_path(registry, Model, '/foo/{id}', lambda model: {'id': model.id},
                  None, None, None, False, get_model)

    mount = App()
    obj, request = consume(mount, 'foo/a')
    assert obj.id == 'a'
    obj, request = consume(mount, '/foo/a')
    assert obj.id == 'a'


def test_get_arguments():
    def foo(a, b):
        pass
    assert get_arguments(foo, []) == {'a': None, 'b': None}


def test_get_arguments_defaults():
    def foo(a, b=1):
        pass
    assert get_arguments(foo, []) == {'a': None, 'b': 1}


def test_get_arguments_exclude():
    def foo(a, b, request):
        pass
    assert get_arguments(foo, ['request']) == {'a': None, 'b': None}


def test_argument_and_explicit_converters_none_defaults():
    class MyConverterRegistry(ConverterRegistry):
        def converter_for_type(self, t):
            return IDENTITY_CONVERTER

        def converter_for_value(self, v):
            return IDENTITY_CONVERTER

    reg = MyConverterRegistry()

    assert reg.argument_and_explicit_converters({'a': None}, {}) == {
        'a': IDENTITY_CONVERTER}


def test_argument_and_explicit_converters_explicit():
    class MyConverterRegistry(ConverterRegistry):
        def converter_for_type(self, t):
            return IDENTITY_CONVERTER

        def converter_for_value(self, v):
            return IDENTITY_CONVERTER

    reg = MyConverterRegistry()

    assert reg.argument_and_explicit_converters(
        {'a': None}, {'a': Converter(int)}) == {'a': Converter(int)}


def test_argument_and_explicit_converters_from_type():
    class MyConverterRegistry(ConverterRegistry):
        def converter_for_type(self, t):
            return Converter(int)

        def converter_for_value(self, v):
            return IDENTITY_CONVERTER

    reg = MyConverterRegistry()

    assert reg.argument_and_explicit_converters({'a': None}, {'a': int}) == {
        'a': Converter(int)}

@@ -1,8 +1,23 @@
+import dectate%0A
 try:%0A   
@@ -776,38 +776,16 @@
 path():%0A
-    config = setup()%0A%0A
     clas
@@ -813,39 +813,20 @@
         
-testing_config = config
+pass
 %0A%0A    ro
@@ -929,38 +929,39 @@
  model%0A%0A    
-config
+dectate
 .commit(
 )%0A%0A    regis
@@ -940,32 +940,37 @@
  dectate.commit(
+%5BApp%5D
 )%0A%0A    registry 
@@ -1474,38 +1474,16 @@
 ters():%0A
-    config = setup()%0A%0A
     clas
@@ -1511,39 +1511,20 @@
         
-testing_config = config
+pass
 %0A%0A    ro
@@ -1672,38 +1672,39 @@
  model%0A%0A    
-config
+dectate
 .commit(
 )%0A%0A    regis
@@ -1683,32 +1683,37 @@
  dectate.commit(
+%5BApp%5D
 )%0A%0A    registry 
@@ -2456,30 +2456,8 @@
 ():%0A
-    config = setup()%0A%0A
     
@@ -2493,31 +2493,12 @@
     
-testing_config = config
+pass
 %0A%0A  
@@ -2613,22 +2613,23 @@
     
-config
+dectate
 .commit(
 )%0A%0A 
@@ -2624,16 +2624,21 @@
 .commit(
+%5BApp%5D
 )%0A%0A    r

Make this work.