4 changed files with 295 additions and 6 deletions
@ -1,4 +1,5 @@ |
|||||
__version__ = "0.1" |
__version__ = "0.2" |
||||
__author__ = "Rossen Georgiev" |
__author__ = "Rossen Georgiev" |
||||
|
|
||||
from .SteamID import SteamID |
from .steamid import SteamID |
||||
|
from .webapi import WebAPI |
||||
|
@ -0,0 +1,243 @@ |
|||||
|
import requests |
||||
|
|
||||
|
|
||||
|
class WebAPI(object): |
||||
|
""" |
||||
|
Steam Web API wrapper |
||||
|
|
||||
|
Interfaces and methods are populated upon init based on |
||||
|
response of available such from the API. |
||||
|
|
||||
|
More: https://developer.valvesoftware.com/wiki/Steam_Web_API |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, key, https=True): |
||||
|
""" |
||||
|
Optain apikey at https://steamcommunity.com/dev/apikey |
||||
|
""" |
||||
|
|
||||
|
self.https = https |
||||
|
self.key = key |
||||
|
self.interfaces = [] |
||||
|
self.load_interfaces() |
||||
|
|
||||
|
def __repr__(self): |
||||
|
return "%s(key=%s, https=%s)" % ( |
||||
|
self.__class__.__name__, |
||||
|
repr(self.key), |
||||
|
repr(self.https), |
||||
|
) |
||||
|
|
||||
|
def load_interfaces(self): |
||||
|
""" |
||||
|
Fetches the available interfaces from the API itself and then |
||||
|
populates the name space under the instance |
||||
|
""" |
||||
|
|
||||
|
result = self._api_request( |
||||
|
"GET", |
||||
|
"ISteamWebAPIUtil/GetSupportedAPIList/v1/", |
||||
|
) |
||||
|
|
||||
|
if result.get('apilist', {}).get('interfaces', None) is None: |
||||
|
raise ValueError("Invalid response for GetSupportedAPIList") |
||||
|
|
||||
|
interfaces = result['apilist']['interfaces'] |
||||
|
if len(interfaces) == 0: |
||||
|
raise ValueError("API returned not interfaces; probably using invalid key") |
||||
|
|
||||
|
# clear existing interface instances |
||||
|
for interface in self.interfaces: |
||||
|
delattr(self, interface.name) |
||||
|
self.interfaces = [] |
||||
|
|
||||
|
# create interface instances from response |
||||
|
for interface in interfaces: |
||||
|
obj = WebAPIInterface(interface, parent=self) |
||||
|
self.interfaces.append(obj) |
||||
|
setattr(self, obj.name, obj) |
||||
|
|
||||
|
def call(self, method_path, **kwargs): |
||||
|
""" |
||||
|
Make an API call for specific method |
||||
|
|
||||
|
method_path is a str in the format of "INTERFACE.METHOD" |
||||
|
""" |
||||
|
|
||||
|
interface, method = method_path.split('.', 1) |
||||
|
return getattr(getattr(self, interface), method)(**kwargs) |
||||
|
|
||||
|
@property |
||||
|
def _url_base(self): |
||||
|
return "%s://api.steampowered.com/" % ('https' if self.https else 'http') |
||||
|
|
||||
|
def _api_request(self, method, path, **kwargs): |
||||
|
if method not in ('GET', 'POST'): |
||||
|
raise NotImplemented("Unsupported method: %s" % self.method) |
||||
|
|
||||
|
# set the key for every request, unless it's already specified by the method |
||||
|
if kwargs.get('params', {}).get('key', None) is None: |
||||
|
if 'params' not in kwargs: |
||||
|
kwargs['params'] = {} |
||||
|
kwargs['params']['key'] = self.key |
||||
|
|
||||
|
# move params to data, if data is not specified for POST |
||||
|
# simplifies code calling this method |
||||
|
if method == 'POST' and 'data' not in kwargs: |
||||
|
kwargs['data'] = kwargs['params'] |
||||
|
del kwargs['params'] |
||||
|
|
||||
|
f = getattr(requests, method.lower()) |
||||
|
resp = f(self._url_base + path, **kwargs) |
||||
|
|
||||
|
if not resp.ok: |
||||
|
raise requests.exceptions.HTTPError("%s %s" % (resp.status_code, resp.reason)) |
||||
|
|
||||
|
return resp.json() |
||||
|
|
||||
|
def doc(self): |
||||
|
doc = "Steam Web API - List of all interfaces\n\n" |
||||
|
for interface in self.interfaces: |
||||
|
doc += interface.doc() |
||||
|
return doc |
||||
|
|
||||
|
|
||||
|
class WebAPIInterface(object): |
||||
|
""" |
||||
|
Steam Web API Interface |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, interface_dict, parent=None): |
||||
|
self._parent = parent |
||||
|
self.name = interface_dict['name'] |
||||
|
self.methods = [] |
||||
|
|
||||
|
for method in interface_dict['methods']: |
||||
|
obj = WebAPIMethod(method, parent=self) |
||||
|
self.methods.append(obj) |
||||
|
setattr(self, obj.name, obj) |
||||
|
|
||||
|
def __repr__(self): |
||||
|
return "<%s %s with %s methods>" % ( |
||||
|
self.__class__.__name__, |
||||
|
repr(self.name), |
||||
|
repr(len(list(self))), |
||||
|
) |
||||
|
|
||||
|
def __iter__(self): |
||||
|
return iter(self.methods) |
||||
|
|
||||
|
@property |
||||
|
def https(self): |
||||
|
return self._parent.https |
||||
|
|
||||
|
def doc(self): |
||||
|
doc = "%s\n%s\n" % (self.name, '-'*len(self.name)) |
||||
|
for method in self.methods: |
||||
|
doc += " %s\n" % method.doc().replace("\n", "\n ") |
||||
|
return doc |
||||
|
|
||||
|
|
||||
|
class WebAPIMethod(object): |
||||
|
""" |
||||
|
Steam Web API Interface Method |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, method_dict, parent=None): |
||||
|
self._parent = parent |
||||
|
self._dict = method_dict |
||||
|
|
||||
|
params = method_dict['parameters'] |
||||
|
self._dict['parameters'] = {} |
||||
|
for param in params: |
||||
|
# add property indicating param can be a list |
||||
|
param['_array'] = param['name'].endswith('[0]') |
||||
|
# fix name |
||||
|
param['name'] = param['name'].rstrip('[0]') |
||||
|
# turn params from a list to a dict |
||||
|
self._dict['parameters'][param['name']] = param |
||||
|
|
||||
|
def __repr__(self): |
||||
|
return "<%s %s for %s>" % ( |
||||
|
self.__class__.__name__, |
||||
|
repr(self.name), |
||||
|
repr(self._parent.name), |
||||
|
) |
||||
|
|
||||
|
def __call__(self, **kwargs): |
||||
|
unrecognized = set(kwargs.keys()).difference(set(self._dict['parameters'].keys() + ['key'])) |
||||
|
if unrecognized: |
||||
|
raise ValueError("Unrecognized parameter %s" % repr(unrecognized.pop())) |
||||
|
|
||||
|
params = {} |
||||
|
for param in self.parameters.values(): |
||||
|
name = param['name'] |
||||
|
islist = param['_array'] |
||||
|
optional = param['optional'] |
||||
|
|
||||
|
# raise if we are missing a required parameter |
||||
|
if not optional and name not in kwargs and name != 'key': |
||||
|
raise ValueError("Method requires %s to be set" % repr(name)) |
||||
|
|
||||
|
# populate params that will be passed to _api_request |
||||
|
if name in kwargs: |
||||
|
# some parameters can be an array, they need to be send as seperate field |
||||
|
# the array index is append to the name (e.g. name[0], name[1] etc) |
||||
|
if islist: |
||||
|
if not isinstance(kwargs[name], list): |
||||
|
raise ValueError("Expected %s to be a list, got %s" % (repr(name), repr(type(kwargs[name])))) |
||||
|
|
||||
|
for idx, value in enumerate(kwargs[name]): |
||||
|
params['%s[%d]' % (name, idx)] = value |
||||
|
else: |
||||
|
params[name] = kwargs[name] |
||||
|
|
||||
|
# make the request |
||||
|
return self._api_request( |
||||
|
self.method, |
||||
|
"%s/%s/v%s/" % (self._parent.name, self.name, self.version), |
||||
|
params=params, |
||||
|
) |
||||
|
|
||||
|
@property |
||||
|
def version(self): |
||||
|
return self._dict['version'] |
||||
|
|
||||
|
@property |
||||
|
def method(self): |
||||
|
return self._dict['httpmethod'] |
||||
|
|
||||
|
@property |
||||
|
def parameters(self): |
||||
|
return self._dict['parameters'] |
||||
|
|
||||
|
@property |
||||
|
def _api_request(self): |
||||
|
return self._parent._parent._api_request |
||||
|
|
||||
|
@property |
||||
|
def name(self): |
||||
|
return self._dict['name'] |
||||
|
|
||||
|
@property |
||||
|
def https(self): |
||||
|
return self._parent.https |
||||
|
|
||||
|
def doc(self): |
||||
|
doc = "%(name)s (version: %(version)s)\n" % self._dict |
||||
|
|
||||
|
if 'description' in self._dict: |
||||
|
doc += "\n %(description)s\n" % self._dict |
||||
|
|
||||
|
if len(self.parameters): |
||||
|
doc += " \n Parameters:\n" |
||||
|
|
||||
|
for param in sorted(self.parameters.values(), key=lambda x: x['name']): |
||||
|
doc += " %s %s %s%s\n" % ( |
||||
|
param['name'].ljust(25), |
||||
|
(param['type']+"[]").ljust(8) if param['_array'] else param['type'].ljust(8), |
||||
|
'optional' if param['optional'] else 'required', |
||||
|
("\n - " + param['description']) if 'description' in param and param['description'] else '', |
||||
|
) |
||||
|
|
||||
|
return doc |
Loading…
Reference in new issue