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