mirror of
https://github.com/MarkParker5/STARK.git
synced 2025-02-17 11:55:35 +02:00
async pattern/object parse
This commit is contained in:
parent
ab233ab878
commit
1249e24342
@ -57,7 +57,7 @@ class CommandsContext:
|
||||
def root_context(self):
|
||||
return CommandsContextLayer(self.commands_manager.commands, {})
|
||||
|
||||
def process_string(self, string: str):
|
||||
async def process_string(self, string: str):
|
||||
|
||||
if not self._context_queue:
|
||||
self._context_queue.append(self.root_context)
|
||||
@ -66,7 +66,7 @@ class CommandsContext:
|
||||
while self._context_queue:
|
||||
|
||||
current_context = self._context_queue[0]
|
||||
search_results = self.commands_manager.search(string = string, commands = current_context.commands)
|
||||
search_results = await self.commands_manager.search(string = string, commands = current_context.commands)
|
||||
|
||||
if search_results:
|
||||
break
|
||||
|
@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
import inspect
|
||||
from asyncer import create_task_group
|
||||
|
||||
from .patterns import Pattern, MatchResult
|
||||
from .types import Object
|
||||
@ -23,18 +24,31 @@ class CommandsManager:
|
||||
self.name = name or 'CommandsManager'
|
||||
self.commands = []
|
||||
|
||||
def search(self, string: str, commands: list[Command] | None = None) -> list[SearchResult]:
|
||||
async def search(self, string: str, commands: list[Command] | None = None) -> list[SearchResult]:
|
||||
|
||||
if not commands:
|
||||
commands = self.commands
|
||||
|
||||
objects_cache: dict[str, Object] = {}
|
||||
results: list[SearchResult] = []
|
||||
# origin = String(string)
|
||||
|
||||
|
||||
i = 0
|
||||
for command in commands:
|
||||
for match in command.pattern.match(string, objects_cache):
|
||||
|
||||
# async with create_task_group() as group:
|
||||
# for command in commands:
|
||||
# async def match_command():
|
||||
# nonlocal i
|
||||
# for match in await command.pattern.match(string, objects_cache):
|
||||
# results.append(SearchResult(
|
||||
# command = command,
|
||||
# match_result = match,
|
||||
# index = i
|
||||
# ))
|
||||
# i += 1
|
||||
# group.soonify(match_command)()
|
||||
|
||||
for command in commands: # TODO: concurrent
|
||||
for match in await command.pattern.match(string, objects_cache):
|
||||
results.append(SearchResult(
|
||||
command = command,
|
||||
match_result = match,
|
||||
@ -51,9 +65,9 @@ class CommandsManager:
|
||||
if prev.match_result.start == current.match_result.start or prev.match_result.end > current.match_result.start:
|
||||
|
||||
# constrain prev end to current start
|
||||
prev_cut = prev.command.pattern.match(string[prev.match_result.start:current.match_result.start], objects_cache)
|
||||
prev_cut = await prev.command.pattern.match(string[prev.match_result.start:current.match_result.start], objects_cache)
|
||||
# constrain current start to prev end
|
||||
current_cut = current.command.pattern.match(string[prev.match_result.end:current.match_result.end], objects_cache)
|
||||
current_cut = await current.command.pattern.match(string[prev.match_result.end:current.match_result.end], objects_cache)
|
||||
|
||||
# less index = more priority to save full match
|
||||
priority1, priority2 = (prev, current) if prev.index < current.index else (current, prev)
|
||||
|
@ -31,7 +31,7 @@ class Pattern:
|
||||
self.parameters = dict(self._get_parameters())
|
||||
self.compiled = self._compile()
|
||||
|
||||
def match(self, string: str, objects_cache: dict[str, Object] | None = None) -> list[MatchResult]:
|
||||
async def match(self, string: str, objects_cache: dict[str, Object] | None = None) -> list[MatchResult]:
|
||||
|
||||
if objects_cache is None:
|
||||
objects_cache = {}
|
||||
@ -64,7 +64,7 @@ class Pattern:
|
||||
parameter_str = parsed_substr
|
||||
break
|
||||
else:
|
||||
parse_result = object_type.parse(from_string = parameter_str, parameters = match_str_groups)
|
||||
parse_result = await object_type.parse(from_string = parameter_str, parameters = match_str_groups) # TODO: concurrent parsing
|
||||
objects_cache[parse_result.substring] = parse_result.obj
|
||||
parameters[name] = parse_result.obj
|
||||
parameter_str = parse_result.substring
|
||||
|
@ -25,7 +25,7 @@ class Object(ABC):
|
||||
'''Just init with wrapped value.'''
|
||||
self.value = value
|
||||
|
||||
def did_parse(self, from_string: str) -> str:
|
||||
async def did_parse(self, from_string: str) -> str:
|
||||
'''
|
||||
This method is called after parsing from string and setting parameters found in pattern.
|
||||
You will very rarely, if ever, need to call this method directly.
|
||||
@ -42,7 +42,7 @@ class Object(ABC):
|
||||
return from_string
|
||||
|
||||
@classmethod
|
||||
def parse(cls, from_string: str, parameters: dict[str, str] | None = None) -> ParseResult:
|
||||
async def parse(cls, from_string: str, parameters: dict[str, str] | None = None) -> ParseResult:
|
||||
'''
|
||||
For internal use only.
|
||||
You will very rarely, if ever, need to override or even call this method.
|
||||
@ -59,9 +59,9 @@ class Object(ABC):
|
||||
if not parameters.get(name):
|
||||
continue
|
||||
value = parameters.pop(name)
|
||||
setattr(obj, name, object_type.parse(from_string = value, parameters = parameters).obj)
|
||||
setattr(obj, name, (await object_type.parse(from_string = value, parameters = parameters)).obj)
|
||||
|
||||
substring = obj.did_parse(from_string)
|
||||
substring = await obj.did_parse(from_string)
|
||||
|
||||
return ParseResult(obj, substring)
|
||||
|
||||
|
@ -49,7 +49,7 @@ class VoiceAssistant(SpeechRecognizerDelegate, CommandsContextDelegate):
|
||||
print(f'\nYou: {result}')
|
||||
# check explicit interaction if needed
|
||||
if pattern_str := self.mode.explicit_interaction_pattern:
|
||||
if not Pattern(pattern_str).match(result):
|
||||
if not await Pattern(pattern_str).match(result):
|
||||
return
|
||||
|
||||
# reset context if timeout reached
|
||||
@ -62,8 +62,7 @@ class VoiceAssistant(SpeechRecognizerDelegate, CommandsContextDelegate):
|
||||
if self.mode.mode_on_interaction:
|
||||
self.mode = self.mode.mode_on_interaction()
|
||||
|
||||
# main part: start command; response will come by delegate
|
||||
self.commands_context.process_string(result) # TODO: async
|
||||
await self.commands_context.process_string(result)
|
||||
|
||||
async def speech_recognizer_did_receive_partial_result(self, result: str):
|
||||
pass # print(f'\rYou: \x1B[3m{result}\x1B[0m', end = '')
|
||||
|
@ -7,7 +7,7 @@ async def test_basic_search(commands_context_flow_filled, autojump_clock):
|
||||
assert len(context_delegate.responses) == 0
|
||||
assert len(context._context_queue) == 1
|
||||
|
||||
context.process_string('lorem ipsum dolor')
|
||||
await context.process_string('lorem ipsum dolor')
|
||||
await anyio.sleep(5)
|
||||
assert len(context_delegate.responses) == 1
|
||||
assert context_delegate.responses[0].text == 'Lorem!'
|
||||
@ -16,14 +16,14 @@ async def test_basic_search(commands_context_flow_filled, autojump_clock):
|
||||
async def test_second_context_layer(commands_context_flow_filled, autojump_clock):
|
||||
async with commands_context_flow_filled() as (context, context_delegate):
|
||||
|
||||
context.process_string('hello world')
|
||||
await context.process_string('hello world')
|
||||
await anyio.sleep(5)
|
||||
assert len(context_delegate.responses) == 1
|
||||
assert context_delegate.responses[0].text == 'Hello, world!'
|
||||
assert len(context._context_queue) == 2
|
||||
context_delegate.responses.clear()
|
||||
|
||||
context.process_string('hello')
|
||||
await context.process_string('hello')
|
||||
await anyio.sleep(5)
|
||||
assert len(context_delegate.responses) == 1
|
||||
assert context_delegate.responses[0].text == 'Hi, world!'
|
||||
@ -33,13 +33,13 @@ async def test_second_context_layer(commands_context_flow_filled, autojump_clock
|
||||
async def test_context_pop_on_not_found(commands_context_flow_filled, autojump_clock):
|
||||
async with commands_context_flow_filled() as (context, context_delegate):
|
||||
|
||||
context.process_string('hello world')
|
||||
await context.process_string('hello world')
|
||||
await anyio.sleep(5)
|
||||
assert len(context._context_queue) == 2
|
||||
assert len(context_delegate.responses) == 1
|
||||
context_delegate.responses.clear()
|
||||
|
||||
context.process_string('lorem ipsum dolor')
|
||||
await context.process_string('lorem ipsum dolor')
|
||||
await anyio.sleep(5)
|
||||
assert len(context._context_queue) == 1
|
||||
assert len(context_delegate.responses) == 1
|
||||
@ -47,35 +47,35 @@ async def test_context_pop_on_not_found(commands_context_flow_filled, autojump_c
|
||||
async def test_context_pop_context_response_action(commands_context_flow_filled, autojump_clock):
|
||||
async with commands_context_flow_filled() as (context, context_delegate):
|
||||
|
||||
context.process_string('hello world')
|
||||
await context.process_string('hello world')
|
||||
await anyio.sleep(5)
|
||||
assert len(context_delegate.responses) == 1
|
||||
assert context_delegate.responses[0].text == 'Hello, world!'
|
||||
assert len(context._context_queue) == 2
|
||||
context_delegate.responses.clear()
|
||||
|
||||
context.process_string('bye')
|
||||
await context.process_string('bye')
|
||||
await anyio.sleep(5)
|
||||
assert len(context_delegate.responses) == 1
|
||||
assert context_delegate.responses[0].text == 'Bye, world!'
|
||||
assert len(context._context_queue) == 1
|
||||
context_delegate.responses.clear()
|
||||
|
||||
context.process_string('hello')
|
||||
await context.process_string('hello')
|
||||
await anyio.sleep(5)
|
||||
assert len(context_delegate.responses) == 0
|
||||
|
||||
async def test_repeat_last_answer_response_action(commands_context_flow_filled, autojump_clock):
|
||||
async with commands_context_flow_filled() as (context, context_delegate):
|
||||
|
||||
context.process_string('hello world')
|
||||
await context.process_string('hello world')
|
||||
await anyio.sleep(5)
|
||||
assert len(context_delegate.responses) == 1
|
||||
assert context_delegate.responses[0].text == 'Hello, world!'
|
||||
context_delegate.responses.clear()
|
||||
assert len(context_delegate.responses) == 0
|
||||
|
||||
context.process_string('repeat')
|
||||
await context.process_string('repeat')
|
||||
await anyio.sleep(5)
|
||||
assert len(context_delegate.responses) == 1
|
||||
assert context_delegate.responses[0].text == 'Hello, world!'
|
||||
|
@ -11,7 +11,7 @@ async def test_command_return_respond(commands_context_flow, autojump_clock):
|
||||
async def foo() -> Response:
|
||||
return Response(text = 'foo!')
|
||||
|
||||
context.process_string('foo')
|
||||
await context.process_string('foo')
|
||||
await anyio.sleep(5)
|
||||
|
||||
assert len(context_delegate.responses) == 1
|
||||
@ -24,7 +24,7 @@ async def test_sync_command_call_sync_respond(commands_context_flow, autojump_cl
|
||||
def foo(handler: ResponseHandler):
|
||||
handler.respond(Response(text = 'foo!'))
|
||||
|
||||
context.process_string('foo')
|
||||
await context.process_string('foo')
|
||||
await anyio.sleep(5)
|
||||
|
||||
assert len(context_delegate.responses) == 1
|
||||
@ -37,7 +37,7 @@ async def test_async_command_call_sync_respond(commands_context_flow, autojump_c
|
||||
async def foo(handler: AsyncResponseHandler):
|
||||
await handler.respond(Response(text = 'foo!'))
|
||||
|
||||
context.process_string('foo')
|
||||
await context.process_string('foo')
|
||||
await anyio.sleep(5)
|
||||
|
||||
assert len(context_delegate.responses) == 1
|
||||
@ -56,7 +56,7 @@ async def test_sync_command_call_async_respond(commands_context_flow, autojump_c
|
||||
assert issubclass(warnings_list[0].category, RuntimeWarning)
|
||||
assert 'was never awaited' in str(warnings_list[0].message)
|
||||
|
||||
context.process_string('foo')
|
||||
await context.process_string('foo')
|
||||
await anyio.sleep(5)
|
||||
|
||||
assert len(context_delegate.responses) == 0
|
||||
@ -70,7 +70,7 @@ async def test_async_command_call_async_respond(commands_context_flow, autojump_
|
||||
with pytest.raises(RuntimeError, match = 'can only be run from an AnyIO worker thread'):
|
||||
handler.respond(Response(text = 'foo!'))
|
||||
|
||||
context.process_string('foo')
|
||||
await context.process_string('foo')
|
||||
await anyio.sleep(5)
|
||||
|
||||
assert len(context_delegate.responses) == 0
|
||||
@ -91,7 +91,7 @@ async def test_command_multiple_respond(commands_context_flow, autojump_clock):
|
||||
await anyio.sleep(2)
|
||||
return Response(text = 'foo4')
|
||||
|
||||
context.process_string('foo')
|
||||
await context.process_string('foo')
|
||||
|
||||
last_count = 0
|
||||
while last_count < 5:
|
||||
|
@ -22,7 +22,7 @@ def test_new_with_extra_parameters_in_pattern():
|
||||
@manager.new('test $name:Word, $secondName:Word')
|
||||
def test(name: Word): pass
|
||||
|
||||
def test_search():
|
||||
async def test_search():
|
||||
manager = CommandsManager()
|
||||
|
||||
@manager.new('test')
|
||||
@ -35,13 +35,13 @@ def test_search():
|
||||
def hello(name: Word): pass
|
||||
|
||||
# test
|
||||
result = manager.search('test')
|
||||
result = await manager.search('test')
|
||||
assert result is not None
|
||||
assert len(result) == 1
|
||||
assert result[0].command.name == 'CommandsManager.test'
|
||||
|
||||
# hello
|
||||
result = manager.search('hello world')
|
||||
result = await manager.search('hello world')
|
||||
assert result is not None
|
||||
assert len(result) == 1
|
||||
assert result[0].command.name == 'CommandsManager.hello'
|
||||
@ -50,7 +50,7 @@ def test_search():
|
||||
assert result[0].match_result.parameters['name'].value == 'world'
|
||||
|
||||
# hello2
|
||||
result = manager.search('hello new world')
|
||||
result = await manager.search('hello new world')
|
||||
assert result is not None
|
||||
assert len(result) == 1
|
||||
assert result[0].command == hello2
|
||||
|
@ -15,7 +15,7 @@ async def test_multiple_commands(commands_context_flow, autojump_clock):
|
||||
def lorem():
|
||||
return Response(text = 'lorem!')
|
||||
|
||||
context.process_string('foo bar lorem ipsum dolor')
|
||||
await context.process_string('foo bar lorem ipsum dolor')
|
||||
await anyio.sleep(5)
|
||||
|
||||
assert len(context_delegate.responses) == 2
|
||||
@ -28,7 +28,7 @@ async def test_repeating_command(commands_context_flow, autojump_clock):
|
||||
def lorem():
|
||||
return Response(text = 'lorem!')
|
||||
|
||||
context.process_string('lorem pisum dolor lorem ipsutest_repeating_commanduum dolor sit amet')
|
||||
await context.process_string('lorem pisum dolor lorem ipsutest_repeating_commanduum dolor sit amet')
|
||||
await anyio.sleep(5)
|
||||
|
||||
assert len(context_delegate.responses) == 2
|
||||
@ -46,7 +46,7 @@ async def test_overlapping_commands_less_priority_cut(commands_context_flow, aut
|
||||
def baz():
|
||||
return Response(text = 'baz!')
|
||||
|
||||
result = manager.search('foo bar test baz')
|
||||
result = await manager.search('foo bar test baz')
|
||||
assert len(result) == 2
|
||||
assert result[0].match_result.substring == 'foo bar test'
|
||||
assert result[1].match_result.substring == 'baz'
|
||||
@ -62,7 +62,7 @@ async def test_overlapping_commands_priority_cut(commands_context_flow, autojump
|
||||
def baz():
|
||||
return Response(text = 'baz!')
|
||||
|
||||
result = manager.search('foo bar test baz')
|
||||
result = await manager.search('foo bar test baz')
|
||||
|
||||
assert len(result) == 2
|
||||
assert result[0].match_result.substring == 'foo bar'
|
||||
@ -79,7 +79,7 @@ async def test_overlapping_commands_remove(commands_context_flow, autojump_clock
|
||||
def barbaz():
|
||||
return Response(text = 'baz!')
|
||||
|
||||
result = manager.search('foo bar baz')
|
||||
result = await manager.search('foo bar baz')
|
||||
assert len(result) == 1
|
||||
assert result[0].command == foobar
|
||||
|
||||
@ -94,7 +94,7 @@ async def test_overlapping_commands_remove_inverse(commands_context_flow, autoju
|
||||
def foobar():
|
||||
return Response(text = 'foo!')
|
||||
|
||||
result = manager.search('foo bar baz')
|
||||
result = await manager.search('foo bar baz')
|
||||
assert len(result) == 1
|
||||
assert result[0].command == barbaz
|
||||
|
||||
@ -107,7 +107,7 @@ async def test_objects_parse_caching(commands_context_flow, autojump_clock):
|
||||
def pattern(cls):
|
||||
return Pattern('*')
|
||||
|
||||
def did_parse(self, from_string: str) -> str:
|
||||
async def did_parse(self, from_string: str) -> str:
|
||||
Mock.parsing_counter += 1
|
||||
return from_string
|
||||
|
||||
@ -130,7 +130,7 @@ async def test_objects_parse_caching(commands_context_flow, autojump_clock):
|
||||
async def test(mock: Mock): pass
|
||||
|
||||
assert Mock.parsing_counter == 0
|
||||
manager.search('hello foobar 22')
|
||||
await manager.search('hello foobar 22')
|
||||
assert Mock.parsing_counter == 1
|
||||
manager.search('hello foobar 22')
|
||||
await manager.search('hello foobar 22')
|
||||
assert Mock.parsing_counter == 2
|
||||
|
@ -16,20 +16,20 @@ class ExtraParameterInPattern(Object):
|
||||
def pattern(cls) -> Pattern:
|
||||
return Pattern('$word1:Word $word2:Word $word3:Word')
|
||||
|
||||
def test_typed_parameters():
|
||||
async def test_typed_parameters():
|
||||
p = Pattern('lorem $name:Word dolor')
|
||||
assert p.parameters == {'name': Word}
|
||||
assert p.compiled == fr'lorem (?P<name>{word}) dolor'
|
||||
|
||||
m = p.match('lorem ipsum dolor')
|
||||
m = await p.match('lorem ipsum dolor')
|
||||
assert m
|
||||
assert m[0].substring == 'lorem ipsum dolor'
|
||||
assert m[0].parameters == {'name': Word('ipsum')}
|
||||
assert not p.match('lorem ipsum foo dolor')
|
||||
assert not await p.match('lorem ipsum foo dolor')
|
||||
|
||||
p = Pattern('lorem $name:String dolor')
|
||||
assert p.parameters == {'name': String}
|
||||
m = p.match('lorem ipsum foo bar dolor')
|
||||
m = await p.match('lorem ipsum foo bar dolor')
|
||||
assert m
|
||||
assert m[0].substring == 'lorem ipsum foo bar dolor'
|
||||
assert m[0].parameters == {'name': String('ipsum foo bar')}
|
||||
|
@ -5,114 +5,114 @@ from core.patterns import expressions
|
||||
word = fr'[{expressions.alphanumerics}]*'
|
||||
words = fr'[{expressions.alphanumerics}\s]*'
|
||||
|
||||
def test_leading_star():
|
||||
async def test_leading_star():
|
||||
p = Pattern('*text')
|
||||
assert p.compiled == fr'{word}text'
|
||||
assert p.match('text')
|
||||
assert p.match('aaatext')
|
||||
assert p.match('bbb aaaatext cccc')[0].substring == 'aaaatext'
|
||||
assert not p.match('aaaaext')
|
||||
assert await p.match('text')
|
||||
assert await p.match('aaatext')
|
||||
assert (await p.match('bbb aaaatext cccc'))[0].substring == 'aaaatext'
|
||||
assert not await p.match('aaaaext')
|
||||
|
||||
p = Pattern('Some *text here')
|
||||
assert p.compiled == fr'Some {word}text here'
|
||||
assert p.match('Some text here')
|
||||
assert p.match('Some aaatext here')
|
||||
assert p.match('bbb Some aaatext here cccc')[0].substring == 'Some aaatext here'
|
||||
assert not p.match('aaatext here')
|
||||
assert await p.match('Some text here')
|
||||
assert await p.match('Some aaatext here')
|
||||
assert (await p.match('bbb Some aaatext here cccc'))[0].substring == 'Some aaatext here'
|
||||
assert not await p.match('aaatext here')
|
||||
|
||||
def test_trailing_star():
|
||||
async def test_trailing_star():
|
||||
p = Pattern('text*')
|
||||
assert p.compiled == fr'text{word}'
|
||||
assert p.match('text')
|
||||
assert p.match('textaaa')
|
||||
assert p.match('bbb textaaa cccc')[0].substring == 'textaaa'
|
||||
assert await p.match('text')
|
||||
assert await p.match('textaaa')
|
||||
assert (await p.match('bbb textaaa cccc'))[0].substring == 'textaaa'
|
||||
|
||||
p = Pattern('Some text* here')
|
||||
assert p.compiled == fr'Some text{word} here'
|
||||
assert p.match('Some text here')
|
||||
assert p.match('Some textaaa here')
|
||||
assert p.match('bbb Some textaaa here cccc')[0].substring == 'Some textaaa here'
|
||||
assert not p.match('Some textaaa ')
|
||||
assert await p.match('Some text here')
|
||||
assert await p.match('Some textaaa here')
|
||||
assert (await p.match('bbb Some textaaa here cccc'))[0].substring == 'Some textaaa here'
|
||||
assert not await p.match('Some textaaa ')
|
||||
|
||||
def test_middle_star():
|
||||
async def test_middle_star():
|
||||
p = Pattern('te*xt')
|
||||
assert p.compiled == fr'te{word}xt'
|
||||
assert p.match('text')
|
||||
assert p.match('teaaaaaxt')
|
||||
assert p.match('bbb teaaaaaxt cccc')[0].substring == 'teaaaaaxt'
|
||||
assert await p.match('text')
|
||||
assert await p.match('teaaaaaxt')
|
||||
assert (await p.match('bbb teaaaaaxt cccc'))[0].substring == 'teaaaaaxt'
|
||||
|
||||
p = Pattern('Some te*xt here')
|
||||
assert p.compiled == fr'Some te{word}xt here'
|
||||
assert p.match('Some text here')
|
||||
assert p.match('Some teaaaaaxt here')
|
||||
assert p.match('bbb Some teaaeaaaxt here cccc')[0].substring == 'Some teaaeaaaxt here'
|
||||
assert not p.match('Some teaaaaaxt')
|
||||
assert await p.match('Some text here')
|
||||
assert await p.match('Some teaaaaaxt here')
|
||||
assert (await p.match('bbb Some teaaeaaaxt here cccc'))[0].substring == 'Some teaaeaaaxt here'
|
||||
assert not await p.match('Some teaaaaaxt')
|
||||
|
||||
def test_double_star():
|
||||
async def test_double_star():
|
||||
p = Pattern('**')
|
||||
assert p.compiled == fr'{words}'
|
||||
assert p.match('bbb teaaaaaxt cccc')[0].substring == 'bbb teaaaaaxt cccc'
|
||||
assert (await p.match('bbb teaaaaaxt cccc'))[0].substring == 'bbb teaaaaaxt cccc'
|
||||
|
||||
p = Pattern('Some ** here')
|
||||
assert p.compiled == fr'Some {words} here'
|
||||
assert p.match('Some text here')
|
||||
assert p.match('Some lorem ipsum dolor here')
|
||||
assert p.match('bbb Some lorem ipsum dolor here cccc')[0].substring == 'Some lorem ipsum dolor here'
|
||||
assert await p.match('Some text here')
|
||||
assert await p.match('Some lorem ipsum dolor here')
|
||||
assert (await p.match('bbb Some lorem ipsum dolor here cccc'))[0].substring == 'Some lorem ipsum dolor here'
|
||||
|
||||
def test_one_of():
|
||||
async def test_one_of():
|
||||
p = Pattern('(foo|bar)')
|
||||
assert p.compiled == r'(?:foo|bar)'
|
||||
assert p.match('foo')
|
||||
assert p.match('bar')
|
||||
assert p.match('bbb foo cccc')[0].substring == 'foo'
|
||||
assert p.match('bbb bar cccc')[0].substring == 'bar'
|
||||
assert await p.match('foo')
|
||||
assert await p.match('bar')
|
||||
assert (await p.match('bbb foo cccc'))[0].substring == 'foo'
|
||||
assert (await p.match('bbb bar cccc'))[0].substring == 'bar'
|
||||
|
||||
p = Pattern('Some (foo|bar) here')
|
||||
assert p.compiled == r'Some (?:foo|bar) here'
|
||||
assert p.match('Some foo here')
|
||||
assert p.match('Some bar here')
|
||||
assert p.match('bbb Some foo here cccc')[0].substring == 'Some foo here'
|
||||
assert p.match('bbb Some bar here cccc')[0].substring == 'Some bar here'
|
||||
assert not p.match('Some foo')
|
||||
assert await p.match('Some foo here')
|
||||
assert await p.match('Some bar here')
|
||||
assert (await p.match('bbb Some foo here cccc'))[0].substring == 'Some foo here'
|
||||
assert (await p.match('bbb Some bar here cccc'))[0].substring == 'Some bar here'
|
||||
assert not await p.match('Some foo')
|
||||
|
||||
def test_optional_one_of():
|
||||
async def test_optional_one_of():
|
||||
p = Pattern('(foo|bar)?')
|
||||
assert p.compiled == r'(?:foo|bar)?'
|
||||
assert p.match('foo')
|
||||
assert p.match('bar')
|
||||
assert not p.match('')
|
||||
assert not p.match('bbb cccc')
|
||||
assert p.match('bbb foo cccc')[0].substring == 'foo'
|
||||
assert p.match('bbb bar cccc')[0].substring == 'bar'
|
||||
assert await p.match('foo')
|
||||
assert await p.match('bar')
|
||||
assert not await p.match('')
|
||||
assert not await p.match('bbb cccc')
|
||||
assert (await p.match('bbb foo cccc'))[0].substring == 'foo'
|
||||
assert (await p.match('bbb bar cccc'))[0].substring == 'bar'
|
||||
|
||||
p = Pattern('Some (foo|bar)? here')
|
||||
assert p.compiled == r'Some (?:foo|bar)? here'
|
||||
assert p.match('Some foo here')
|
||||
assert p.match('Some bar here')
|
||||
assert p.match('Some here')
|
||||
assert p.match('bbb Some foo here cccc')[0].substring == 'Some foo here'
|
||||
assert p.match('bbb Some bar here cccc')[0].substring == 'Some bar here'
|
||||
assert p.match('bbb Some here cccc')[0].substring == 'Some here'
|
||||
assert await p.match('Some foo here')
|
||||
assert await p.match('Some bar here')
|
||||
assert await p.match('Some here')
|
||||
assert (await p.match('bbb Some foo here cccc'))[0].substring == 'Some foo here'
|
||||
assert (await p.match('bbb Some bar here cccc'))[0].substring == 'Some bar here'
|
||||
assert (await p.match('bbb Some here cccc'))[0].substring == 'Some here'
|
||||
|
||||
# assert Pattern('[foo|bar]').compiled == Pattern('(foo|bar)?').compiled
|
||||
|
||||
def test_one_or_more_of():
|
||||
async def test_one_or_more_of():
|
||||
p = Pattern('{foo|bar}')
|
||||
assert p.compiled == r'(?:(?:foo|bar)\s?)+'
|
||||
assert p.match('foo')
|
||||
assert p.match('bar')
|
||||
assert not p.match('')
|
||||
assert p.match('bbb foo cccc')[0].substring == 'foo'
|
||||
assert p.match('bbb bar cccc')[0].substring == 'bar'
|
||||
assert p.match('bbb foo bar cccc')[0].substring == 'foo bar'
|
||||
assert not p.match('bbb cccc')
|
||||
assert await p.match('foo')
|
||||
assert await p.match('bar')
|
||||
assert not await p.match('')
|
||||
assert (await p.match('bbb foo cccc'))[0].substring == 'foo'
|
||||
assert (await p.match('bbb bar cccc'))[0].substring == 'bar'
|
||||
assert (await p.match('bbb foo bar cccc'))[0].substring == 'foo bar'
|
||||
assert not await p.match('bbb cccc')
|
||||
|
||||
p = Pattern('Some {foo|bar} here')
|
||||
assert p.compiled == r'Some (?:(?:foo|bar)\s?)+ here'
|
||||
assert p.match('Some foo here')
|
||||
assert p.match('Some bar here')
|
||||
assert not p.match('Some here')
|
||||
assert p.match('bbb Some foo here cccc')[0].substring == 'Some foo here'
|
||||
assert p.match('bbb Some bar here cccc')[0].substring == 'Some bar here'
|
||||
assert p.match('bbb Some foo bar here cccc')[0].substring == 'Some foo bar here'
|
||||
assert not p.match('Some foo')
|
||||
assert await p.match('Some foo here')
|
||||
assert await p.match('Some bar here')
|
||||
assert not await p.match('Some here')
|
||||
assert (await p.match('bbb Some foo here cccc'))[0].substring == 'Some foo here'
|
||||
assert (await p.match('bbb Some bar here cccc'))[0].substring == 'Some bar here'
|
||||
assert (await p.match('bbb Some foo bar here cccc'))[0].substring == 'Some foo bar here'
|
||||
assert not await p.match('Some foo')
|
||||
|
@ -10,21 +10,22 @@ class Lorem(Object):
|
||||
def pattern(cls):
|
||||
return Pattern('* ipsum')
|
||||
|
||||
def did_parse(self, from_string: str) -> str:
|
||||
async def did_parse(self, from_string: str) -> str:
|
||||
if 'lorem' not in from_string:
|
||||
raise ParseError('lorem not found')
|
||||
self.value = 'lorem'
|
||||
return 'lorem'
|
||||
|
||||
def test_complex_parsing_failed():
|
||||
async def test_complex_parsing_failed():
|
||||
with pytest.raises(ParseError):
|
||||
Lorem.parse('some lor ipsum')
|
||||
await Lorem.parse('some lor ipsum')
|
||||
|
||||
def test_complex_parsing():
|
||||
async def test_complex_parsing():
|
||||
string = 'some lorem ipsum'
|
||||
match = Lorem.parse(string)
|
||||
match = await Lorem.parse(string)
|
||||
assert match
|
||||
assert match.obj
|
||||
assert match.obj.value == 'lorem'
|
||||
assert match.substring == 'lorem'
|
||||
assert Lorem.pattern.match(string)[0].substring == 'lorem ipsum'
|
||||
assert (await Lorem.pattern.match(string))[0].substring == 'lorem ipsum'
|
||||
|
@ -20,27 +20,27 @@ class ExtraParameterInAnnotation(Object):
|
||||
def pattern(cls) -> Pattern:
|
||||
return Pattern('$word1:Word $word2:Word')
|
||||
|
||||
def test_nested_objects():
|
||||
async def test_nested_objects():
|
||||
Pattern.add_parameter_type(FullName)
|
||||
|
||||
p = Pattern('$name:FullName')
|
||||
assert p
|
||||
assert p.compiled
|
||||
|
||||
m = p.match('John Galt')
|
||||
m = await p.match('John Galt')
|
||||
assert m
|
||||
assert set(m[0].parameters.keys()) == {'name'}
|
||||
assert m[0].parameters['name'].first == Word('John')
|
||||
assert m[0].parameters['name'].second == Word('Galt')
|
||||
|
||||
def test_extra_parameter_in_annotation():
|
||||
async def test_extra_parameter_in_annotation():
|
||||
Pattern.add_parameter_type(ExtraParameterInAnnotation)
|
||||
|
||||
p = Pattern('$name:ExtraParameterInAnnotation')
|
||||
assert p
|
||||
assert p.compiled
|
||||
|
||||
m = p.match('John Galt')
|
||||
m = await p.match('John Galt')
|
||||
assert m
|
||||
assert set(m[0].parameters.keys()) == {'name'}
|
||||
assert m[0].parameters['name'].word1 == Word('John')
|
||||
|
@ -4,23 +4,23 @@ from core import String, Pattern
|
||||
def test_pattern():
|
||||
assert String.pattern == Pattern('**')
|
||||
|
||||
def test_parse():
|
||||
assert String.parse('')
|
||||
assert String.parse('foo bar baz').obj.value == 'foo bar baz'
|
||||
async def test_parse():
|
||||
assert await String.parse('')
|
||||
assert (await String.parse('foo bar baz')).obj.value == 'foo bar baz'
|
||||
|
||||
def test_match():
|
||||
async def test_match():
|
||||
p = Pattern('foo $bar:String baz')
|
||||
assert p
|
||||
|
||||
m = p.match('foo qwerty baz')
|
||||
m = await p.match('foo qwerty baz')
|
||||
assert m
|
||||
assert m[0].parameters['bar'] == String('qwerty')
|
||||
|
||||
m = p.match('foo lorem ipsum dolor sit amet baz')
|
||||
m = await p.match('foo lorem ipsum dolor sit amet baz')
|
||||
assert m
|
||||
assert m[0].parameters['bar'] == String('lorem ipsum dolor sit amet')
|
||||
|
||||
def test_formatted():
|
||||
string = String.parse('foo bar baz').obj
|
||||
async def test_formatted():
|
||||
string = (await String.parse('foo bar baz')).obj
|
||||
assert str(string) == '<String value: "foo bar baz">'
|
||||
assert f'{string}' == 'foo bar baz'
|
||||
assert f'{string}' == 'foo bar baz'
|
||||
|
@ -4,23 +4,23 @@ from core import Word, Pattern
|
||||
def test_pattern():
|
||||
assert Word.pattern == Pattern('*')
|
||||
|
||||
def test_parse():
|
||||
word = Word.parse('foo').obj
|
||||
async def test_parse():
|
||||
word = (await Word.parse('foo')).obj
|
||||
assert word
|
||||
assert word.value == 'foo'
|
||||
|
||||
def test_match():
|
||||
async def test_match():
|
||||
p = Pattern('foo $bar:Word baz')
|
||||
assert p
|
||||
|
||||
m = p.match('foo qwerty baz')
|
||||
m = await p.match('foo qwerty baz')
|
||||
assert m
|
||||
assert m[0].parameters['bar'] == Word('qwerty')
|
||||
|
||||
m = p.match('foo lorem ipsum dolor sit amet baz')
|
||||
m = await p.match('foo lorem ipsum dolor sit amet baz')
|
||||
assert not m
|
||||
|
||||
def test_formatted():
|
||||
string = Word.parse('foo').obj
|
||||
async def test_formatted():
|
||||
string = (await Word.parse('foo')).obj
|
||||
assert str(string) == '<Word value: "foo">'
|
||||
assert f'{string}' == 'foo'
|
||||
assert f'{string}' == 'foo'
|
||||
|
Loading…
x
Reference in New Issue
Block a user