From 1249e24342f28573b8ca8ea0ec53fa7ef066b58c Mon Sep 17 00:00:00 2001 From: Mark Parker Date: Sat, 16 Sep 2023 16:27:28 +0200 Subject: [PATCH] async pattern/object parse --- stark/core/commands_context.py | 4 +- stark/core/commands_manager.py | 28 +++- stark/core/patterns/pattern.py | 4 +- stark/core/types/object.py | 8 +- stark/voice_assistant/voice_assistant.py | 5 +- .../test_commands_context.py | 20 +-- .../test_commands_context_respond.py | 12 +- .../test_commands_manager.py | 8 +- .../test_multiple_commands.py | 18 +-- .../test_patterns/test_pattern_parameters.py | 8 +- tests/test_patterns/test_patterns.py | 136 +++++++++--------- tests/test_viobjects/test_complex_parsing.py | 13 +- tests/test_viobjects/test_nested_viobjects.py | 8 +- tests/test_viobjects/test_vistring.py | 18 +-- tests/test_viobjects/test_viword.py | 16 +-- 15 files changed, 160 insertions(+), 146 deletions(-) diff --git a/stark/core/commands_context.py b/stark/core/commands_context.py index 39cdb93..ca0081b 100644 --- a/stark/core/commands_context.py +++ b/stark/core/commands_context.py @@ -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 diff --git a/stark/core/commands_manager.py b/stark/core/commands_manager.py index f93f4f5..77dbb2d 100644 --- a/stark/core/commands_manager.py +++ b/stark/core/commands_manager.py @@ -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) diff --git a/stark/core/patterns/pattern.py b/stark/core/patterns/pattern.py index 9357be9..297f29f 100644 --- a/stark/core/patterns/pattern.py +++ b/stark/core/patterns/pattern.py @@ -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 diff --git a/stark/core/types/object.py b/stark/core/types/object.py index f2f83e6..bb433f8 100644 --- a/stark/core/types/object.py +++ b/stark/core/types/object.py @@ -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) diff --git a/stark/voice_assistant/voice_assistant.py b/stark/voice_assistant/voice_assistant.py index 39f3b23..8bfc909 100644 --- a/stark/voice_assistant/voice_assistant.py +++ b/stark/voice_assistant/voice_assistant.py @@ -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 = '') diff --git a/tests/test_commands_flow/test_commands_context.py b/tests/test_commands_flow/test_commands_context.py index 112adc9..3e9117b 100644 --- a/tests/test_commands_flow/test_commands_context.py +++ b/tests/test_commands_flow/test_commands_context.py @@ -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!' diff --git a/tests/test_commands_flow/test_commands_context_respond.py b/tests/test_commands_flow/test_commands_context_respond.py index 59d937a..738d587 100644 --- a/tests/test_commands_flow/test_commands_context_respond.py +++ b/tests/test_commands_flow/test_commands_context_respond.py @@ -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: diff --git a/tests/test_commands_flow/test_commands_manager.py b/tests/test_commands_flow/test_commands_manager.py index 547d8e8..b0d5f8b 100644 --- a/tests/test_commands_flow/test_commands_manager.py +++ b/tests/test_commands_flow/test_commands_manager.py @@ -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 diff --git a/tests/test_commands_flow/test_multiple_commands.py b/tests/test_commands_flow/test_multiple_commands.py index bff0011..38433a8 100644 --- a/tests/test_commands_flow/test_multiple_commands.py +++ b/tests/test_commands_flow/test_multiple_commands.py @@ -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 diff --git a/tests/test_patterns/test_pattern_parameters.py b/tests/test_patterns/test_pattern_parameters.py index 12088e0..c23351d 100644 --- a/tests/test_patterns/test_pattern_parameters.py +++ b/tests/test_patterns/test_pattern_parameters.py @@ -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{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')} diff --git a/tests/test_patterns/test_patterns.py b/tests/test_patterns/test_patterns.py index 629ebd9..44a124e 100644 --- a/tests/test_patterns/test_patterns.py +++ b/tests/test_patterns/test_patterns.py @@ -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') \ No newline at end of file + 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') diff --git a/tests/test_viobjects/test_complex_parsing.py b/tests/test_viobjects/test_complex_parsing.py index b8b3072..9b9035b 100644 --- a/tests/test_viobjects/test_complex_parsing.py +++ b/tests/test_viobjects/test_complex_parsing.py @@ -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' \ No newline at end of file + assert (await Lorem.pattern.match(string))[0].substring == 'lorem ipsum' + \ No newline at end of file diff --git a/tests/test_viobjects/test_nested_viobjects.py b/tests/test_viobjects/test_nested_viobjects.py index bd1aaf1..f220c01 100644 --- a/tests/test_viobjects/test_nested_viobjects.py +++ b/tests/test_viobjects/test_nested_viobjects.py @@ -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') diff --git a/tests/test_viobjects/test_vistring.py b/tests/test_viobjects/test_vistring.py index 41aece8..d67b31f 100644 --- a/tests/test_viobjects/test_vistring.py +++ b/tests/test_viobjects/test_vistring.py @@ -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) == '' - assert f'{string}' == 'foo bar baz' \ No newline at end of file + assert f'{string}' == 'foo bar baz' diff --git a/tests/test_viobjects/test_viword.py b/tests/test_viobjects/test_viword.py index c0184df..fafa432 100644 --- a/tests/test_viobjects/test_viword.py +++ b/tests/test_viobjects/test_viword.py @@ -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) == '' - assert f'{string}' == 'foo' \ No newline at end of file + assert f'{string}' == 'foo'