Add typing in HLDS code, change price to int
This commit is contained in:
parent
798e08d74b
commit
fe593fece6
4 changed files with 42 additions and 31 deletions
|
@ -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)
|
||||||
|
|
|
@ -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}/ ] ;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue