Skip to content

Commit

Permalink
Merge pull request #21 from martgra/dev
Browse files Browse the repository at this point in the history
ver 1.0.0
  • Loading branch information
martgra authored Oct 15, 2020
2 parents bc3024e + 749bb52 commit 9e5d02a
Show file tree
Hide file tree
Showing 12 changed files with 16,099 additions and 42 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/codeconv.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
codecov:
require_ci_to_pass: yes

coverage:
precision: 2
round: down
range: "70...100"

parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no

comment:
layout: "reach,diff,flags,tree"
behavior: default
require_changes: no
ignore:
- "tests"
4 changes: 2 additions & 2 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ jobs:
# This path is specific to Ubuntu
path: ~/.cache/pip
# Look to see if there is a cache hit for the corresponding requirements file
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
key: ${{ runner.os }}-pip-${{ hashFiles('requirements_dev.txt') }}
restore-keys: |
${{ runner.os }}-pip-
${{ runner.os }}-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest pylint pytest-cov
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f requirements.txt ]; then pip install -r requirements_dev.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
Expand Down
45 changes: 25 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ https://towardsdatascience.com/fantasy-premier-league-value-analysis-python-tuto
The repo is based in python3 and jupyter with jupytext for agile version control.

#### **Install package**

```bash
git clone https://github.com/martgra/fpl2021.git
cd fpl2021
Expand All @@ -18,47 +19,51 @@ pip install -r requirements
pip install -e .
touch .env
```
Add the following to the created ```.env``` file

Add the following to the created `.env` file

```bash
# .env
AZURE_STORAGE_CONNECTION_STRING="https://martinfplstats1337.blob.core.windows.net/fplstats"
```

### Dataset
The dataset from Fantasy Premier League is accessed by folling this link.

The dataset from Fantasy Premier League is accessed by folling this link.
https://fantasy.premierleague.com/api/bootstrap-static/

As of now the dataset is downloaded every 6th hour (UTC) and stored as as Azure blob "snapshot" with the format

```
%Y-%m-%dT%H:%M:%SZ_data.json
```

For now access to the blob demands a "connection string" that can be required by the repo owner. Used together with the azure_storage.py module.
Access to the dataset is provided with "read only" access through:

```python
# Download all new data from Azure Blob Storage to disk
$ fantasy download-all -d <PATH_TO_DIR_TO_STORE_DATA>
# Remember to add connection string to .env file or provide it with the -c flag
$ fantasy storage download-all -d <PATH_TO_DIR_TO_STORE_DATA>
```


API - Other useful methods

* Fixtures: https://fantasy.premierleague.com/api/fixtures/
* A single teams hostory: https://fantasy.premierleague.com/api/entry/{}/history/
* A single teams score: https://fantasy.premierleague.com/api/entry/{team-id}/
* Score in a specific "classic"-league: https://fantasy.premierleague.com/api/leagues-classic/{league-id}/standings/
* Score in a specific "H2H"-league: https://fantasy.premierleague.com/api/leagues-h2h/{league-id}/standings/
* Latest transfers: https://fantasy.premierleague.com/api/entry/{team-id}/transfers-latest/
* My Team https://fantasy.premierleague.com/api/my-team/{team-id}/ *
- Fixtures: https://fantasy.premierleague.com/api/fixtures/
- A single teams hostory: https://fantasy.premierleague.com/api/entry/{}/history/
- A single teams score: https://fantasy.premierleague.com/api/entry/{team-id}/
- Score in a specific "classic"-league: https://fantasy.premierleague.com/api/leagues-classic/{league-id}/standings/
- Score in a specific "H2H"-league: https://fantasy.premierleague.com/api/leagues-h2h/{league-id}/standings/
- Latest transfers: https://fantasy.premierleague.com/api/entry/{team-id}/transfers-latest/
- My Team https://fantasy.premierleague.com/api/my-team/{team-id}/ \*

*To use the "my team api" authentication is required. See following link
\*To use the "my team api" authentication is required. See following link
https://medium.com/@bram.vanherle1/fantasy-premier-league-api-authentication-guide-2f7aeb2382e4)

### Other useful links

* Reddit-thread about FPL API
https://www.reddit.com/r/FantasyPL/comments/c64rrx/fpl_api_url_has_been_changed/
* Blogpost about FPL API (its a little old, but change drf with api and it seems to work)
https://medium.com/@YourMumSaysWhat/how-to-get-data-from-the-fantasy-premier-league-api-4477d6a334c3
* Historic data for the FPL
https://github.com/vaastav/Fantasy-Premier-League

- Reddit-thread about FPL API
https://www.reddit.com/r/FantasyPL/comments/c64rrx/fpl_api_url_has_been_changed/
- Blogpost about FPL API (its a little old, but change drf with api and it seems to work)
https://medium.com/@YourMumSaysWhat/how-to-get-data-from-the-fantasy-premier-league-api-4477d6a334c3
- Historic data for the FPL
https://github.com/vaastav/Fantasy-Premier-League
28 changes: 21 additions & 7 deletions fpl/command_line/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,29 @@


@click.group(help="Procedures to interact with Azure Cosmos DB", name="cosmos")
@click.option("--uri", "-u", type=str, default=None)
@click.option("--token", "-t", type=str, default=None)
@click.pass_context
def cosmos_cli(ctx):
def cosmos_cli(ctx, uri, token):
"""Download group."""
db_client = ElementsInserter(
os.getenv("AZURE_COSMOS_URI"),
os.getenv("AZURE_COSMOS_TOKEN"),
{"database": "fplstats", "container": "elements", "partition_key": "download_time"},
)
ctx.obj = db_client
common = {"database": "fplstats", "container": "elements", "partition_key": "download_time"}
try:
if uri and token:
db_client = ElementsInserter(
uri,
token,
common,
)
else:
db_client = ElementsInserter(
os.getenv("AZURE_COSMOS_URI"),
os.getenv("AZURE_COSMOS_TOKEN"),
common,
)
ctx.obj = db_client
except TypeError:
ctx.obj = None
print("ERROR IN CREDENTIALS")


@cosmos_cli.command(name="dump")
Expand Down
13 changes: 10 additions & 3 deletions fpl/command_line/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@


@click.group(help="Procedures to download data from Azure Blob Storage")
@click.option("--connection-string", "-c", type=str, default=None)
@click.pass_context
def storage(ctx):
def storage(ctx, connection_string):
"""Download group."""
storage_client = AzureStorage(os.getenv("AZURE_STORAGE_CONNECTION_STRING"), "fplstats")
ctx.obj = storage_client
try:
if connection_string:
storage_client = AzureStorage(connection_string, "fplstats")
else:
storage_client = AzureStorage(os.getenv("AZURE_STORAGE_CONNECTION_STRING"), "fplstats")
ctx.obj = storage_client
except TypeError:
print("ERROR IN CONNECTION STRING")


@storage.command(name="download-all", help="Download multiple blobs to local storage")
Expand Down
96 changes: 95 additions & 1 deletion fpl/data/transformations.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Common transformation."""
import hashlib

import requests


def get_game_week(events: list) -> int:
"""Get the gameweek from a events list.
Expand All @@ -11,7 +13,10 @@ def get_game_week(events: list) -> int:
Returns:
int: Current gameweek
"""
return list(filter(lambda x: x["is_current"] is True, events))[0]["id"]
gw = list(filter(lambda x: x["is_current"] is True, events))
if gw:
return gw[0]["id"]
return 0


def create_id(element: dict) -> str:
Expand Down Expand Up @@ -48,3 +53,92 @@ def add_unique_id(elements: list):
"""
list(map(lambda x: x.update({"player_id": x.pop("id")}), elements))
list(map(lambda x: x.update({"id": create_id(x)}), elements))


def create_opponents(
teams_data: list, fixtures_uri="https://fantasy.premierleague.com/api/fixtures/", sort=False
) -> dict:
"""Return the fixtures list for each PL team.
Args:
teams_data (list): List holding teams data loaded from /api/boostrap-static dump
fixtures_uri (str, optional): Path the FPL fixtures list.
Defaults to "https://fantasy.premierleague.com/api/fixtures/".
sort (boolean, optional): Sort opponents on gameweek. Defaults to False.
Returns:
dict: {team_name: [{team: str, difficulty: int, venue: str}]}
"""
url = fixtures_uri
fpl_json = requests.get(url).json()
name_mapping = {i["id"]: i["name"] for i in teams_data}
teams = set([i["team_a"] for i in fpl_json])
all_teams = {}
for y in teams:
opponents = []
for i in fpl_json:
if i["team_h"] == y:
opponents.append(
{
"team": name_mapping[i["team_a"]],
"difficulty": i["team_h_difficulty"],
"venue": "h",
"gameweek": i["event"],
}
)
if i["team_a"] == y:
opponents.append(
{
"team": name_mapping[i["team_h"]],
"difficulty": i["team_a_difficulty"],
"venue": "a",
"gameweek": i["event"],
}
)

if sort:
all_teams[name_mapping[y]] = sorted(
opponents, key=lambda i: i["gameweek"] if i["gameweek"] else 99999
)
else:
all_teams[name_mapping[y]] = opponents

return all_teams


def get_team_opponents(all_teams: list, team_name: str, from_gameweek=1, number_fixtures=37):
"""Return fixtures data for a specific team.
Args:
all_teams (list): All teams fixtures list.
team_name (str): The name of team to return fixtures on
from_gameweek (int, optional): Fixtures from gameweek. Defaults to 1.
number_fixtures (int, optional): Number of fixtures to return. Defaults to 37.
Example:
all_teams = create_opponents(
data["teams"], fixtures_uri="https://fantasy.premierleague.com/api/fixtures/")
fixtures = get_team_opponents(all_teams, "Man City", 1, 5)
Returns:
dict: {
"opponents": list,
"in_gameweeks": dict,
"postponed": boolen,
"has_double_gw": boolean,
}
"""
team_fixtures = all_teams[team_name][from_gameweek - 1 : from_gameweek - 1 + number_fixtures]
if from_gameweek + number_fixtures > 1 + len(all_teams[team_name]):
number_fixtures = len(all_teams[team_name]) + 1 - from_gameweek

gameweeks = [i["gameweek"] for i in team_fixtures]
gameweeks = {
i: gameweeks.count(i) for i in range(from_gameweek, from_gameweek + number_fixtures, 1)
}
return {
"opponents": team_fixtures,
"in_gameweeks": gameweeks,
"postponed": bool([i for i in gameweeks if gameweeks[i] < 1]),
"has_double_gw": bool([i for i in gameweeks if gameweeks[i] > 1]),
}
56 changes: 56 additions & 0 deletions notebooks/Untitled.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
jupyter:
jupytext:
text_representation:
extension: .Rmd
format_name: rmarkdown
format_version: '1.2'
jupytext_version: 1.6.0
kernelspec:
display_name: Python 3
language: python
name: python3
---

```{python}
# Nødvendige importer og setup for å komme i gang.
import requests
import pandas as pd
import numpy as np
import json
import os
from datetime import datetime
from IPython.display import display
pd.set_option('display.max_columns', 100)
```

```{python}
url = "https://fantasy.premierleague.com/api/fixtures/"
fpl_json = requests.get(url).json()
fpl_json
```

```{python}
teams = set([i["team_a"] for i in fpl_json])
print(teams)
all = []
for y in teams:
opponent = []
for i in fpl_json:
if i["team_h"] == y:
opponent.append({"team": i["team_a"], "difficulty": i["team_a_difficulty"], "venue": "a"} )
if i["team_a"] == y:
opponent.append({"team": i["team_h"], "difficulty": i["team_h_difficulty"], "venue": "h"})
all.append(opponent)
print(all)
```

```{python}
```
3 changes: 2 additions & 1 deletion requirements_dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ black
pylint
flake8
pytest
pydocstyle
pydocstyle
requests-mock
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ testpaths = tests

[coverage:run]
branch = True
source =fpl
source = fpl

[flake8]
max-line-length = 100
Expand Down
Loading

0 comments on commit 9e5d02a

Please sign in to comment.