feat: make config_section a global CLI option
Users can now specify --config-section once at the beginning of the command instead of repeating it for each subcommand. Also bumped version to v0.5.0 for this new feature.
This commit is contained in:
127
myice/myice.py
127
myice/myice.py
@@ -92,6 +92,23 @@ def sanitize_json_response(text):
|
||||
app = typer.Typer(no_args_is_help=True)
|
||||
session: requests.Session
|
||||
userid: int
|
||||
global_config_section: str = "default"
|
||||
|
||||
|
||||
# Add global option for config section
|
||||
@app.callback()
|
||||
def main(
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
"""My Ice Hockey schedule tool"""
|
||||
# Store the config_section in a global variable so it can be accessed by commands
|
||||
global global_config_section
|
||||
global_config_section = config_section
|
||||
|
||||
|
||||
class AgeGroup(str, Enum):
|
||||
@@ -210,12 +227,15 @@ def select_club(club_id: int = 172):
|
||||
r.raise_for_status()
|
||||
|
||||
|
||||
def do_login(config_section: str = "default"):
|
||||
def do_login(config_section: str | None = None):
|
||||
global session
|
||||
global userid
|
||||
username, password, userid_tmp, token, club_id = get_login(
|
||||
config_section=config_section
|
||||
)
|
||||
global global_config_section
|
||||
|
||||
# Use provided config_section, or fall back to global one
|
||||
section = config_section if config_section is not None else global_config_section
|
||||
|
||||
username, password, userid_tmp, token, club_id = get_login(config_section=section)
|
||||
if userid_tmp is not None:
|
||||
userid = userid_tmp
|
||||
r = session.get("https://app.myice.hockey/", headers={"User-Agent": user_agent})
|
||||
@@ -261,9 +281,9 @@ def get_userid():
|
||||
|
||||
def wrapper_session(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
global session, userid
|
||||
# Extract config_section from kwargs if present
|
||||
config_section = kwargs.get("config_section", "default")
|
||||
global session, userid, global_config_section
|
||||
# Use the global config_section
|
||||
config_section = global_config_section
|
||||
|
||||
session = requests.Session()
|
||||
# session.verify = False
|
||||
@@ -271,7 +291,7 @@ def wrapper_session(func):
|
||||
session.cookies.clear_expired_cookies()
|
||||
if not session.cookies.get("mih_v3_cookname"):
|
||||
print("login...", file=sys.stderr)
|
||||
do_login(config_section=config_section)
|
||||
do_login(config_section=None) # Use global config_section
|
||||
save_cookies()
|
||||
_, _, userid, _, _ = get_login(config_section=config_section)
|
||||
if not userid:
|
||||
@@ -284,7 +304,7 @@ def wrapper_session(func):
|
||||
|
||||
|
||||
@wrapper_session
|
||||
def get_schedule(num_days: int, config_section: str = "default") -> str:
|
||||
def get_schedule(num_days: int) -> str:
|
||||
global session
|
||||
global userid
|
||||
assert session and userid
|
||||
@@ -315,7 +335,7 @@ def get_schedule(num_days: int, config_section: str = "default") -> str:
|
||||
|
||||
|
||||
@wrapper_session
|
||||
def game_pdf(gameid: int, outfile: Path, config_section: str = "default"):
|
||||
def game_pdf(gameid: int, outfile: Path):
|
||||
global session, userid
|
||||
assert session and userid
|
||||
r = session.get(
|
||||
@@ -332,7 +352,7 @@ def game_pdf(gameid: int, outfile: Path, config_section: str = "default"):
|
||||
|
||||
|
||||
@wrapper_session
|
||||
def practice_pdf(gameid: int, outfile: Path, config_section: str = "default"):
|
||||
def practice_pdf(gameid: int, outfile: Path):
|
||||
global session, userid
|
||||
assert session and userid
|
||||
r = session.get(
|
||||
@@ -357,17 +377,12 @@ def schedule(
|
||||
),
|
||||
] = None,
|
||||
num_days: Annotated[int, typer.Option("--days")] = 7,
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
"""
|
||||
Fetch schedule as json
|
||||
"""
|
||||
schedule = get_schedule(num_days, config_section=config_section)
|
||||
global global_config_section
|
||||
schedule = get_schedule(num_days)
|
||||
# Sanitize the JSON response using our proven approach
|
||||
sanitized_schedule = sanitize_json_response(schedule)
|
||||
if outfile:
|
||||
@@ -406,21 +421,16 @@ def extract_players(pdf_file: Path) -> List[str]:
|
||||
def get_game_pdf(
|
||||
game_id: Annotated[int, typer.Argument(help="ID of game to gen pdf for")],
|
||||
open_file: Annotated[bool, typer.Option("--open", "-o")] = False,
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
"""
|
||||
Genate the pdf for the game invitation
|
||||
"""
|
||||
global global_config_section
|
||||
if open_file:
|
||||
output_filename = f"game_{game_id}.pdf"
|
||||
else:
|
||||
output_filename = tempfile.NamedTemporaryFile().name
|
||||
game_pdf(game_id, Path(output_filename), config_section=config_section)
|
||||
game_pdf(game_id, Path(output_filename))
|
||||
if open_file:
|
||||
os_open(output_filename)
|
||||
else:
|
||||
@@ -432,18 +442,13 @@ def get_game_pdf(
|
||||
@app.command("practice")
|
||||
def get_practice_pdf(
|
||||
game_id: Annotated[int, typer.Argument(help="ID of practice to gen pdf for")],
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
"""
|
||||
Genate the pdf for the practice invitation
|
||||
"""
|
||||
global global_config_section
|
||||
output_filename = f"practice_{game_id}.pdf"
|
||||
practice_pdf(game_id, Path(output_filename), config_section=config_section)
|
||||
practice_pdf(game_id, Path(output_filename))
|
||||
os_open(output_filename)
|
||||
|
||||
|
||||
@@ -457,16 +462,11 @@ def parse_schedule(
|
||||
schedule_file: Annotated[
|
||||
Path, typer.Option(help="schedule json file to parse")
|
||||
] = Path("schedule.json"),
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
"""
|
||||
Parse schedule.json to look for specific games or practices
|
||||
"""
|
||||
global global_config_section
|
||||
try:
|
||||
with schedule_file.open("r") as f:
|
||||
data = json.load(f)
|
||||
@@ -512,16 +512,11 @@ def check_with_ai(
|
||||
schedule_file: Annotated[
|
||||
Path, typer.Option(help="schedule json file to parse")
|
||||
] = Path("schedule.json"),
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
"""
|
||||
Search through the schedule with natural language using Infomaniak LLM API
|
||||
"""
|
||||
global global_config_section
|
||||
if not utils.init():
|
||||
sys.exit(1)
|
||||
with schedule_file.open("r") as f:
|
||||
@@ -570,10 +565,14 @@ mobile_headers = {
|
||||
}
|
||||
|
||||
|
||||
def mobile_login(config_section: str = "default"):
|
||||
def mobile_login(config_section: str | None = None):
|
||||
global global_config_section
|
||||
import base64
|
||||
|
||||
username, password, _, token, club_id = get_login(config_section=config_section)
|
||||
# Use provided config_section, or fall back to global one
|
||||
section = config_section if config_section is not None else global_config_section
|
||||
|
||||
username, password, _, token, club_id = get_login(config_section=section)
|
||||
if token and club_id:
|
||||
return {"id": 0, "token": token, "id_club": club_id}
|
||||
|
||||
@@ -612,30 +611,16 @@ def refresh_data():
|
||||
|
||||
|
||||
@app.command("mobile-login")
|
||||
def do_mobile_login(
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
global userdata
|
||||
userdata = mobile_login(config_section=config_section)
|
||||
def do_mobile_login():
|
||||
global userdata, global_config_section
|
||||
userdata = mobile_login(config_section=global_config_section)
|
||||
print(json.dumps(userdata, indent=2))
|
||||
|
||||
|
||||
@app.command("mobile")
|
||||
def mobile(
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
global userdata
|
||||
userdata = mobile_login(config_section=config_section)
|
||||
def mobile():
|
||||
global userdata, global_config_section
|
||||
userdata = mobile_login(config_section=global_config_section)
|
||||
games = [x for x in refresh_data().get("club_games")]
|
||||
print(json.dumps(games, indent=2))
|
||||
|
||||
@@ -644,15 +629,9 @@ def mobile(
|
||||
def mobile_game(
|
||||
game_id: Annotated[int, typer.Argument(help="game id")],
|
||||
raw: Annotated[bool, typer.Option(help="display raw output")] = False,
|
||||
config_section: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--config-section", "-c", help="Configuration section to use from INI file"
|
||||
),
|
||||
] = "default",
|
||||
):
|
||||
global userdata
|
||||
userdata = mobile_login(config_section=config_section)
|
||||
global userdata, global_config_section
|
||||
userdata = mobile_login(config_section=global_config_section)
|
||||
|
||||
# data = refresh_data()
|
||||
with requests.post(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "myice"
|
||||
version = "v0.4.3"
|
||||
version = "v0.5.0"
|
||||
description = "myice parsing"
|
||||
authors = [
|
||||
{ name = "Rene Luria", "email" = "<rene@luria.ch>"},
|
||||
|
||||
Reference in New Issue
Block a user