Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jonolsu committed Jan 30, 2022
0 parents commit 6bd2b5e
Show file tree
Hide file tree
Showing 15 changed files with 661 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
*.env
__pycache__
10 changes: 10 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Release History
===============

0.0.1 (2022-01-29)
------------------

- Soccer: get_elo_season, get_elo_match
- Database: data_query, command_query, write_dataframe, get_engine
- Credentials: set_credentials
- Datasets: list_datasets, load_dataset. copa_rayados.2021.csv dataset
40 changes: 40 additions & 0 deletions KonoPyUtil/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""
KonoPyUtil Library
~~~~~~~~~~~~~~~~~~
KonoPyUtil is a library of convenience fuctions, written in Python, for Kono Analytics and anyone else who wants to use it.
Basic usage:
>>> import KonoPyUtil as kpu
>>> credentials = kpu.set_credentials('.env')
>>> query = "SELECT TOP 10 * FROM [mytable];"
>>> df = kpu.data_query(query)
:license: Apache 2.0, see LICENSE for more details.
"""


from .__version__ import (
__title__,
__description__,
__url__,
__version__,
__author__,
__author_email__,
__license__,
__copyright__,
)

from .dbutils import (
data_query,
command_query,
write_dataframe,
get_engine,
)
from .credentials import (
set_credentials,
)
from .datasets import list_datasets, load_dataset
from .soccer import get_elo_season, get_elo_match
import logging

logging.getLogger(__name__).addHandler(logging.NullHandler())
8 changes: 8 additions & 0 deletions KonoPyUtil/__version__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
__title__ = "KonoPyUtil"
__description__ = "Python Utilities for Kono Analytics"
__url__ = "https://konoanalytics.com"
__version__ = "0.0.1"
__author__ = "Jonathan Bennett"
__author_email__ = "[email protected]"
__license__ = "Apache 2.0"
__copyright__ = "Copyright 2022 Jonathan Bennett"
32 changes: 32 additions & 0 deletions KonoPyUtil/credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os
import json
from environs import Env


def set_credentials(file_and_path_to_credential_file=".env", recurse=False):
"""
Loads credential file into O/S environment if a file_and_path_to_credential_file is not None
overwrites DB_CREDENTIALS O/S environment variable
returns DB_CREDENTIALS as a dictionary
credential_file should be formatted as follows:
DB_CREDENTIALS='{"DBNAME": "postgres", "SCHEMA": "public", "USERID": "useridhere", "PASSWORD": "passwordhere", "HOST": "path_to_database_here", "PORT": "port_here"}'
:param file_and_path_to_dot_env: defaults to .env, uf yi
:param recurse: Boolean = if True recursively search upward for a .env file
:return: dictionary of database credentials if present, or empty dictionary otherwise
"""
if file_and_path_to_credential_file:
# clear existing "DB_CREDENTIALS" environment variable
try:
del os.environ["DB_CREDENTIALS"]
except KeyError:
pass
finally:
env = Env()
file_and_path_formatted = os.path.abspath(file_and_path_to_credential_file)
env.read_env(file_and_path_formatted, recurse=recurse)
if "DB_CREDENTIALS" in os.environ:
return dict(json.loads(os.environ["DB_CREDENTIALS"]))
else:
return {}
60 changes: 60 additions & 0 deletions KonoPyUtil/data/copa_rayados.2021.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
match,game_time,home_name,away_name,home_score,away_score,game_description
527,11/24/2021 11:00,TEXAS TIGRES 09',CHELSEA EAST 09,2,2,
561,11/24/2021 11:00,EP LOCOMOTIVE FC EP LOCOMOT,HOUSTONIANS FC 09B,0,0,
562,11/24/2021 11:00,AZTECAS FUTBOL AZTECAS FC 09B Blue,MSK RAYADOS 09B,1,0,
536,11/24/2021 11:30,BARÇA ACADEMY NASHVILLE BAR,SPORTS GROUP 1 SG1 09B,0,0,
537,11/24/2021 11:30,PRIMOS FC,AVANTI SOCCER ACADEMY 09B,0,1,
546,11/24/2021 12:15,RAPIDS SOUTH 09B ELITE,ALBION HURRICANES AHFC 09B,1,2,
547,11/24/2021 12:15,AVANTI SOCCER ACADEMY 09B WEST,ASPIRE FC 09 YELLOW,4,0,
526,11/24/2021 13:30,CADENCE SFC 2009 ACADEMY,RISE SC RISE U13B ECNL,0,1,
559,11/24/2021 14:45,AZTECAS FUTBOL AZTECAS FC 09B Blue,HOUSTONIANS FC 09B,0,2,
560,11/24/2021 15:15,IMPERIAL SC 09B,ID CHELSEA JR 09B Q,2,3,
525,11/24/2021 16:00,CHELSEA EAST 09,ID REAL HOUSTON 09B Q,0,2,
544,11/24/2021 16:00,AVANTI SOCCER ACADEMY 09B WEST,ALBION HURRICANES AHFC 09B,2,0,
535,11/24/2021 16:30,AVANTI SOCCER ACADEMY 09B,DYNAMO WOODLANDS 09 PA,1,1,
545,11/24/2021 17:15,SOCCER CENTRO 09,DDYSC HOUSTON DYNAMO YOUTH ECNL RL 09,1,1,
528,11/25/2021 08:15,CADENCE SFC 2009 ACADEMY,CHELSEA EAST 09,0,1,
530,11/25/2021 08:15,RISE SC RISE U13B ECNL,ID REAL HOUSTON 09B Q,1,4,
541,11/25/2021 08:15,BARÇA ACADEMY NASHVILLE BAR,PRIMOS FC,0,1,
563,11/25/2021 08:15,EP LOCOMOTIVE FC EP LOCOMOT,ID CHELSEA JR 09B Q,0,2,
564,11/25/2021 09:00,AZTECAS FUTBOL AZTECAS FC 09B Blue,IMPERIAL SC 09B,1,1,
551,11/25/2021 11:30,SOCCER CENTRO 09,RAPIDS SOUTH 09B ELITE,0,3,
566,11/25/2021 11:30,EP LOCOMOTIVE FC EP LOCOMOT,IMPERIAL SC 09B,3,0,
538,11/26/2021 08:00,BARÇA ACADEMY NASHVILLE BAR,AVANTI SOCCER ACADEMY 09B,1,1,
552,11/26/2021 08:00,AVANTI SOCCER ACADEMY 09B WEST,DDYSC HOUSTON DYNAMO YOUTH ECNL RL 09,1,0,
554,11/26/2021 08:00,SOCCER CENTRO 09,ALBION HURRICANES AHFC 09B,0,4,
540,11/26/2021 08:30,DYNAMO WOODLANDS 09 PA,SPORTS GROUP 1 SG1 09B,1,1,
572,11/26/2021 08:30,ID CHELSEA JR 09B Q,MSK RAYADOS 09B,0,1,
531,11/26/2021 09:00,CADENCE SFC 2009 ACADEMY,TEXAS TIGRES 09',1,5,
548,11/26/2021 09:00,RAPIDS SOUTH 09B ELITE,DDYSC HOUSTON DYNAMO YOUTH ECNL RL 09,1,0,
550,11/26/2021 09:00,ALBION HURRICANES AHFC 09B,ASPIRE FC 09 YELLOW,3,0,
568,11/26/2021 09:00,EP LOCOMOTIVE FC EP LOCOMOT,AZTECAS FUTBOL AZTECAS FC 09B Blue,6,0,
539,11/26/2021 09:45,PRIMOS FC,DYNAMO WOODLANDS 09 PA,1,0,
553,11/26/2021 11:00,SOCCER CENTRO 09,ASPIRE FC 09 YELLOW,3,0,
532,11/26/2021 11:10,CHELSEA EAST 09,RISE SC RISE U13B ECNL,0,0,
569,11/26/2021 12:15,IMPERIAL SC 09B,MSK RAYADOS 09B,5,0,
529,11/26/2021 12:20,TEXAS TIGRES 09',ID REAL HOUSTON 09B Q,0,4,
570,11/26/2021 12:30,ID CHELSEA JR 09B Q,HOUSTONIANS FC 09B,4,0,
542,11/26/2021 13:30,AVANTI SOCCER ACADEMY 09B,SPORTS GROUP 1 SG1 09B,0,1,
556,11/26/2021 13:45,RAPIDS SOUTH 09B ELITE,AVANTI SOCCER ACADEMY 09B WEST,0,0,
557,11/26/2021 15:00,DDYSC HOUSTON DYNAMO YOUTH ECNL RL 09,ASPIRE FC 09 YELLOW,2,1,
534,11/26/2021 17:15,PRIMOS FC,SPORTS GROUP 1 SG1 09B,0,1,
533,11/26/2021 17:45,BARÇA ACADEMY NASHVILLE BAR,DYNAMO WOODLANDS 09 PA,1,1,
523,11/26/2021 19:20,CADENCE SFC 2009 ACADEMY,ID REAL HOUSTON 09B Q,0,4,
524,11/26/2021 19:20,TEXAS TIGRES 09',RISE SC RISE U13B ECNL,0,0,
565,11/26/2021 21:45,MSK RAYADOS 09B,HOUSTONIANS FC 09B,0,1,
574,11/27/2021 08:15,SPORTS GROUP 1 SG1 09B,AVANTI SOCCER ACADEMY 09B WEST,0,4,gold semi
580,11/27/2021 08:15,AVANTI SOCCER ACADEMY 09B,RAPIDS SOUTH 09B ELITE,0,4,bronze semi
585,11/27/2021 08:30,CADENCE SFC 2009 ACADEMY,AZTECAS FUTBOL AZTECAS FC 09B Blue,1,5,quartz semi
586,11/27/2021 08:30,DYNAMO WOODLANDS 09 PA,SOCCER CENTRO 09,5,4,quartz semi
573,11/27/2021 10:00,ID REAL HOUSTON 09B Q,ID CHELSEA JR 09B Q,1,2,gold semi
579,11/27/2021 10:00,CHELSEA EAST 09,HOUSTONIANS FC 09B,1,3,bronze semi
582,11/27/2021 10:00,RISE SC RISE U13B ECNL,IMPERIAL SC 09B,1,2,copper semi
583,11/27/2021 10:00,BARÇA ACADEMY NASHVILLE BAR,DDYSC HOUSTON DYNAMO YOUTH ECNL RL 09,2,4,copper semi
576,11/27/2021 11:45,TEXAS TIGRES 09',EP LOCOMOTIVE FC EP LOCOMOT,0,2,silver semi
577,11/27/2021 12:00,PRIMOS FC,ALBION HURRICANES AHFC 09B,0,8,silver semi
581,11/28/2021 13:15,HOUSTONIANS FC 09B,RAPIDS SOUTH 09B ELITE,0,3,bronze final
575,11/28/2021 13:30,ID CHELSEA JR 09B Q,AVANTI SOCCER ACADEMY 09B WEST,0,1,gold final
587,11/28/2021 14:40,AZTECAS FUTBOL AZTECAS FC 09B Blue,DYNAMO WOODLANDS 09 PA,3,1,quartz final
578,11/28/2021 15:15,EP LOCOMOTIVE FC EP LOCOMOT,ALBION HURRICANES AHFC 09B,1,0,silver final
584,11/28/2021 15:15,IMPERIAL SC 09B,DDYSC HOUSTON DYNAMO YOUTH ECNL RL 09,2,0,copper final
25 changes: 25 additions & 0 deletions KonoPyUtil/datasets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os
import pandas as pd


def list_datasets():
"""
List all datasets in KonoPyUtil library
:return: a list of filenames corresponding to datasets
"""
_here = os.path.abspath(os.path.dirname(__file__))
data_directory = os.path.join(_here, "data")
return os.listdir(data_directory)


def load_dataset(dataset):
"""
Loads a specific dataset in KonoPyUtil library
:param dataset: name of dataset (options can be found via list_datasets()
:return: a Pandas dataframe of the requested dataset
"""
_here = os.path.abspath(os.path.dirname(__file__))
file_and_path = os.path.join(_here, "data", dataset)
if dataset in list_datasets():
return pd.read_csv(file_and_path)
return pd.DataFrame()
86 changes: 86 additions & 0 deletions KonoPyUtil/dbutils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import sqlalchemy as sa
import pandas as pd
from .credentials import set_credentials
from .exceptions import MissingCredentialsError


def data_query(query, engine=None, **kwargs):
"""
consumes a select query and returns a dataframe with the results
:param query: string of query
:param engine: sql alchemy engine
:param **kwargs: remaining parameters for pandas.read_sql()
:return: dataframe of results of query
"""
close_engine = False
if engine is None:
close_engine = True
engine = get_engine(**kwargs)
df = pd.read_sql(query, engine)
if close_engine:
engine.dispose()
return df


def command_query(query, engine=None, **kwargs):
"""
consumes a command query (update, drop, etc)
:param query: string of query
:param engine: sql alchemy engine
:return: returns result of query execution
"""
close_engine = False
if engine is None:
close_engine = True
engine = get_engine(**kwargs)
if close_engine:
engine.dispose()
return engine.execute(sa.text(query).execution_options(autocommit=True))


def write_dataframe(df, tablename, engine, if_exists="append", index=False, **kwargs):
"""
Appends dataframe records to a database. (Creates table if it doesn't exist)
:param df: dataframe
:param tablename: table name
:param engine: engine
:param if_exists: {‘fail’, ‘replace’, ‘append’}, default ‘append’
:param **kwargs: remaining parameters for pandas.to_sql()
:return: True if success, False otherwise
"""

close_engine = False
if engine is None:
close_engine = True
engine = get_engine(**kwargs)
try:
df.to_sql(name=tablename, con=engine, if_exists=if_exists, index=index)
engine.dispose()
success = True
except Exception as ex:
template = "An exception of type {0} occurred. Arguments:\n{1!r}"
message = template.format(type(ex).__name__, ex.args)
print(message)
success = False
finally:
if close_engine:
engine.dispose()
return success


def get_engine(credentials=None, **kwargs):
"""
Returns a sqlalchemy engine given appropriate inputs
:param **kwargs: remaining parameters for sqlalchemy.create_engine()
"""
if not credentials:
os_credentials = set_credentials()
if not os_credentials:
raise (MissingCredentialsError())
userid = os_credentials.get("USERID", "db_userid")
password = os_credentials.get("PASSWORD", "db_password")
host = os_credentials.get("HOST", "db_host")
port = int(os_credentials.get("PORT", "0"))
dbname = os_credentials.get("DBNAME", "db_name")
cstring = f"postgresql://{userid}:{password}@{host}:{port}/{dbname}"
return sa.create_engine(cstring, **kwargs)
19 changes: 19 additions & 0 deletions KonoPyUtil/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class ParameterError(Exception):
def __init__(self, valid_parameters, bad_parameter):
self.valid_parameters = valid_parameters
self.bad_parameter = bad_parameter

def __str__(self):
return repr(f"""Valid Option: {self.valid_parameters}. Option Provided: {self.bad_parameter}""")


class MissingCredentialsError(Exception):
def __init__(
self,
):
pass

def __str__(self):
return repr(
f"""Your credentials are missing. Try KonoPyUtil.set_credentials() to set an environment variable named DB_CREDENTIALS."""
)
1 change: 1 addition & 0 deletions KonoPyUtil/soccer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .elo import get_elo_season, get_elo_match
Loading

0 comments on commit 6bd2b5e

Please sign in to comment.