Skip to content

Commit 90916df

Browse files
authored
New typer based cli (#9)
1 parent f4db09a commit 90916df

File tree

11 files changed

+655
-549
lines changed

11 files changed

+655
-549
lines changed

lazyfpl/__main__.py

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,8 @@
1-
def help_message() -> None:
2-
print(
3-
"""
4-
LazyFPL - Fantasy Premier League Team Optimizer - Win at FPL with Laziness
1+
def main() -> None:
2+
from lazyfpl import cli
53

6-
- Constraints Module
7-
Contains functions to check various constraints like team composition
8-
and budget limits.
9-
10-
- Database Module
11-
Manages interactions with the database, including queries and data storage.
12-
13-
- Fetch Module
14-
Retrieves various types of data related to players, teams, and games.
15-
16-
- Helpers Module
17-
Provides utility functions for calculations and data manipulations.
18-
19-
- Populator Module
20-
Responsible for populating the database with current and historical FPL data.
21-
22-
- Structures Module
23-
Defines data structures and models for representing players, teams, and games.
24-
25-
- Transfer Modulee
26-
Assists in making transfer decisions based on various strategies
27-
and constraints.
28-
29-
- Differentials Module
30-
Offers analytics to identify potential differential picks in
31-
your fantasy football team.
32-
33-
Usage:
34-
Each module is designed to be used as a standalone tool or in conjunction
35-
with others to enhance your Fantasy Premier League strategy. Use the respective
36-
module's functions to fetch data, analyze team compositions, make
37-
transfers, and more.
38-
39-
For more detailed information on each module, refer to their individual
40-
documentation or use help(module_name).
41-
"""
42-
)
4+
cli.app()
435

446

457
if __name__ == "__main__":
46-
help_message()
8+
main()

lazyfpl/cli.py

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
import typer
2+
3+
app = typer.Typer(
4+
help="Tool for managing LazyFPL.",
5+
no_args_is_help=True,
6+
)
7+
8+
9+
@app.command()
10+
def populate() -> None:
11+
"""Populate the database with team data."""
12+
from lazyfpl import populator
13+
14+
populator.main()
15+
16+
17+
@app.command()
18+
def train(
19+
epochs: int = typer.Option(
20+
5,
21+
help="Number of training epochs.",
22+
),
23+
lr: float = typer.Option(
24+
0.01,
25+
help="Learning rate for the optimizer.",
26+
),
27+
min_mtm: int = typer.Option(
28+
0,
29+
help="Minimum mean time metric for filtering players.",
30+
),
31+
upsample: int = typer.Option(
32+
16,
33+
help="Factor for upsampling the training data.",
34+
),
35+
batch_size: int = typer.Option(
36+
16,
37+
help="Batch size for training.",
38+
),
39+
no_news: bool = typer.Option(
40+
False,
41+
help="Exclude players with news attached to them.",
42+
),
43+
) -> None:
44+
"""Train the ML model on the populated data."""
45+
from lazyfpl import ml_model
46+
47+
ml_model.main(
48+
epochs=epochs,
49+
lr=lr,
50+
min_mtm=min_mtm,
51+
upsample=upsample,
52+
batch_size=batch_size,
53+
no_news=no_news,
54+
)
55+
56+
57+
@app.command()
58+
def show(
59+
top: int = typer.Option(
60+
None,
61+
help="Top N players per position.",
62+
),
63+
no_news: bool = typer.Option(
64+
False,
65+
help="Drop players with news attached to them.",
66+
),
67+
) -> None:
68+
"""Show player database"""
69+
from lazyfpl import show
70+
71+
show.main(top, no_news)
72+
73+
74+
@app.command()
75+
def transfer(
76+
add: list[str] = typer.Option(
77+
[],
78+
help="Players to add.",
79+
),
80+
exclude: list[str] = typer.Option(
81+
[],
82+
help="Players to exclude.",
83+
),
84+
max_transfers: int = typer.Option(
85+
...,
86+
help="Maximum number of transfers allowed.",
87+
),
88+
min_mtm: float = typer.Option(
89+
0.0,
90+
help="Minimum mean time metric.",
91+
),
92+
min_xp: float = typer.Option(
93+
0.0,
94+
help="Minimum expected points.",
95+
),
96+
no_news: bool = typer.Option(
97+
False,
98+
help="Exclude players with news attached to them.",
99+
),
100+
remove: list[str] = typer.Option(
101+
[],
102+
help="Players to remove.",
103+
),
104+
) -> None:
105+
"""Pick transfer options based on specified constraints."""
106+
from lazyfpl import transfer
107+
108+
transfer.main(
109+
add,
110+
exclude,
111+
max_transfers,
112+
min_mtm,
113+
min_xp,
114+
no_news,
115+
remove,
116+
)
117+
118+
119+
@app.command(name="lineup")
120+
def lineup_optimizer(
121+
budget_lower: int = typer.Option(
122+
900,
123+
help="Lower budget limit.",
124+
),
125+
budget_upper: int = typer.Option(
126+
1000,
127+
help="Upper budget limit.",
128+
),
129+
gkp_def_not_same_team: bool = typer.Option(
130+
False,
131+
help="Goalkeeper and defenders should not be from the same team.",
132+
),
133+
include: list[str] = typer.Option(
134+
[],
135+
help="Players to include in the lineup.",
136+
),
137+
keep_squad: int = typer.Option(
138+
1000,
139+
help="Number of lineups to keep.",
140+
),
141+
max_def_per_team: int = typer.Option(
142+
3,
143+
help="Maximum number of defenders per team.",
144+
),
145+
max_players_per_team: int = typer.Option(
146+
3,
147+
help="Maximum number of players per team.",
148+
),
149+
min_mtm: float = typer.Option(
150+
0.0,
151+
help="Minimum mean time metric.",
152+
),
153+
min_xp: float = typer.Option(
154+
0.0,
155+
help="Minimum expected points.",
156+
),
157+
no_news: bool = typer.Option(
158+
False,
159+
help="Exclude players with news attached to them.",
160+
),
161+
remove: list[str] = typer.Option(
162+
[],
163+
help="Players to remove from consideration.",
164+
),
165+
top_position_price: int = typer.Option(
166+
0,
167+
help="Top players per position by price.",
168+
),
169+
) -> None:
170+
"""Optimize the best possible lineup within given constraints."""
171+
from lazyfpl import optimizer
172+
173+
optimizer.main(
174+
budget_lower,
175+
budget_upper,
176+
gkp_def_not_same_team,
177+
include,
178+
keep_squad,
179+
max_def_per_team,
180+
max_players_per_team,
181+
min_mtm,
182+
min_xp,
183+
no_news,
184+
remove,
185+
top_position_price,
186+
)
187+
188+
189+
@app.command()
190+
def differential(
191+
min_mtm: float = typer.Option(
192+
0.0,
193+
help="Minimum mean time metric.",
194+
),
195+
min_selected: int = typer.Option(
196+
1000,
197+
"-mc",
198+
help="Player must be selected by at least this amount of managers.",
199+
),
200+
min_xp: float = typer.Option(
201+
0.0,
202+
help="Minimum expected points.",
203+
),
204+
no_news: bool = typer.Option(
205+
False,
206+
help="Exclude players with news attached to them.",
207+
),
208+
top: int = typer.Option(
209+
None,
210+
"-t",
211+
help="Top N players per position.",
212+
),
213+
) -> None:
214+
"""Show differentials based on specified criteria."""
215+
from lazyfpl import differentials
216+
217+
differentials.main(
218+
min_mtm,
219+
min_selected,
220+
min_xp,
221+
no_news,
222+
top,
223+
)
224+
225+
226+
if __name__ == "__main__":
227+
app()

lazyfpl/differentials.py

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,27 @@
11
from __future__ import annotations
22

3-
import argparse
43
from itertools import chain, groupby
54

65
from lazyfpl import fetch, helpers
76

8-
if __name__ == "__main__":
9-
parser = argparse.ArgumentParser()
10-
parser.add_argument(
11-
"--min-mtm",
12-
type=float,
13-
default=0.0,
14-
help="(default: %(default)s)",
15-
)
16-
parser.add_argument(
17-
"--min-selected",
18-
"-mc",
19-
default=1_000,
20-
help=(
21-
"Player must be selected by at least this amunt of"
22-
"managers. (default: %(default)s)"
23-
),
24-
type=int,
25-
)
26-
parser.add_argument(
27-
"--min-xp",
28-
type=float,
29-
default=0.0,
30-
help="(default: %(default)s)",
31-
)
32-
parser.add_argument(
33-
"--no-news",
34-
action="store_true",
35-
help="Drop players with news attched to them. (default: %(default)s)",
36-
)
37-
parser.add_argument(
38-
"--top",
39-
"-t",
40-
default=None,
41-
help="Top N players per position. (default: %(default)s)",
42-
type=int,
43-
)
44-
args = parser.parse_args()
457

8+
def main(
9+
min_mtm: float,
10+
min_selected: int,
11+
min_xp: float,
12+
no_news: bool,
13+
top: int,
14+
) -> None:
4615
pool = fetch.players()
4716

48-
if args.no_news:
17+
if no_news:
4918
pool = [p for p in pool if not p.news]
5019

5120
pool = sorted(
5221
[
5322
p
5423
for p in pool
55-
if p.selected > args.min_selected
56-
and (p.xP or 0) > args.min_xp
57-
and p.mtm() > args.min_mtm
24+
if p.selected > min_selected and (p.xP or 0) > min_xp and p.mtm() > min_mtm
5825
],
5926
key=lambda x: (
6027
-helpers.position_order(x.position),
@@ -64,7 +31,7 @@
6431

6532
pool = list(
6633
chain.from_iterable(
67-
list(x)[: args.top]
34+
list(x)[:top]
6835
for _, x in groupby(
6936
pool,
7037
key=lambda x: helpers.position_order(x.position),

0 commit comments

Comments
 (0)