This commit is contained in:
2024-07-15 13:05:25 +03:00
parent aff8c9b58d
commit e23b933142
13 changed files with 184 additions and 212 deletions
+3
View File
@@ -1,5 +1,8 @@
*.pyc
*.pyo
__pycache__
.pytest_cache
*.egg-info
prototypes
dist
+23
View File
@@ -0,0 +1,23 @@
{
"app1": {
"route": {
"operator": "and",
"rules": [
{
"key": "url.host",
"operator": "regex",
"value": ".*"
},
{
"key": "url.path",
"operator": "regex",
"value": "\/"
}
]
},
"function": {
"operator": "const",
"value": "OK"
}
}
}
+4 -2
View File
@@ -1,15 +1,17 @@
[project]
name = "router"
version ="0.1.0"
version ="0.2"
authors = [
{ name="RemiZOffAlex", email="remizoffalex@gmail.com" },
]
description = "Маршрутизатор"
requires-python = ">=3.10"
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12"
]
keywords = ["documentation"]
keywords = ["broker", "router"]
dependencies = []
-57
View File
@@ -1,57 +0,0 @@
__author__ = 'RemiZOffAlex'
__email__ = 'remizoffalex@mail.ru'
import logging
from collections.abc import Callable
from .route import Route
log = logging.getLogger(__name__)
class Broker:
def __init__(self):
self.routes = []
def __call__(self, query):
"""Вызов метода
"""
for route in self.routes:
log.debug(route)
output = route.comparator(query)
if output:
return (route.endpoint, output)
def __getitem__(self, key):
method = self.methods[key]
return method.function
def __iter__(self):
return iter(self.methods)
def __len__(self):
return len(self.methods)
def __setitem__(self, key, function, pre=None):
method = Method(function=function, pre=pre)
self.methods[key] = method
def __delitem__(self, key):
del self.methods[key]
def __repr__(self):
return repr(self.methods)
def route(self, comparator: Callable, *args):
"""Декоратор
"""
def wrap(function):
_route = Route(
comparator=comparator,
endpoint=function
)
self.routes.append(_route)
return function
return wrap
-37
View File
@@ -1,37 +0,0 @@
__author__ = 'RemiZOffAlex'
__email__ = 'remizoffalex@mail.ru'
import logging
from .dsl.common import And, Equal, Or, Regex
log = logging.getLogger(__name__)
class Compiler:
def __call__(self, rule):
if isinstance(rule, list):
val = []
for item in rule:
val.append(self(item))
return val
elif isinstance(rule, dict):
assert 'operator' in rule, \
'Not operator in rule: {rule}'.format(rule=rule)
if rule['operator'] == 'and':
val = self(rule['rules'])
result = And(val)
return result
elif rule['operator'] == 'or':
val = self(rule['rules'])
return Or(val)
elif rule['operator'] == 'equal':
return Equal(
key=rule['key'],
value=rule['value']
)
elif rule['operator'] == 'regex':
return Regex(
key=rule['key'],
value=rule['value']
)
-95
View File
@@ -1,95 +0,0 @@
__author__ = 'RemiZOffAlex'
__email__ = 'remizoffalex@mail.ru'
import re
_part_re = re.compile(
r"""
(?:
(?P<slash>/) # a slash
|
(?P<static>[^</]+) # static rule data
|
(?:
<
(?:
(?P<converter>[a-zA-Z_][a-zA-Z0-9_]*) # converter name
(?:\((?P<arguments>.*?)\))? # converter arguments
: # variable delimiter
)?
(?P<variable>[a-zA-Z_][a-zA-Z0-9_]*) # variable name
>
)
)
""",
re.VERBOSE,
)
def rule_parse(rule: str) -> list:
"""Парсим правило
"""
result = []
pos = 0
while pos < len(rule):
match = _part_re.match(rule, pos)
print('match:', match)
pos = match.end()
data = match.groupdict()
print('data:', data)
result.append(data)
return result
def rule_compile(rule: list):
"""Компилируем регулярку из правила
"""
result = []
params = {}
for item in rule:
if item['slash']:
result.append(item['slash'])
elif item['static']:
result.append(item['static'])
elif item['converter']:
params[item['variable']] = None
if item['converter']=='int':
result.append('(?P<{}>\d+)'.format(item['variable']))
print('item:', item)
regexp = ''.join(result)
print('regexp:', regexp)
return (re.compile(regexp), params)
def rule_extract(regexp, request):
pass
def rule_comparator(rule, request):
try:
rule_proto = rule_parse(rule)
print('rule_proto:', rule_proto)
rule_regex, params = rule_compile(rule_proto)
print('rule:', rule_regex)
result = rule_regex.match(url)
for key in params:
params[key] = result.group(key)
print(key, ':', params[key])
return params
except Exception as error:
return None
def main():
print('_part_re.groups:', _part_re.groups)
print('_part_re.groups:', _part_re.groups)
rule = '/v<int:major>.<int:minor>'
urls = [
'/v3451.5432',
'/v3sdfsdf451.5432'
]
for url in urls:
params = rule_comparator(rule, url)
if params:
print('route {} is valid:'.format(url), params)
else:
print('route {} invalid'.format(url))
+67
View File
@@ -0,0 +1,67 @@
__author__ = 'RemiZOffAlex'
__email__ = 'remizoffalex@mail.ru'
import logging
from collections.abc import Callable
from .route import Route
log = logging.getLogger(__name__)
class Broker:
def __init__(self, debug: bool = False):
self.routes = {}
self.debug = debug
def __call__(self, query):
"""Вызов метода
"""
for key in self.routes:
_route = self.routes[key]
if self.debug:
log.debug('{key}: {route}'.format(
key=key,
route=_route
))
print(key)
print(_route)
print(_route.comparator)
print(query)
output = _route.comparator(query)
if output:
return (_route.endpoint, output)
def __getitem__(self, key):
method = self.routes[key]
return method.function
def __iter__(self):
return iter(self.routes)
def __len__(self):
return len(self.routes)
def __setitem__(self, key, function, pre=None):
method = Method(function=function, pre=pre)
self.routes[key] = method
def __delitem__(self, key):
del self.routes[key]
def __repr__(self):
return repr(self.routes)
def route(self, name: str, comparator: Callable, *args):
"""Декоратор
"""
def wrap(function):
_route = Route(
comparator=comparator,
endpoint=function
)
self.routes[name] = _route
return function
return wrap
+68
View File
@@ -0,0 +1,68 @@
__author__ = 'RemiZOffAlex'
__email__ = 'remizoffalex@mail.ru'
import re
import logging
log = logging.getLogger(__name__)
class Node:
__params__ = {}
def __init__(self, **kwargs):
log.debug('{}.__init__'.format(self.__class__.__name__))
for item in self.__params__:
setattr(self, item, kwargs[item])
def __call__(self, state):
print(self.__class__.__name__)
raise ValueError('Метод не реализован')
def __repr__(self):
log.debug('{}.__repr__'.format(self.__class__.__name__))
result = self.__class__.__name__ + '(' + ')'
params = []
for item in self.__params__:
param = getattr(self, item)
params.append('{} = {}'.format(item, getattr(self, item)))
result = self.__class__.__name__ + '(' + ', '.join(params) + ')'
log.debug('__repr__')
return result
class Regex(Node):
__params__ = {
'key': '',
'value': ''
}
def __init__(self, key, value):
self.key = key
self.value = re.compile(value)
def __json__(self):
return {
'operator': 'regex',
'key': self.key,
'value': self.value.pattern
}
def __call__(self, query):
print('Regex.__call__')
if isinstance(query, dict):
result = self.value.match(query[self.key])
else:
if '.' in self.key:
keys = self.key.split('.')
value = query
for key in keys:
value = getattr(value, key)
else:
value = getattr(query, self.key)
print(value)
print(type(value).__name__)
result = self.value.match(value)
print(result)
return result
@@ -4,12 +4,15 @@ __email__ = 'remizoffalex@mail.ru'
import re
import logging
from .common import Node
log = logging.getLogger(__name__)
class And:
def __init__(self, rules):
self.rules = rules
class And(Node):
__params__ = {
'rules': ''
}
def __json__(self):
result = []
@@ -26,6 +29,10 @@ class And:
class Equal:
__params__ = {
'key': '',
'value': ''
}
def __init__(self, key, value):
self.key = key
self.value = value
@@ -43,6 +50,9 @@ class Equal:
class Or:
__params__ = {
'rules': ''
}
def __init__(self, rules):
self.rules = rules
@@ -58,21 +68,3 @@ class Or:
def __call__(self, query):
print('Or.__call__')
return any(map(lambda x: x(query), self.rules))
class Regex:
def __init__(self, key, value):
self.key = key
self.value = re.compile(value)
def __json__(self):
return {
'operator': 'regex',
'key': self.key,
'value': self.value.pattern
}
def __call__(self, query):
print('Regex.__call__')
result = self.value.match(query[self.key])
return result
+6
View File
@@ -11,3 +11,9 @@ class Route:
print('Route.__init__')
self.comparator = comparator
self.endpoint = endpoint
def __repr__(self):
return 'Route(comparator={comparator}, endpoint={endpoint})'.format(
comparator=self.comparator,
endpoint=self.endpoint
)