Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
secret.py
*__pycache__/*
.idea/*
.idea/*
Pipfile
Pipfile.lock
.vscode/settings.json
19 changes: 0 additions & 19 deletions find_hero_test.py

This file was deleted.

129 changes: 127 additions & 2 deletions opendota.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,133 @@

# get/find matches

def generate_query(*heroes):
"""generates an SQL query where hero1+hero2 is vs hero3+hero4"""
Comment on lines +11 to +12
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want you to get in the habit of creating more descriptive function names. Conceivably in this project we will be generating many types of queries. What makes this one THE query?

How about generate_laning_matchups_query?

# won't support 2v3's or 1v3's in the case of trilanes

def select(*heroes):
"""generates select statement for certain num of heroes"""
select = f"SELECT"


i = 0 #leave me be sir
for data in heroes:
for hero in data:
if i == 0:
select = select + f" player_matches.hero_id AS hero1, \n"
else:
select = select + f"player_matches{i}.hero_id AS hero{i+1}, \n"
i = i+1
i = 0
for hero in data:
if i == 0:
select = select + f"player_matches.player_slot AS ps1, \n"
else:
select = select + f"player_matches{i}.player_slot AS ps{i+1}, \n"
i = i+1
Comment on lines +20 to +34
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is harder than it needs to be.

How about something like

for i, hero in enumerate(heroes):
    select += f"player_matches{i}.hero_id AS hero{i}\n"
    select += f"player_matches{i}.player_slot AS ps{i}, \n"


select = select + f"matches.match_id,\n"
select = select + f"leagues.name leaguename\n"
return select

def join(*heroes):
"""generates join statements for certain num of heroes"""
join = f"FROM player_matches \n"
i = 0
for data in heroes:
for hero in data:
if i == 0:
i = i+1
continue
Comment on lines +46 to +48
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like this shouldn't be necessary

how about something like

for i, hero in enumerate(heroes):
    if i==0:
        continue
    else:
        join +=...
        join += ...

else:
join = join + f"JOIN player_matches AS player_matches{i}\n"
join = join + f"ON player_matches.match_id = player_matches{i}.match_id\n"
i = i+1
join = join + f"JOIN matches\n"
join = join + f"ON player_matches.match_id = matches.match_id\n"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you implement my suggestion this has to become player_matches1

join = join + f"JOIN leagues using(leagueid)\n"
return join

def where(*heroes):
"""generates where statement for certain num of heroes"""
i = 0
where = f"WHERE"
for data in heroes:
for hero in data:
if i == 0:
where = where + f" player_matches.hero_id = {get_hero_id(hero)}\n"
i = i+1
else:
where = where + f"AND player_matches{i}.hero_id = {get_hero_id(hero)}\n"
i = i+1
Comment on lines +62 to +69
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only difference is player_matches vs player_matches{i}, just make them all player_matches{i}


#probably need to pass in a timestamp or something at some point for the following
where = where + f"AND matches.start_time >= extract(epoch FROM timestamp '2018-10-01T06:53:44.537Z')\n"
return where

def teams(*heroes):
"""adds onto where statement and specifies which team each hero is on, hero1+hero2 =teamA, hero3+hero4 = teamB"""
i = 0
teams = ""
for data in heroes:
for hero in data:
if i == 0:
i = i+1
continue
elif i == 1:
teams = teams + f"AND abs(player_matches.player_slot - player_matches1.player_slot) < 6\n"
i = i+1
elif i == 2:
teams = teams + f"AND abs(player_matches.player_slot - player_matches2.player_slot) > 123\n"
i = i+1
elif i == 3:
teams = teams + f"AND abs(player_matches2.player_slot - player_matches3.player_slot) < 6\n"
teams = teams + f"AND abs(player_matches1.player_slot - player_matches3.player_slot) > 123\n"
i = i+1
Comment on lines +79 to +93
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we say if it's the first hero in team A, no teams clause. if the hero is >1 item in team A, add same team clause. if in team B, add other team clause, if that makes sense.

teams = teams + "ORDER BY matches.match_id NULLS LAST LIMIT 200"
return teams

return select(heroes) + join(heroes) + where(heroes) + teams(heroes)


def make_query(hero1, hero2):
query = f"""SELECT player_matches.hero_id AS hero1,
player_matches1.hero_id AS hero2,
player_matches.player_slot AS ps1,
player_matches1.player_slot AS ps2,
matches.match_id,
leagues.name leaguename
FROM player_matches
JOIN player_matches AS player_matches1
ON player_matches.match_id = player_matches1.match_id
JOIN matches
ON player_matches.match_id = matches.match_id
JOIN leagues using(leagueid)
WHERE player_matches.hero_id = {get_hero_id(hero1)}
AND player_matches1.hero_id = {get_hero_id(hero2)}
AND matches.start_time >= extract(epoch
FROM timestamp '2020-10-23T06:53:44.537Z')
AND abs(player_matches.player_slot - player_matches1.player_slot) > 123
ORDER BY matches.match_id NULLS LAST LIMIT 200"""

# def find_matches_by_hero():
response = requests.get(
f"{API_ROOT}/explorer", params=dict(api_key=secret.OPENDOTA_API_KEY, sql=query)
)
return response.json()


def get_matches(hero1, hero2):

"""returns list of pro match ids played between two heroes"""

query_response = make_query(hero1, hero2)
match_list = query_response["rows"] #list of dictionaries for some reason
result = []

for match in match_list:
return [match['match_id'] for match in match_list]

return result


def find_hero(heroname):
Expand Down Expand Up @@ -45,4 +170,4 @@ def load_hero_list():


if __name__ == "__main__":
main()
main()
13 changes: 13 additions & 0 deletions tests/test_find_hero.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,16 @@ def test_find_juggernaut():
def test_hero_id():
juggernaut_id = opendota.get_hero_id("Juggernaut")
assert juggernaut_id == 8


def test_query():
print(opendota.make_query("Bloodseeker", "Crystal Maiden"))
assert type(opendota.make_query("Bloodseeker", "Crystal Maiden")) is dict
Comment on lines +16 to +17
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will make two separate queries to opendota, eating away at our cap. if you're gonna print, at least assign to an intermediary variable.

also, are there stronger assertions we can make beyond "it's a list"?



def test_get_matches():
assert type(opendota.get_matches("Bloodseeker", "Crystal Maiden")) is list


def test_generate_query():
print(opendota.generate_query("Bloodseeker", "Crystal Maiden", "Juggernaut", "Oracle"))