diff --git a/pyproject.toml b/pyproject.toml index f04e9334..42eb87d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,7 @@ force_single_line = true [tool.black] line_length = 100 +target-version = ["py310"] [tool.pylint.MASTER] disable = [ diff --git a/src/ytdl_sub/downloaders/ytdl_options_builder.py b/src/ytdl_sub/downloaders/ytdl_options_builder.py index b159da42..9f389b51 100644 --- a/src/ytdl_sub/downloaders/ytdl_options_builder.py +++ b/src/ytdl_sub/downloaders/ytdl_options_builder.py @@ -17,7 +17,7 @@ class YTDLOptionsBuilder: self, *ytdl_option_dicts: Optional[Dict], before: bool = False, - strategy: mergedeep.Strategy = mergedeep.Strategy.TYPESAFE_ADDITIVE + strategy: mergedeep.Strategy = mergedeep.Strategy.TYPESAFE_ADDITIVE, ) -> "YTDLOptionsBuilder": """ Parameters diff --git a/src/ytdl_sub/script/script.py b/src/ytdl_sub/script/script.py index d7e3bd37..f73dd870 100644 --- a/src/ytdl_sub/script/script.py +++ b/src/ytdl_sub/script/script.py @@ -1,4 +1,5 @@ -from typing import Dict, Optional +from typing import Dict +from typing import Optional from ytdl_sub.script.parser import parse from ytdl_sub.script.syntax_tree import SyntaxTree @@ -28,9 +29,11 @@ class Script: if not self._is_function(override_name) } - def resolve(self, pre_resolved_variables: Optional[Dict[Variable, Resolvable]] = None) -> Dict[str, Resolvable]: + def resolve( + self, pre_resolved_variables: Optional[Dict[Variable, Resolvable]] = None + ) -> Dict[str, Resolvable]: return SyntaxTree.resolve_overrides( parsed_overrides=self._variables, custom_functions=self._functions, pre_resolved_variables=pre_resolved_variables, - ) \ No newline at end of file + ) diff --git a/src/ytdl_sub/script/syntax_tree.py b/src/ytdl_sub/script/syntax_tree.py index 666594c4..1e943a31 100644 --- a/src/ytdl_sub/script/syntax_tree.py +++ b/src/ytdl_sub/script/syntax_tree.py @@ -1,9 +1,9 @@ from dataclasses import dataclass -from typing import Dict, Optional +from typing import Dict from typing import List +from typing import Optional from typing import Set -from ytdl_sub.script.types.function import Function from ytdl_sub.script.types.resolvable import ArgumentType from ytdl_sub.script.types.resolvable import Resolvable from ytdl_sub.script.types.resolvable import String @@ -73,14 +73,19 @@ class SyntaxTree(VariableDependency): @classmethod def resolve_overrides( - cls, parsed_overrides: Dict[str, "SyntaxTree"], custom_functions: Dict[str, "SyntaxTree"], pre_resolved_variables: Optional[Dict[Variable, Resolvable]] + cls, + parsed_overrides: Dict[str, "SyntaxTree"], + custom_functions: Dict[str, "SyntaxTree"], + pre_resolved_variables: Optional[Dict[Variable, Resolvable]], ) -> Dict[str, Resolvable]: overrides: Dict[Variable, "SyntaxTree"] = { Variable(name): ast for name, ast in parsed_overrides.items() } unresolved_variables: List[Variable] = list(overrides.keys()) - resolved_variables: Dict[Variable, Resolvable] = pre_resolved_variables if pre_resolved_variables else {} + resolved_variables: Dict[Variable, Resolvable] = ( + pre_resolved_variables if pre_resolved_variables else {} + ) while unresolved_variables: unresolved_count: int = len(unresolved_variables) diff --git a/src/ytdl_sub/validators/string_formatter_validators.py b/src/ytdl_sub/validators/string_formatter_validators.py index 4408680f..8891604d 100644 --- a/src/ytdl_sub/validators/string_formatter_validators.py +++ b/src/ytdl_sub/validators/string_formatter_validators.py @@ -14,7 +14,7 @@ from ytdl_sub.validators.validators import ListValidator from ytdl_sub.validators.validators import LiteralDictValidator from ytdl_sub.validators.validators import StringValidator -_fields_validator = re.compile(r"{([a-z][a-z0-9_]+?)}") +_fields_validator = re.compile(r"{([a-z][a-z0-9_]*?)}") _fields_validator_exception_message: str = ( "{variable_names} must start with a lowercase letter, should only contain lowercase letters, " diff --git a/tests/unit/script/test_parser.py b/tests/unit/script/test_parser.py index aacab1a6..9b870b6a 100644 --- a/tests/unit/script/test_parser.py +++ b/tests/unit/script/test_parser.py @@ -4,7 +4,7 @@ import pytest from ytdl_sub.script.parser import parse from ytdl_sub.script.syntax_tree import SyntaxTree -from ytdl_sub.script.types.function import Function +from ytdl_sub.script.types.function import BuiltInFunction from ytdl_sub.script.types.resolvable import Boolean from ytdl_sub.script.types.resolvable import Float from ytdl_sub.script.types.resolvable import Integer @@ -24,7 +24,7 @@ class TestParser: assert parsed == SyntaxTree( [ String("hello "), - Function(name="capitalize", args=[String(value="hi mom")]), + BuiltInFunction(name="capitalize", args=[String(value="hi mom")]), ] ) @@ -56,7 +56,7 @@ class TestParser: assert parsed == SyntaxTree( [ String("hello "), - Function( + BuiltInFunction( name="if", args=[Boolean(value=True), String(value="hi"), Float(value=3.4)] ), ] @@ -68,10 +68,10 @@ class TestParser: assert parsed == SyntaxTree( [ String("hello "), - Function( + BuiltInFunction( name="concat", args=[ - Function( + BuiltInFunction( name="if", args=[Boolean(value=True), String("hi"), String("mom")] ), String(value="and dad"), @@ -85,10 +85,10 @@ class TestParser: assert parsed == SyntaxTree( [ String("hello "), - Function( + BuiltInFunction( name="string", args=[ - Function(name="if", args=[Boolean(True), String("hi"), Integer(4)]), + BuiltInFunction(name="if", args=[Boolean(True), String("hi"), Integer(4)]), ], ), ] @@ -99,7 +99,7 @@ class TestParser: assert parsed == SyntaxTree( [ String("hello "), - Function(name="concat", args=[String(value="hi mom")]), + BuiltInFunction(name="concat", args=[String(value="hi mom")]), ] ) @@ -108,7 +108,7 @@ class TestParser: assert parsed == SyntaxTree( [ String("hello "), - Function(name="concat", args=[String(value="hi"), String(value="mom")]), + BuiltInFunction(name="concat", args=[String(value="hi"), String(value="mom")]), ] ) @@ -117,7 +117,7 @@ class TestParser: assert parsed == SyntaxTree( [ String("hello "), - Function( + BuiltInFunction( name="replace", args=[String(value="hi mom"), String(value="hi"), String(value="")], ), @@ -129,7 +129,7 @@ class TestParser: assert parsed == SyntaxTree( [ String("hello "), - Function( + BuiltInFunction( name="replace", args=[ String(value="hi mom"), @@ -151,15 +151,15 @@ class TestParser: assert parsed == SyntaxTree( [ String(value=f"hello{s}"), - Function( + BuiltInFunction( name="concat", args=[ String(value="string"), - Function(name="string", args=[Integer(value=1)]), - Function(name="string", args=[Float(value=2.4)]), - Function(name="string", args=[Boolean(value=True)]), - Function(name="string", args=[Variable(name="variable_name")]), - Function(name="capitalize", args=[String(value="hi")]), + BuiltInFunction(name="string", args=[Integer(value=1)]), + BuiltInFunction(name="string", args=[Float(value=2.4)]), + BuiltInFunction(name="string", args=[Boolean(value=True)]), + BuiltInFunction(name="string", args=[Variable(name="variable_name")]), + BuiltInFunction(name="capitalize", args=[String(value="hi")]), ], ), ] diff --git a/tests/unit/script/test_script.py b/tests/unit/script/test_script.py index 378c18d3..37a15a23 100644 --- a/tests/unit/script/test_script.py +++ b/tests/unit/script/test_script.py @@ -11,27 +11,34 @@ from ytdl_sub.utils.exceptions import StringFormattingException class TestSyntaxTree: - def test_simple(self): - script = Script( - { - "a": "a", - "b": "{b_}", - "b_": "b", - } - ) - def test_custom_function(self): - script = Script( + assert Script( { "%custom_func": "return {[$1, $2]}", "aa": "a", "bb": "b", "cc": "{%custom_func(aa, bb)}", } - ) + ).resolve() == {"aa": String("a"), "bb": String("b"), "cc": String("return [aa, bb]")} - out = script.resolve() - assert False + def test_simple(self): + assert Script({"a": "a", "b": "{b_}", "b_": "b",}).resolve() == { + "a": String("a"), + "b": String("b"), + "b_": String("b"), + } + def test_simple_with_function(self): + assert Script({"a": "a", "b": "{%capitalize(b_)}", "b_": "b",}).resolve() == { + "a": String("a"), + "b": String("B"), + "b_": String("b"), + } + def test_simple_cycle(self): + with pytest.raises(StringFormattingException): + Script({"a": "{b}", "b": "{a}"}).resolve() + def test_simple_cycle_with_function(self): + with pytest.raises(StringFormattingException): + Script({"b": "{%capitalize(b_)}", "b_": "{b}"}).resolve()