-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5d9591b
Showing
16 changed files
with
353 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Created by .ignore support plugin (hsz.mobi) | ||
### Python template | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
env/ | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*,cover | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
Copyright 2016 Aaron Toth | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
puckdb | ||
====== | ||
|
||
An async-first hockey data extractor and API. | ||
|
||
Still under active development and not ready for consumption. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
__title__ = 'puckdb' | ||
__author__ = 'Aaron Toth' | ||
__version__ = '0.0.1' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from contextlib import contextmanager | ||
|
||
from aiopg.sa import create_engine | ||
|
||
from .. import conf | ||
|
||
|
||
@contextmanager | ||
async def get_engine(): | ||
async with create_engine(dsn=conf.get_db()) as engine: | ||
await engine | ||
|
||
|
||
__all__ = ['get_engine'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import configparser | ||
import os | ||
|
||
import click | ||
|
||
from . import __title__ | ||
|
||
|
||
def _get_config_file_path(): | ||
return os.path.join(click.get_app_dir(__title__), 'config.ini') | ||
|
||
|
||
def _read(): | ||
conf_file = _get_config_file_path() | ||
conf = configparser.RawConfigParser() | ||
try: | ||
conf.read(conf_file) | ||
return conf, conf_file | ||
except IOError: | ||
raise IOError('Could not find settings file.\n' | ||
'Make sure it exists at "{path}"'.format(path=conf_file)) | ||
|
||
|
||
def _write(dsn=''): | ||
conf_file = _get_config_file_path() | ||
conf = configparser.RawConfigParser() | ||
if 'db' not in conf.sections(): | ||
conf.add_section('db') | ||
conf.set('db', 'dsn', dsn) | ||
with open(conf_file, 'w') as f: | ||
conf.write(f) | ||
|
||
|
||
def init(): | ||
config_file = _get_config_file_path() | ||
if not os.path.exists(os.path.dirname(config_file)): | ||
os.makedirs(os.path.dirname(config_file)) | ||
_write() | ||
|
||
|
||
def get_db() -> str: | ||
dsn = os.getenv('PUCKDB_DATABASE', None) | ||
if dsn: | ||
return dsn | ||
config, config_file = _read() | ||
try: | ||
return config.get('db', 'dsn') | ||
except configparser.NoSectionError: | ||
raise IOError('Could not read database settings from the config file.\n' | ||
'Make sure the [db] section exists in "{path}"'.format(path=config_file)) | ||
except configparser.NoOptionError: | ||
raise IOError('Could not read database settings from the config file.\n' | ||
'Make sure the [db] has the proper headings in "{path}"'.format(path=config_file)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import click | ||
|
||
|
||
@click.command() | ||
def init(): | ||
pass | ||
|
||
|
||
@click.group | ||
@click.version_option() | ||
def main(): | ||
pass | ||
|
||
main.add_command(init) | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import enum | ||
|
||
|
||
class GameState(enum.Enum): | ||
not_started = -1 | ||
in_progress = 0 | ||
finished = 1 | ||
|
||
|
||
class GameEvent(enum.Enum): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import sqlalchemy as sa | ||
from sqlalchemy.schema import CreateTable | ||
|
||
from .constants import GameState | ||
from .async.db import * | ||
|
||
metadata = sa.MetaData() | ||
|
||
league_tbl = sa.Table('league', metadata, | ||
sa.Column('id', sa.SmallInteger, primary_key=True), | ||
sa.Column('name', sa.String(255)) | ||
) | ||
|
||
team_tbl = sa.Table('team', metadata, | ||
sa.Column('id', sa.SmallInteger, primary_key=True), | ||
sa.Column('league', sa.SmallInteger, sa.ForeignKey('league.id'), nullable=False), | ||
sa.Column('name', sa.String), | ||
sa.Column('full_name', sa.String), | ||
sa.Column('city', sa.String) | ||
) | ||
|
||
game_tbl = sa.Table('game', metadata, | ||
sa.Column('id', sa.BigInteger, primary_key=True), | ||
sa.Column('season', sa.SmallInteger), | ||
sa.Column('status', sa.Enum(GameState)), | ||
sa.Column('away', sa.SmallInteger, sa.ForeignKey('team.id'), nullable=False), | ||
sa.Column('home', sa.SmallInteger, sa.ForeignKey('team.id'), nullable=False), | ||
sa.Column('away_score', sa.SmallInteger), | ||
sa.Column('home_score', sa.SmallInteger), | ||
sa.Column('start', sa.DateTime, index=True), | ||
sa.Column('duration', sa.Time), | ||
sa.Column('periods', sa.SmallInteger) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
class FilterException(Exception): | ||
def __init__(self, message=None): | ||
self.message = message | ||
|
||
def __str__(self): | ||
return 'Invalid filter{message}'.format(': ' + self.message if self.message else '') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
from datetime import datetime | ||
|
||
from . import exceptions | ||
|
||
|
||
class BaseFilter(object): | ||
pass | ||
|
||
|
||
class TeamFilter(BaseFilter): | ||
def __init__(self, name=None): | ||
self.name = name | ||
|
||
|
||
class GameFilter(BaseFilter): | ||
def __init__(self, from_date=None, to_date=None, team=None): | ||
""" | ||
:type from_date: datetime | ||
:type to_date: datetime | ||
:type team: TeamFilter | ||
""" | ||
if from_date is None: | ||
raise exceptions.FilterException('from_date must be provided') | ||
to_date = to_date or datetime.utcnow() | ||
if to_date < from_date: | ||
raise exceptions.FilterException('to_date must be after from_date') | ||
self.from_date = from_date | ||
self.to_date = to_date | ||
self.team = team | ||
|
||
@property | ||
def season_range(self): | ||
seasons = [] | ||
from_season = self.from_date.year if self.from_date.month >= 9 else self.from_date.year - 1 | ||
to_season = self.to_date.year - 1 if self.to_date.month < 9 else self.to_date.year | ||
for i in range(to_season - from_season + 1): | ||
season_start = from_season + i | ||
seasons.append('{}{}'.format(season_start, season_start+1)) | ||
return seasons |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import abc | ||
from datetime import datetime | ||
|
||
import aiohttp | ||
|
||
from . import exceptions, filters | ||
|
||
class BaseScraper(object): | ||
__metaclass__ = abc.ABCMeta | ||
|
||
@abc.abstractmethod | ||
async def get_schedule(self, game_filter: filters.GameFilter): | ||
pass | ||
|
||
|
||
class NHLScraper(BaseScraper): | ||
schedule_url = 'http://live.nhl.com/GameData/SeasonSchedule-{season}.json' | ||
|
||
async def get_schedule(self, game_filter: filters.GameFilter): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import re | ||
import ast | ||
|
||
from setuptools import setup, find_packages | ||
|
||
_version_re = re.compile(r'__version__\s+=\s+(.*)') | ||
with open('puckdb/__init__.py', 'rb') as f: | ||
version = str(ast.literal_eval(_version_re.search( | ||
f.read().decode('utf-8')).group(1))) | ||
|
||
setup( | ||
name='puckdb', | ||
author='Aaron Toth', | ||
version=version, | ||
url='https://github.com/aaront/puckdb', | ||
description='An async-first hockey data extractor and API', | ||
long_description=open('README.rst').read(), | ||
install_requires=[ | ||
'click', | ||
'cchardet', | ||
'aiohttp', | ||
'aiopg', | ||
'sqlalchemy' | ||
], | ||
test_suite="tests", | ||
include_package_data=True, | ||
packages=find_packages(), | ||
package_data={'': ['LICENSE']}, | ||
package_dir={'puckdb': 'puckdb'}, | ||
license='Apache 2.0', | ||
entry_points=''' | ||
[console_scripts] | ||
puckdb=puckdb.console:main | ||
''', | ||
classifiers=( | ||
'Development Status :: 2 - Pre-Alpha', | ||
'Intended Audience :: Developers', | ||
'Natural Language :: English', | ||
'License :: OSI Approved :: Apache Software License', | ||
'Programming Language :: Python', | ||
'Programming Language :: Python :: 3.5', | ||
'Topic :: Software Development :: Libraries' | ||
) | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import unittest | ||
from datetime import datetime | ||
|
||
from puckdb import filters | ||
|
||
|
||
class TestGameFilter(unittest.TestCase): | ||
def test_one_season_range(self): | ||
from_date = datetime(2014, 10, 22) | ||
to_date = datetime(2015, 4, 1) | ||
game_filter = filters.GameFilter(from_date=from_date, to_date=to_date) | ||
seasons = game_filter.season_range | ||
self.assertEqual(1, len(seasons)) | ||
self.assertEqual('20142015', seasons[0]) | ||
|
||
def test_season_before_range(self): | ||
from_date = datetime(2014, 4, 22) | ||
to_date = datetime(2015, 4, 1) | ||
game_filter = filters.GameFilter(from_date=from_date, to_date=to_date) | ||
seasons = game_filter.season_range | ||
self.assertEqual(2, len(seasons)) | ||
self.assertEqual('20132014', seasons[0]) | ||
self.assertEqual('20142015', seasons[1]) | ||
|
||
def test_season_after_range(self): | ||
from_date = datetime(2014, 10, 22) | ||
to_date = datetime(2015, 9, 1) | ||
game_filter = filters.GameFilter(from_date=from_date, to_date=to_date) | ||
seasons = game_filter.season_range | ||
self.assertEqual(2, len(seasons)) | ||
self.assertEqual('20142015', seasons[0]) | ||
self.assertEqual('20152016', seasons[1]) |