'''Module for the heropediadata api.'''
from __future__ import print_function
from json import loads
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
from contextlib import closing
from ast import literal_eval
from os import makedirs
import os.path as path
from logging import getLogger as get_logger
[docs]class HeropediaData(object):
'''Uses dota2's heropediadata api to find the correct hero/item name.'''
# CONSTANTS
DATA_DIR = path.abspath(path.join(path.dirname(__file__), 'data'))
ITEM_DATA = 'itemdata'
HERO_DATA = 'herodata'
HERO_NAME = {
'night_stalker': 'nightstalker', 'antimage': 'anti-mage',
'abyssal_underlord': 'underlord', 'rattletrap': 'clockwerk',
'windrunner': 'windranger', 'nevermore': 'shadow_fiend',
'vengefulspirit': 'vengeful_spirit', 'drow_ranger': 'drow',
'furion': "nature's_prophet", 'necrolyte': 'necrophos',
'skeleton_king': 'wraith_king', 'zuus': 'zeus', 'doom_bringer': 'doom',
'magnataur': 'magnus', 'wisp': 'io', 'centaur': 'centaur_warrunner',
'treant': 'treant_protector', 'shredder': 'timbersaw',
'obsidian_destroyer': 'outworld_devourer',
'life_stealer': 'lifestealer', 'queenofpain': 'queen_of_pain',
}
ITEM_NAME = {
'sphere': "linken's_sphere", 'bfury': 'battle_fury',
'manta': 'manta_style', 'courier': 'animal_courier',
'boots': 'boots_of_speed', 'basher': 'skull_basher',
'refresher': 'refresher_orb', 'heart': 'heart_of_tarrasque',
'blink': 'blink_dagger', 'travel_boots': 'boots_of_travel',
'ward_observer': 'observer_ward', 'vladmir': "vladmir's_offering",
'heavens_halberd': "heaven's_halberd", 'ward_sentry': 'sentry_ward',
'cyclone': "eul's_scepter_of_divinity", 'tpscroll': 'tp_scroll',
'sheepstick': 'scythe_of_vyse', 'branches': 'iron_branch',
'ancient_janggo': 'drum_of_endurance'
# 'combo_breaker': 'aeon_disk'
}
_logger = get_logger('dotapatch.data')
# Initialization Functions
@classmethod
def _download_file(cls, name):
'''Parses dota2's heropediadata file into dict.
Parameters
----------
name : str
heropediadata feed to be downloaded
Returns
-------
dictionary : dict
heropediadata
'''
cls._logger.info(
"Downloading {} from dota2's heropediadata".format(name))
link = 'http://www.dota2.com/jsfeed/heropediadata?feeds=' + name
try:
if 'file:///' in link:
raise ValueError('urlopen trying to leak information')
except ValueError as err:
cls._logger.critical('{}: {}'.format(err.__class__.__name__, err))
raise SystemExit(-1)
with closing(urlopen(link)) as response:
content = response.read()
json_data = content.decode('utf-8')
dictionary = loads(json_data)
cls._save_file(name, dictionary[name])
cls._logger.info("Updated {} saved successfully".format(name))
return dictionary[name]
@classmethod
def _open_file(cls, name):
'''Open dotapatch's heropediadata file.
Parameters
----------
name : str
heropediadata file to be opened
Returns
-------
dictionary : dict
heropediadata
'''
with open(path.join(cls.DATA_DIR, name), 'r') as text:
data = text.read()
dictionary = literal_eval(data)
return dictionary
@classmethod
def _save_file(cls, name, content):
'''Stores heropediadata file.
Parameters
----------
name : str
heropediadata file name to be created
content : str
heropediadata content to be stored
'''
with open(path.join(cls.DATA_DIR, name), 'w') as text:
print(content, file=text)
@staticmethod
def _key_to_value(dic):
'''Maps key to value from a dictionary.
e.g. {1: 'asd'} to {'asd': 1}
Parameters
----------
dic : dict
Dictionary to be mapped
Returns
-------
dict
Mapped dictionary
'''
return {value: key for key, value in dic.items()}
# Initialization
def __init__(self):
'''Initializes HeropediaData.
Check if heropediadata files exist.
If a file is not found, it's downloaded from dota2 heropediadata feed.
'''
# Check data folder
if not path.exists(self.DATA_DIR):
makedirs(self.DATA_DIR)
# Data Initialization
if not path.isfile(path.join(self.DATA_DIR, self.ITEM_DATA)):
self._item_dictionary = self.download_file(self.ITEM_DATA)
else:
self._item_dictionary = self._open_file(self.ITEM_DATA)
if not path.isfile(path.join(self.DATA_DIR, self.HERO_DATA)):
self._hero_dictionary = self.download_file(self.HERO_DATA)
else:
self._hero_dictionary = self._open_file(self.HERO_DATA)
# Proper Name Initialization
self._proper_hero_name = self._key_to_value(self.HERO_NAME)
self._proper_item_name = self._key_to_value(self.ITEM_NAME)
[docs] @classmethod
def sort_hero(cls, hero_tuple):
'''Formats hero_id to proper hero name.
Note
----
``shredder`` returns ``timbersaw``
Parameters
----------
hero_tuple : tuple
(name, _)
Returns
-------
name : str
Proper hero name
'''
name, _ = hero_tuple
return cls.HERO_NAME.get(name.lower(), name)
[docs] @classmethod
def sort_item(cls, item_tuple):
'''Formats item_id to proper item name.
Note
----
``sphere`` returns ``linkens sphere``
Parameters
----------
item_tuple : tuple
(name, _)
Returns
-------
name : str
Proper item name
'''
name, _ = item_tuple
return cls.ITEM_NAME.get(name.lower(), name)
# Default Function
@staticmethod
def _get_name(line, dictionary, proper_name):
'''Default function for finding object name.
Splits the line by ':' and checks if it exists in the object's
dictionary (heropediadata).
Note
----
``Illusions attack damage reduced against buildings`` returns ``None``
Parameters
----------
line : str
The phrase to be checked
dictionary : dict
Object's main dictionary (heropediadata)
proper_name : dict
Object's secondary dictionary
Returns
-------
name : str or None
Proper object name
'''
name = line.split(':')[0]
name = name.lower().replace(' ', '_')
found = dictionary.get(name, None)
if not found:
name = proper_name.get(name, None)
return name
# Name Functions
[docs] def get_item_name(self, line):
'''Searches the line for an item name and returns its proper name.
Note
----
``Dragon Lance: strength reduced from 14 to 13`` returns
``dragon_lance``
Parameters
----------
line : str
The phrase to be checked
Returns
-------
name : str or None
Proper item name
'''
name = self._get_name(
line,
self._item_dictionary,
self._proper_item_name)
return name
[docs] def get_hero_name(self, line):
'''Searches the line for a hero name and returns its proper name.
Note
----
``Juggernaut: base damage reduced by 2`` returns ``juggernaut``
Parameters
----------
line : str
The phrase to be checked
Returns
-------
name : str or None
Proper hero name
'''
name = self._get_name(
line,
self._hero_dictionary,
self._proper_hero_name)
return name