forked from Hanabi/hanabi-league
Add config file for hanabi league
This commit is contained in:
parent
cc8dd2a90c
commit
ab32fae4f2
5 changed files with 147 additions and 1 deletions
115
config.py
115
config.py
|
@ -1,8 +1,11 @@
|
||||||
import shutil
|
import shutil
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
import platformdirs
|
import platformdirs
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
import dateutil.parser
|
||||||
|
|
||||||
import constants
|
import constants
|
||||||
from log_setup import logger
|
from log_setup import logger
|
||||||
|
@ -71,3 +74,115 @@ def create_db_config() -> None:
|
||||||
logger.info("Created default DB config file at {}".format(config_path))
|
logger.info("Created default DB config file at {}".format(config_path))
|
||||||
else:
|
else:
|
||||||
logger.info("DB config file at {} already exists".format(config_path))
|
logger.info("DB config file at {} already exists".format(config_path))
|
||||||
|
|
||||||
|
|
||||||
|
def check_config_attr(func):
|
||||||
|
def wrapper():
|
||||||
|
try:
|
||||||
|
func()
|
||||||
|
except KeyError as e:
|
||||||
|
logger.error("Missing config attribute:\n{}".format(e))
|
||||||
|
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
def __init__(self, config: Dict):
|
||||||
|
self._config = config
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def player_base_rating(self) -> int:
|
||||||
|
return self._config["player_base_rating"]
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def min_player_count(self) -> int:
|
||||||
|
return self._config["min_player_count"]
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def max_player_count(self) -> int:
|
||||||
|
return self._config["max_player_count"]
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def min_suit_count(self) -> int:
|
||||||
|
return self._config["min_suit_count"]
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def max_suit_count(self) -> int:
|
||||||
|
return self._config["max_suit_count"]
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def starting_game_id(self) -> int:
|
||||||
|
return self._config["starting_game_id"]
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def ending_game_id(self) -> int:
|
||||||
|
return self._config["ending_game_id"]
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def starting_time(self):
|
||||||
|
time = self._config["starting_time"]
|
||||||
|
return dateutil.parser(time, tzinfos={'EST': 'US/Eastern'})
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def ending_time(self):
|
||||||
|
time = self._config["ending_time"]
|
||||||
|
return dateutil.parser(time, tzinfos={'EST': 'US/Eastern'})
|
||||||
|
|
||||||
|
@check_config_attr
|
||||||
|
def variant_base_rating(self, variant_name: str, player_count: int) -> int:
|
||||||
|
global_base_rating = self._config["variant_base_rating"]
|
||||||
|
|
||||||
|
# We use different ways of specifying base ratings here:
|
||||||
|
# First, there is a (required) config setting for the variant base rating, which will be used as default.
|
||||||
|
# Then, for each variant, it is possible to either specify some base rating directly,
|
||||||
|
# or further specify a base rating for each player count.
|
||||||
|
# Parsing this is now quite easy: We just check if there is an entry for the specific variant and if so,
|
||||||
|
# read the base rating from there, where we will have to distinguish between a player-independent value
|
||||||
|
# and possibly player-specific entries. Whenever we don't find an explicit entry, we use the global fallback.
|
||||||
|
# This makes it possible to just specify the variant + player combinations that differ in their base rating
|
||||||
|
# from the globally specified one.
|
||||||
|
|
||||||
|
var_rating = self._config.get("variant_base_ratings", {}).get(variant_name, None)
|
||||||
|
|
||||||
|
if type(var_rating) == int:
|
||||||
|
return var_rating
|
||||||
|
elif type(var_rating) == dict:
|
||||||
|
return var_rating.get("{}p".format(player_count), global_base_rating)
|
||||||
|
elif var_rating is None:
|
||||||
|
return global_base_rating
|
||||||
|
|
||||||
|
logger.error("Unexpected config format for entry {} in 'variant_base_ratings'".format(variant_name))
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_path():
|
||||||
|
config_dir = Path(platformdirs.user_config_dir(constants.APP_NAME, ensure_exists=True))
|
||||||
|
config_path = config_dir / constants.CONFIG_FILE_NAME
|
||||||
|
return config_path
|
||||||
|
|
||||||
|
|
||||||
|
def read_config() -> Config:
|
||||||
|
config_path = get_config_path()
|
||||||
|
logger.verbose("Hanabi League configuration read from file {}".format(config_path))
|
||||||
|
if config_path.exists():
|
||||||
|
with open(config_path, "r") as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
return Config(config)
|
||||||
|
else:
|
||||||
|
logger.info("No hanabi league configuration found. Falling back to default file {}".format(
|
||||||
|
constants.DEFAULT_CONFIG_PATH))
|
||||||
|
logger.info(
|
||||||
|
"Note: To turn off this message, create a config file at {}".format(config_path)
|
||||||
|
)
|
||||||
|
with open(constants.DEFAULT_CONFIG_PATH, "r") as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
return Config(config)
|
||||||
|
|
||||||
|
|
||||||
|
def create_config() -> None:
|
||||||
|
"""
|
||||||
|
Creates a default config file for the league at the config location
|
||||||
|
"""
|
||||||
|
config_path = get_config_path()
|
||||||
|
if not config_path.exists():
|
||||||
|
shutil.copy(constants.DEFAULT_CONFIG_PATH, config_path)
|
||||||
|
logger.info("Created default hanabi league config file at {}".format(config_path))
|
||||||
|
else:
|
||||||
|
logger.info("Hanabi league config file at {} already exists".format(config_path))
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
# It's not meant to include all string constants or anything, just the ones that are important for functioning.
|
# It's not meant to include all string constants or anything, just the ones that are important for functioning.
|
||||||
|
|
||||||
APP_NAME = 'hanabi-league'
|
APP_NAME = 'hanabi-league'
|
||||||
DB_CONFIG_FILE_NAME = 'config.yaml'
|
DB_CONFIG_FILE_NAME = 'db_config.yaml'
|
||||||
|
CONFIG_FILE_NAME = 'config.yaml'
|
||||||
|
|
||||||
DEFAULT_DB_NAME = 'hanabi-league'
|
DEFAULT_DB_NAME = 'hanabi-league'
|
||||||
DEFAULT_DB_USER = 'hanabi-league'
|
DEFAULT_DB_USER = 'hanabi-league'
|
||||||
|
@ -27,3 +28,4 @@ DB_TABLE_NAMES = [
|
||||||
|
|
||||||
DATABASE_SCHEMA_PATH = 'install/database_schema.sql'
|
DATABASE_SCHEMA_PATH = 'install/database_schema.sql'
|
||||||
DEFAULT_DB_CONFIG_PATH = 'install/default_db_config.yaml'
|
DEFAULT_DB_CONFIG_PATH = 'install/default_db_config.yaml'
|
||||||
|
DEFAULT_CONFIG_PATH = 'install/default_config.yaml'
|
||||||
|
|
27
install/default_config.yaml
Normal file
27
install/default_config.yaml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
player_base_rating: 1500
|
||||||
|
variant_base_rating: 1500
|
||||||
|
variant_base_ratings:
|
||||||
|
No Variant:
|
||||||
|
3p: 1500
|
||||||
|
4p: 1500
|
||||||
|
5p: 1500
|
||||||
|
6 Suits:
|
||||||
|
3p: 1500
|
||||||
|
4p: 1500
|
||||||
|
5p: 1500
|
||||||
|
Clue Starved:
|
||||||
|
3p: 1500
|
||||||
|
4p: 1500
|
||||||
|
6p: 1700
|
||||||
|
Clue Starved (6 Suits):
|
||||||
|
3p: 1500
|
||||||
|
4p: 1500
|
||||||
|
6p: 1700
|
||||||
|
min_player_count: 3
|
||||||
|
max_player_count: 5
|
||||||
|
min_suits: 5
|
||||||
|
max_suits: 6
|
||||||
|
starting_game_id: 1000000
|
||||||
|
ending_game_id: 9999999
|
||||||
|
starting_time: "2023-10-10 00:00:00 EST"
|
||||||
|
ending_time: "2023-12-10 00:00:00 EST"
|
1
main.py
1
main.py
|
@ -32,6 +32,7 @@ def subcommand_init(force: bool):
|
||||||
|
|
||||||
def subcommand_generate_config():
|
def subcommand_generate_config():
|
||||||
config.create_db_config()
|
config.create_db_config()
|
||||||
|
config.create_config()
|
||||||
|
|
||||||
|
|
||||||
def get_parser() -> argparse.ArgumentParser:
|
def get_parser() -> argparse.ArgumentParser:
|
||||||
|
|
|
@ -2,3 +2,4 @@ psycopg2
|
||||||
platformdirs
|
platformdirs
|
||||||
PyYAML
|
PyYAML
|
||||||
verboselogs
|
verboselogs
|
||||||
|
python-dateutil
|
||||||
|
|
Loading…
Reference in a new issue