Compare commits
5 Commits
main
...
c4d9236b16
| Author | SHA1 | Date | |
|---|---|---|---|
|
c4d9236b16
|
|||
|
2a5883375f
|
|||
|
c4b6e39e9e
|
|||
|
d3b5b6b6fd
|
|||
|
bcde9fccf5
|
@@ -3,7 +3,7 @@
|
||||
---
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.2.0
|
||||
rev: v6.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: check-case-conflict
|
||||
@@ -15,7 +15,7 @@ repos:
|
||||
- id: detect-private-key
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.6.8
|
||||
rev: v0.12.9
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
@@ -24,26 +24,26 @@ repos:
|
||||
- id: ruff-format
|
||||
args: [--diff, --target-version, py312]
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.11.2
|
||||
rev: v1.17.1
|
||||
hooks:
|
||||
- id: mypy
|
||||
exclude: ^(docs/|example-plugin/)
|
||||
args: [--ignore-missing-imports]
|
||||
additional_dependencies: [types-requests, PyPDF2]
|
||||
- repo: https://github.com/adrienverge/yamllint.git
|
||||
rev: v1.35.1
|
||||
rev: v1.37.1
|
||||
hooks:
|
||||
- id: yamllint
|
||||
args: [--strict]
|
||||
|
||||
- repo: https://github.com/markdownlint/markdownlint
|
||||
rev: v0.12.0
|
||||
rev: v0.13.0
|
||||
hooks:
|
||||
- id: markdownlint
|
||||
exclude: "^.github|(^docs/_sidebar\\.md$)"
|
||||
|
||||
- repo: https://github.com/shellcheck-py/shellcheck-py
|
||||
rev: v0.10.0.1
|
||||
rev: v0.11.0.1
|
||||
hooks:
|
||||
- id: shellcheck
|
||||
args: ["--severity=error"]
|
||||
@@ -51,12 +51,12 @@ repos:
|
||||
files: "\\.sh$"
|
||||
|
||||
- repo: https://github.com/golangci/misspell
|
||||
rev: v0.6.0
|
||||
rev: v0.7.0
|
||||
hooks:
|
||||
- id: misspell
|
||||
args: ["-i", "charactor"]
|
||||
- repo: https://github.com/python-poetry/poetry
|
||||
rev: "2.0.0"
|
||||
rev: "2.1.4"
|
||||
hooks:
|
||||
- id: poetry-check
|
||||
- id: poetry-lock
|
||||
|
||||
+55
-75
@@ -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,19 +291,20 @@ 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:
|
||||
print("get userid...", file=sys.stderr)
|
||||
userid = get_userid()
|
||||
print(f"{userid=}", file=sys.stderr)
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
@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
|
||||
@@ -314,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(
|
||||
@@ -331,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(
|
||||
@@ -356,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:
|
||||
@@ -405,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:
|
||||
@@ -431,24 +442,19 @@ 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)
|
||||
|
||||
|
||||
@app.command("search")
|
||||
def parse_schedule(
|
||||
age_group: Annotated[AgeGroup | None, typer.Option(...)] = None,
|
||||
age_group: Annotated[AgeGroup | None, typer.Option()] = None,
|
||||
event_type_filter: Annotated[
|
||||
EventType | None,
|
||||
typer.Option("--type", help="Only display events of this type"),
|
||||
@@ -456,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)
|
||||
@@ -511,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:
|
||||
@@ -569,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}
|
||||
|
||||
@@ -611,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))
|
||||
|
||||
@@ -643,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(
|
||||
|
||||
Generated
+11
-11
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
@@ -31,7 +31,7 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
|
||||
|
||||
[package.extras]
|
||||
doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"]
|
||||
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"]
|
||||
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""]
|
||||
trio = ["trio (>=0.26.1)"]
|
||||
|
||||
[[package]]
|
||||
@@ -402,7 +402,7 @@ files = [
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
@@ -560,7 +560,7 @@ httpcore = "==1.*"
|
||||
idna = "*"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli", "brotlicffi"]
|
||||
brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""]
|
||||
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
|
||||
http2 = ["h2 (>=3,<5)"]
|
||||
socks = ["socksio (==1.*)"]
|
||||
@@ -642,7 +642,7 @@ typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""}
|
||||
[package.extras]
|
||||
all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"]
|
||||
black = ["black"]
|
||||
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing_extensions"]
|
||||
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"]
|
||||
kernel = ["ipykernel"]
|
||||
matplotlib = ["matplotlib"]
|
||||
nbconvert = ["nbconvert"]
|
||||
@@ -712,7 +712,7 @@ traitlets = ">=5.3"
|
||||
|
||||
[package.extras]
|
||||
docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"]
|
||||
test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"]
|
||||
test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko ; sys_platform == \"win32\"", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"]
|
||||
|
||||
[[package]]
|
||||
name = "jupyter-core"
|
||||
@@ -1102,7 +1102,7 @@ typing-extensions = ">=4.12.2"
|
||||
|
||||
[package.extras]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
timezone = ["tzdata"]
|
||||
timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
@@ -1755,7 +1755,7 @@ files = [
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
||||
brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
|
||||
h2 = ["h2 (>=4,<5)"]
|
||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
@@ -1779,12 +1779,12 @@ h11 = ">=0.8"
|
||||
httptools = {version = ">=0.6.3", optional = true, markers = "extra == \"standard\""}
|
||||
python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
|
||||
pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""}
|
||||
uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
|
||||
uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
|
||||
watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
|
||||
websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""}
|
||||
|
||||
[package.extras]
|
||||
standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"]
|
||||
standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "uvloop"
|
||||
@@ -1793,7 +1793,7 @@ description = "Fast implementation of asyncio event loop on top of libuv"
|
||||
optional = false
|
||||
python-versions = ">=3.8.0"
|
||||
groups = ["main"]
|
||||
markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\""
|
||||
markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\""
|
||||
files = [
|
||||
{file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"},
|
||||
{file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"},
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "myice"
|
||||
version = "v0.3.2"
|
||||
version = "v0.5.0"
|
||||
description = "myice parsing"
|
||||
authors = [
|
||||
{ name = "Rene Luria", "email" = "<rene@luria.ch>"},
|
||||
@@ -35,7 +35,7 @@ priority = "supplemental"
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[projectscripts]
|
||||
[project.scripts]
|
||||
myice = 'myice.myice:app'
|
||||
|
||||
[tool.poetry.requires-plugins]
|
||||
|
||||
Reference in New Issue
Block a user