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
|
||||
from typing import Dict
|
||||
|
||||
import yaml
|
||||
import platformdirs
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
import dateutil.parser
|
||||
|
||||
import constants
|
||||
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))
|
||||
else:
|
||||
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.
|
||||
|
||||
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_USER = 'hanabi-league'
|
||||
|
@ -27,3 +28,4 @@ DB_TABLE_NAMES = [
|
|||
|
||||
DATABASE_SCHEMA_PATH = 'install/database_schema.sql'
|
||||
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():
|
||||
config.create_db_config()
|
||||
config.create_config()
|
||||
|
||||
|
||||
def get_parser() -> argparse.ArgumentParser:
|
||||
|
|
|
@ -2,3 +2,4 @@ psycopg2
|
|||
platformdirs
|
||||
PyYAML
|
||||
verboselogs
|
||||
python-dateutil
|
||||
|
|
Loading…
Reference in a new issue