Add typing in HLDS code, change price to int

This commit is contained in:
Midgard 2020-01-26 15:09:22 +01:00
parent 798e08d74b
commit fe593fece6
Signed by: midgard
GPG key ID: 511C112F1331BBB4
4 changed files with 42 additions and 31 deletions

View file

@ -1,7 +1,9 @@
# Import this class to load the standard HLDS definitions # Import this class to load the standard HLDS definitions
from os import path from os import path
from typing import List
from .parser import parse_all_directory from .parser import parse_all_directory
from .models import Location
__all__ = ["location_definitions"] __all__ = ["location_definitions"]
@ -10,4 +12,4 @@ __all__ = ["location_definitions"]
DATA_DIR = path.join(path.dirname(__file__), "..", "..", "data") DATA_DIR = path.join(path.dirname(__file__), "..", "..", "data")
# pylint: disable=invalid-name # pylint: disable=invalid-name
location_definitions = parse_all_directory(DATA_DIR) location_definitions: List[Location] = parse_all_directory(DATA_DIR)

View file

@ -80,7 +80,7 @@ identifier = /[a-z0-9_-]+/ ;
string = /[^\n]+/ ; string = /[^\n]+/ ;
choice_type = 'single_choice' | 'multi_choice' ; choice_type = 'single_choice' | 'multi_choice' ;
number = /[0-9]+(\.[0-9]+)?/ ; int = /[0-9]+/ ;
currency = '€' ; currency = '€' ;
price = currency:currency s value:number ; price = currency:currency s value_unit:int [ '.' value_cents:/[0-9]{,2}/ ] ;

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
from typing import List from typing import List, Mapping, Any
def _format_tags(tags): def _format_tags(tags):
@ -19,11 +19,11 @@ def _format_type_and_choice(type_and_choice):
class Option: class Option:
def __init__(self, id_, *, name, description, price, tags): def __init__(self, id_, *, name, description, price, tags):
self.id = id_ self.id: str = id_
self.name = name self.name: str = name
self.description = description self.description: str = description
self.price = price self.price: int = price
self.tags = tags self.tags: List[str] = tags
def __str__(self): def __str__(self):
return "{0.id}: {0.name}{1}{2}{3}".format( return "{0.id}: {0.name}{1}{2}{3}".format(
@ -36,9 +36,9 @@ class Option:
class Choice: class Choice:
def __init__(self, id_, *, name, description, options): def __init__(self, id_, *, name, description, options):
self.id = id_ self.id: str = id_
self.name = name self.name: str = name
self.description = description self.description: str = description
self.options: List[Option] = options self.options: List[Option] = options
@ -52,11 +52,11 @@ class Choice:
class Dish: class Dish:
def __init__(self, id_, *, name, description, price, tags, choices): def __init__(self, id_, *, name, description, price, tags, choices):
self.id = id_ self.id: str = id_
self.name = name self.name: str = name
self.description = description self.description: str = description
self.price = price self.price: int = price
self.tags = tags self.tags: List[str] = tags
self.choices: List[(str, Choice)] = choices self.choices: List[(str, Choice)] = choices
@ -72,9 +72,9 @@ class Dish:
class Location: class Location:
def __init__(self, id_, *, name, attributes, dishes): def __init__(self, id_, *, name, attributes, dishes):
self.id = id_ self.id: str = id_
self.name = name self.name: str = name
self.attributes = attributes self.attributes: Mapping[str, Any] = attributes
self.dishes: List[Dish] = dishes self.dishes: List[Dish] = dishes

View file

@ -3,7 +3,9 @@
from glob import glob from glob import glob
from os import path from os import path
import itertools import itertools
from typing import Iterable, List, Union, Tuple
from tatsu import parse as tatsu_parse from tatsu import parse as tatsu_parse
from tatsu.ast import AST
from .models import Location, Choice, Option, Dish from .models import Location, Choice, Option, Dish
@ -18,7 +20,7 @@ def filter_instance(cls, iterable):
# pylint: disable=no-self-use # pylint: disable=no-self-use
class HldsSemanticActions: class HldsSemanticActions:
def location(self, ast): def location(self, ast) -> Location:
choices = {choice.id: choice for choice in filter_instance(Choice, ast["items_"])} choices = {choice.id: choice for choice in filter_instance(Choice, ast["items_"])}
dishes = filter_instance(Dish, ast["items_"]) dishes = filter_instance(Dish, ast["items_"])
for dish in dishes: for dish in dishes:
@ -33,7 +35,7 @@ class HldsSemanticActions:
dishes=dishes, dishes=dishes,
) )
def base_block(self, ast): def base_block(self, ast) -> Dish:
return Dish( return Dish(
ast["id"], ast["id"],
name=ast["name"], name=ast["name"],
@ -43,7 +45,7 @@ class HldsSemanticActions:
choices=ast["choices"], choices=ast["choices"],
) )
def choice_block(self, ast): def choice_block(self, ast) -> Choice:
return Choice( return Choice(
ast["id"], ast["id"],
name=ast["name"], name=ast["name"],
@ -51,14 +53,14 @@ class HldsSemanticActions:
options=ast["entries"], options=ast["entries"],
) )
def indent_choice_block(self, ast): def indent_choice_block(self, ast) -> Tuple[str, Union[Choice, AST]]:
return ( return (
(ast["type"], self.choice_block(ast)) (ast["type"], self.choice_block(ast))
if ast["kind"] == "declaration" else if ast["kind"] == "declaration" else
(ast["type"], ast["id"]) (ast["type"], ast["id"])
) )
def indent_choice_entry(self, ast): def indent_choice_entry(self, ast) -> Option:
return Option( return Option(
ast["id"], ast["id"],
name=ast["name"], name=ast["name"],
@ -69,8 +71,15 @@ class HldsSemanticActions:
noindent_choice_entry = indent_choice_entry noindent_choice_entry = indent_choice_entry
def price(self, ast): def price(self, ast) -> int:
return "{0[currency]} {0[value]}".format(ast) return (
100 * int(ast["value_unit"]) +
(
0 if not ast["value_cents"] else
10 * int(ast["value_cents"]) if len(ast["value_cents"]) == 1 else
int(ast["value_cents"])
)
)
def _default(self, ast): def _default(self, ast):
return ast return ast
@ -78,22 +87,22 @@ class HldsSemanticActions:
SEMANTICS = HldsSemanticActions() SEMANTICS = HldsSemanticActions()
def parse(menu): def parse(menu: str) -> List[Location]:
parsed = tatsu_parse(GRAMMAR, menu, semantics=SEMANTICS) parsed = tatsu_parse(GRAMMAR, menu, semantics=SEMANTICS)
return parsed return parsed
def parse_file(filename): def parse_file(filename: str) -> List[Location]:
with open(filename, "r") as file_handle: with open(filename, "r") as file_handle:
return parse(file_handle.read()) return parse(file_handle.read())
def parse_files(files): def parse_files(files: Iterable[str]) -> List[Location]:
menus = map(parse_file, files) menus = map(parse_file, files)
return list(itertools.chain.from_iterable(menus)) return list(itertools.chain.from_iterable(menus))
def parse_all_directory(directory): def parse_all_directory(directory: str) -> List[Location]:
# TODO Use proper way to get resources, see https://stackoverflow.com/a/10935674 # TODO Use proper way to get resources, see https://stackoverflow.com/a/10935674
files = glob(path.join(directory, "**.hlds"), recursive=True) files = glob(path.join(directory, "**.hlds"), recursive=True)
return parse_files(files) return parse_files(files)