Skip to content

Commit 1c409d0

Browse files
authored
Merge pull request #48 from hadpro24/develop
refactoring reverse path and fix arg error
2 parents 70364e6 + 25dabb9 commit 1c409d0

File tree

4 files changed

+45
-27
lines changed

4 files changed

+45
-27
lines changed

nimba/http/utils.py

+32-17
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from wsgiref.headers import Headers
66
import pathlib
77
import urllib.parse
8+
from collections.abc import Iterable
89

910
import traceback
1011
import mimetypes
@@ -38,35 +39,49 @@
3839
REVERSE_ROUTE_INFO = {}
3940
PROJECT_MASK = 'PROJECT_MASK_PATH'
4041

41-
def reverse(name_path:str, args=None, kwargs=None) -> str:
42+
def reverse(name_path:str, *args, **kwargs) -> str:
4243
if not isinstance(name_path, str) or not re.match(r"^[^\d\W][\w-]*\Z", name_path):
4344
raise ValueError("Name path must but a valid identifier name.")
44-
args = args or {}
45-
kwargs = kwargs or {}
45+
46+
args = kwargs.get('args') or args or {}
47+
kwargs.pop('args', None)
48+
kwargs = kwargs.get('kwargs') or kwargs or {}
49+
4650
if args and kwargs:
47-
raise ValueError(("Don't use *args and **kwargs."
48-
"*args is for get and **kwargs for post method."))
49-
path = REVERSE_ROUTE_INFO.get(name_path)
51+
raise ValueError(("You can't mix *args and **kwargs."))
52+
if not isinstance(args, Iterable) or not isinstance(kwargs, dict):
53+
raise ValueError("*args or ** kwargs must be list and dict respectively")
54+
55+
path, view = REVERSE_ROUTE_INFO.get(name_path) or (None, None)
56+
original_path = path
5057
if not path:
5158
raise NoReverseFound(f"Reverse for {name_path} not found.")
52-
59+
regex = r'<(?:(?P<converter>[^>:]+):)?(?P<parameter>[^>]+)>'
60+
url = re.compile(regex, 0)
61+
params_path = list(url.finditer(path))
62+
got_params = args or kwargs
63+
if len(params_path) != len(got_params):
64+
raise ValueError((f"The view `{view}` expects {len(params_path)} "
65+
f"parameters but has received {len(got_params)}"))
5366
if args:
54-
path = path +'?'+ urllib.parse.urlencode(args)
67+
for arg, match in zip(args, params_path):
68+
path = re.sub(
69+
original_path[match.start():match.end()],
70+
urllib.parse.quote(str(arg)),
71+
path
72+
)
5573
else:
56-
regex = r'<(?:(?P<converter>[^>:]+):)?(?P<parameter>[^>]+)>'
57-
url = re.compile(regex, 0)
58-
helper_path = path
59-
for match in url.finditer(path):
74+
for match in params_path:
6075
value = kwargs.get(match['parameter'])
6176
if not value:
62-
raise NoReverseFound((f"Reverse for {name_path} not found. "
77+
raise NoReverseFound((f"Reverse for `{name_path}` not found. "
6378
"Keyword arguments '%s' not found." % match['parameter']))
6479
path = re.sub(
65-
helper_path[match.start():match.end()],
66-
str(value),
80+
original_path[match.start():match.end()],
81+
urllib.parse.quote(str(value)),
6782
path
6883
)
69-
return path
84+
return path
7085

7186
def load_static(value):
7287
return os.path.join('/staticfiles/', value)
@@ -125,7 +140,7 @@ def request_response_application(callback):
125140
ROUTES[new_path] = (callback, converters, path, methods)
126141

127142
# if: pass
128-
REVERSE_ROUTE_INFO[name or callback.__name__] = path
143+
REVERSE_ROUTE_INFO[name or callback.__name__] = path, callback.__name__
129144
def application(environ, start_response):
130145
request = Request(environ)
131146
#authorized

nimba/test/client.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ def get(self, path, data=None, secure=False):
120120
query_string = urllib.parse.urlencode(data)
121121
url = path+'?'+query_string
122122
else:
123-
url = path
123+
url = urllib.parse.quote(path)
124+
124125
url = self.base_url+url
125126
res = {}
126127
f = open(os.devnull, 'w')

setup.cfg

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = nimba
3-
version = 0.0.10
3+
version = 0.0.11
44
description = Nimba is a fast coding, web framework with Python.
55
long_description = file: README.rst
66
keywords = python, python3, framework, nimba, nimba-solution, web
@@ -17,9 +17,9 @@ classifiers =
1717
Programming Language :: Python
1818
Programming Language :: Python :: 3
1919
Programming Language :: Python :: 3 :: Only
20+
Programming Language :: Python :: 3.6
2021
Programming Language :: Python :: 3.7
2122
Programming Language :: Python :: 3.8
22-
Programming Language :: Python :: 3.9
2323
Topic :: Internet :: WWW/HTTP
2424
Topic :: Internet :: WWW/HTTP :: Dynamic Content
2525
Topic :: Internet :: WWW/HTTP :: WSGI

tests/test_router.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import shutil
66
import sys
77
import time
8-
import pytest
98
import shutil
109
from unittest.mock import patch
1110

@@ -66,7 +65,7 @@ def test_route_about(self):
6665
self.assertEqual(TEST, response['text'])
6766

6867
def test_route_about_with_query(self):
69-
response = self.get('/about?id=5')
68+
response = self.get('/about', data={'id': 5})
7069
self.assertEqual(200, response['status_code'])
7170
self.assertEqual('yes', response['text'])
7271

@@ -110,13 +109,12 @@ def test_reverse_with_name_and_kwargs(self):
110109
#give kwargs and args
111110
with self.assertRaises(ValueError) as error:
112111
reverse('article', kwargs={'id': 5}, args={'name': 'test'})
113-
self.assertEqual(str(error.exception), ("Don't use *args and **kwargs."
114-
"*args is for get and **kwargs for post method."))
112+
self.assertEqual(str(error.exception), "You can't mix *args and **kwargs.")
115113
#invalid parmas name
116114
invalid_params = 'id_wrong'
117115
with self.assertRaises(NoReverseFound) as error:
118116
reverse('article', kwargs={invalid_params: 5})
119-
self.assertEqual(str(error.exception), ("Reverse for article not found. "
117+
self.assertEqual(str(error.exception), ("Reverse for `article` not found. "
120118
"Keyword arguments 'id' not found."))
121119
#valid
122120
_id = 5
@@ -127,8 +125,12 @@ def test_reverse_with_name_and_kwargs(self):
127125

128126
def test_reverse_with_args(self):
129127
name = 'Harouna Diallo'
130-
url = reverse('info', args={'name': name})
131-
response = self.get(url)
128+
with self.assertRaises(ValueError) as error:
129+
url = reverse('info', args={'name': name})
130+
self.assertEqual(str(error.exception),
131+
f"The view `info` expects 0 parameters but has received 1")
132+
url = reverse('info')
133+
response = self.get(url, data={'name': name})
132134
self.assertEqual(200, response['status_code'])
133135
self.assertEqual(name, response['text'])
134136

0 commit comments

Comments
 (0)