resolvable types
This commit is contained in:
parent
63be17e920
commit
b16f6262ec
5 changed files with 86 additions and 38 deletions
|
|
@ -1,27 +1,67 @@
|
||||||
|
from abc import ABC
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Generic
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Resolvable(ABC, Generic[T]):
|
||||||
|
value: T
|
||||||
|
|
||||||
|
def resolve(self) -> str:
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Integer(Resolvable[int]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Float(Resolvable[float]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Boolean(Resolvable[bool]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class String(Resolvable[str]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Functions:
|
class Functions:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def lower(string: str) -> str:
|
def lower(string: String) -> String:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
Lower-cased string
|
Lower-cased string
|
||||||
"""
|
"""
|
||||||
return string.lower()
|
return String(string.value.lower())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def upper(string: str) -> str:
|
def upper(string: String) -> String:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
Upper-cased string
|
Upper-cased string
|
||||||
"""
|
"""
|
||||||
return string.upper()
|
return String(string.value.upper())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def capitalize(string: str) -> str:
|
def capitalize(string: String) -> String:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
Capitalized string
|
Capitalized string
|
||||||
"""
|
"""
|
||||||
return string.capitalize()
|
return String(string.value.capitalize())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def concat(l_string: String, r_string: String) -> String:
|
||||||
|
return String(f"{l_string}{r_string}")
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from ytdl_sub.script.functions import Boolean
|
||||||
|
from ytdl_sub.script.functions import Float
|
||||||
|
from ytdl_sub.script.functions import Integer
|
||||||
|
from ytdl_sub.script.functions import String
|
||||||
from ytdl_sub.script.types import ArgumentType
|
from ytdl_sub.script.types import ArgumentType
|
||||||
from ytdl_sub.script.types import Boolean
|
|
||||||
from ytdl_sub.script.types import Float
|
|
||||||
from ytdl_sub.script.types import Function
|
from ytdl_sub.script.types import Function
|
||||||
from ytdl_sub.script.types import Integer
|
|
||||||
from ytdl_sub.script.types import LiteralString
|
from ytdl_sub.script.types import LiteralString
|
||||||
from ytdl_sub.script.types import NumericType
|
from ytdl_sub.script.types import NumericType
|
||||||
from ytdl_sub.script.types import String
|
|
||||||
from ytdl_sub.script.types import SyntaxTree
|
from ytdl_sub.script.types import SyntaxTree
|
||||||
from ytdl_sub.script.types import Variable
|
from ytdl_sub.script.types import Variable
|
||||||
from ytdl_sub.utils.exceptions import StringFormattingException
|
from ytdl_sub.utils.exceptions import StringFormattingException
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,18 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import List, Dict, Optional
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
from typing import Set
|
from typing import Set
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
from ytdl_sub.script.functions import Boolean
|
||||||
|
from ytdl_sub.script.functions import Float
|
||||||
|
from ytdl_sub.script.functions import Functions
|
||||||
|
from ytdl_sub.script.functions import Integer
|
||||||
|
from ytdl_sub.script.functions import String
|
||||||
from ytdl_sub.utils.exceptions import StringFormattingException
|
from ytdl_sub.utils.exceptions import StringFormattingException
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class Integer:
|
|
||||||
value: int
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class Float:
|
|
||||||
value: float
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class Boolean:
|
|
||||||
value: bool
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class String:
|
|
||||||
value: str
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Variable:
|
class Variable:
|
||||||
name: str
|
name: str
|
||||||
|
|
@ -40,6 +27,12 @@ class Function:
|
||||||
name: str
|
name: str
|
||||||
args: List[ArgumentType]
|
args: List[ArgumentType]
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
try:
|
||||||
|
getattr(Functions, self.name)
|
||||||
|
except AttributeError:
|
||||||
|
raise StringFormattingException(f"Function name {self.name} does not exist")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def variables(self) -> Set[Variable]:
|
def variables(self) -> Set[Variable]:
|
||||||
"""
|
"""
|
||||||
|
|
@ -68,6 +61,11 @@ class SyntaxTree:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def variables(self) -> Set[Variable]:
|
def variables(self) -> Set[Variable]:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
All variables used within the SyntaxTree
|
||||||
|
"""
|
||||||
variables: Set[Variable] = set()
|
variables: Set[Variable] = set()
|
||||||
for token in self.ast:
|
for token in self.ast:
|
||||||
if isinstance(token, Variable):
|
if isinstance(token, Variable):
|
||||||
|
|
@ -79,11 +77,19 @@ class SyntaxTree:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def detect_cycles(cls, parsed_overrides: Dict[str, "SyntaxTree"]) -> None:
|
def detect_cycles(cls, parsed_overrides: Dict[str, "SyntaxTree"]) -> None:
|
||||||
|
"""
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
parsed_overrides
|
||||||
|
``overrides`` in a subscription, parsed into a SyntaxTree
|
||||||
|
"""
|
||||||
variable_dependencies: Dict[Variable, Set[Variable]] = {
|
variable_dependencies: Dict[Variable, Set[Variable]] = {
|
||||||
Variable(name): ast.variables for name, ast in parsed_overrides.items()
|
Variable(name): ast.variables for name, ast in parsed_overrides.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
def _traverse(to_variable: Variable, visited_variables: Optional[List[Variable]] = None) -> None:
|
def _traverse(
|
||||||
|
to_variable: Variable, visited_variables: Optional[List[Variable]] = None
|
||||||
|
) -> None:
|
||||||
if visited_variables is None:
|
if visited_variables is None:
|
||||||
visited_variables = []
|
visited_variables = []
|
||||||
|
|
||||||
|
|
@ -97,4 +103,6 @@ class SyntaxTree:
|
||||||
for variable in variable_dependencies.keys():
|
for variable in variable_dependencies.keys():
|
||||||
_traverse(variable)
|
_traverse(variable)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve(cls, parsed_overrides: Dict[str, "SyntaxTree"]) -> Dict[str, str]:
|
||||||
|
raise NotImplemented()
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ def download_and_convert_url_thumbnail(
|
||||||
# timeout after 8 seconds
|
# timeout after 8 seconds
|
||||||
with urlopen(thumbnail_url, timeout=1.0) as file:
|
with urlopen(thumbnail_url, timeout=1.0) as file:
|
||||||
with tempfile.NamedTemporaryFile(delete=False) as thumbnail:
|
with tempfile.NamedTemporaryFile(delete=False) as thumbnail:
|
||||||
thumbnail.write(file._read())
|
thumbnail.write(file.read())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.makedirs(os.path.dirname(output_thumbnail_path), exist_ok=True)
|
os.makedirs(os.path.dirname(output_thumbnail_path), exist_ok=True)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from ytdl_sub.script.functions import Boolean
|
||||||
|
from ytdl_sub.script.functions import Float
|
||||||
|
from ytdl_sub.script.functions import Integer
|
||||||
|
from ytdl_sub.script.functions import String
|
||||||
from ytdl_sub.script.parser import parse
|
from ytdl_sub.script.parser import parse
|
||||||
from ytdl_sub.script.types import Boolean
|
|
||||||
from ytdl_sub.script.types import Float
|
|
||||||
from ytdl_sub.script.types import Function
|
from ytdl_sub.script.types import Function
|
||||||
from ytdl_sub.script.types import Integer
|
|
||||||
from ytdl_sub.script.types import LiteralString
|
from ytdl_sub.script.types import LiteralString
|
||||||
from ytdl_sub.script.types import String
|
|
||||||
from ytdl_sub.script.types import SyntaxTree
|
from ytdl_sub.script.types import SyntaxTree
|
||||||
from ytdl_sub.script.types import Variable
|
from ytdl_sub.script.types import Variable
|
||||||
from ytdl_sub.utils.exceptions import StringFormattingException
|
from ytdl_sub.utils.exceptions import StringFormattingException
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue