Source code for woeid.modules

try:
	from urllib import quote
except ImportError as e:
	from urllib.parse import quote
from woeid import WoeidError
from six import string_types

__author__ = 'Renchen'

[docs]class Filters: """A class that encapsulates all filters Args: q(``str`` or ``tuple``, optional): Specify a place name to search for or a tuple that has a place name and a focus. This filter is mutually exclusive with the `woeid` filter. The specified place can be any unicode characters. Focus can be either an ISO-3166-1 country code or a WOEID. For a "startswith" filter, specify the place as a string followed by an asterisk (*). woeid(``list``(``str``) or ``list``(``int``), optional): Specify a `Where On Earth Identifier` (`woeid`). Up to ten WOEIDs may be specified. This filter is mutually exclusive with the `q` filter. Example: woeid=(1,2,3) typ(``list``(``str``) or ``list``(``int``) or ``int``, optional): Specify one or more place type codes (https://developer.yahoo.com/geo/geoplanet/guide/concepts.html#placetypes). Up to ten place type codes or names may be provided. degree(``int`` or ``str``, optional): `.degree` specifier which represents the degree to which two places are neighborhoods. Only consider valid if either `neighbors` or `children` filters are set. nd(``boolean``, optional): Specify a join operations on two filters. Example: >>> import woeid >>> api = woeid.Api(client_id='YOUR_CLIENT_ID') >>> ret = api.GetPlaces(q='StringField', typ=22, nd=True) """ def __init__(self, q=None, woeid=None, typ=None, degree=None, aand=None): filters = {} # q and woeid are mutually exclusive if isinstance(q, string_types) or isinstance(q, tuple): filters['q'] = q elif woeid and isinstance(woeid, list): # Make sure the values are str filters['woeid'] = [str(val) for val in woeid if isinstance(val, int) or isinstance(val, string_types)] if typ and isinstance(typ, list) or isinstance(typ, int): filters['type'] = typ if degree and isinstance(degree, int): filters['degree'] = degree if aand and isinstance(aand, bool): filters['and'] = aand self._filters = filters
[docs] def HasQ(self): """Return if the filter object has `.q` filter. """ return 'q' in self._filters
[docs] def HasWoeid(self): """Return if the filter object has `.woeid` filter. """ return 'woeid' in self._filters
[docs] def HasType(self): """Return if the filter object has `.type` filter """ return 'type' in self._filters
[docs] def HasDegree(self): """Return if the filter object has `.degree` filter """ return 'degree' in self._filters
[docs] def HasAnd(self): """Return if the filter object has `$and` filter """ return 'and' in self._filters
[docs] def IsValid(self): return isinstance(self._filters, dict)
def __str__(self): qstr = '' woeidstr = '' typestr = '' degreestr = '' andstr = '' # work on .q filter if self.HasQ(): if isinstance(self._filters['q'], string_types): qstr = quote(self._filters['q'].encode('utf-8')) elif isinstance(self._filters['q'], tuple): stra = self._filters['q'][0].encode('utf-8') strb = self._filters['q'][1].encode('utf-8') # Second item will be a focus value # Focus can be either an ISO-3166-1 country code or a WOEID. qstr += quote(stra + ',' + strb) else: raise WoeidError("Unexpected usage of function! query filter is %s" % self._filters['q']) qstr = '.q(%s)'%qstr # work on .woeid filter if self.HasWoeid(): if isinstance(self._filters['woeid'], list) and len(self._filters[ 'woeid']) > 1: for item in self._filters['woeid']: if (isinstance(item, string_types) and item.isdigit()) or isinstance(item, int): woeidstr += quote(item) + ',' # tick out the last comma woeidstr = woeidstr[:-1] elif isinstance(self._filters['woeid'], list) and len( self._filters['woeid']) == 1: woeidstr = '/' + quote(self._filters['woeid'][0]) else: raise WoeidError("Unexpected usage of function! query filter is %s"%self._filters['woeid']) #.woeid can be omitted if there is only one item if ',' in woeidstr: woeidstr = '.woeid(%s)'%woeidstr # work on .type filter if 'type' in self._filters: tpitem = self._filters['type'] if isinstance(tpitem, list): for item in tpitem: if (isinstance(item, string_types) and item.isdigit()) or isinstance(item, int): typestr += quote(str(item)) + ',' typestr = typestr[:-1] typestr = '.type(%s)'%typestr elif (type(tpitem) is str and tpitem.isdigit()) or isinstance(tpitem, int): typestr = '.type(%s)'%quote(str(tpitem)) # work on .degree filter if 'degree' in self._filters: degree = str(self._filters['degree']) degreestr = '.degree(%s)'%degree # work on .and filter if 'and' in self._filters: conda = '' condb = '' if self.HasQ() and qstr: conda = qstr if self.HasWoeid() and woeidstr: conda = woeidstr if typestr: condb = typestr if degreestr: condb = degreestr if conda and condb: andstr = '$and(%s,%s)'%(conda,condb) if andstr: return andstr query_or_woeid_str = qstr if qstr else woeidstr return query_or_woeid_str + typestr + degreestr
[docs]class Relationships: """"A class that encapsulates all relationships Args: parent(``boolean``, optional): A relationship specifier used to return a parent place of a given woeid. ancestors(``boolean``, optional): A relationship specifier used to return one or more acestors of a place of a given woeid. belongtos(``boolean``, optional): A relationship specifier used to return a collection of places that have a place as a child or descendant (child of a child). neighbors(``boolean``, optional): A relationship specifier used to return a collection of places that neighbor of a place. children(``boolean``, optional): A relationship specifier used to return a collection of places that are children of a place. siblings(``boolean``, optional): A relationship specifier used to return a collection of places that are siblings of a place. descendants(``boolean``, optional): A relationship specifier used to return a collection of places that are in the child hierarchy (the child, the child of child, etc). common(``boolean``, optional): A relationship specifier used to return the common ancestor of both places. """ def __init__(self, parent=False, ancestors=False, belongstos=False, neighbors=False, siblings=False, children=False, descendants=False, common=False): self._parent=parent self._ancestors=ancestors self._belongtos=belongstos self._neighbors=neighbors self._siblings=siblings self._children=children self._descendants=descendants self._common=common def __str__(self): if self._parent: return '/parent' if self._ancestors: return '/ancestors' if self._belongtos: return '/belongtos' if self._neighbors: return '/neighbors' if self._siblings: return '/siblings' if self._children: return '/children' if self._descendants: return '/descendants' if self._common: return '/common/' return '' def __Validate(self, filters): if isinstance(filters, Filters): raise WoeidError("Unexpected modules usage: %s"%"Validate takes a Filters object as its argument") if not filters.IsValid(): raise WoeidError("Unexpected API usage: %s"%"filters should be a dictionary") ''' /parent, /ancestors, /siblings, /common/ don't support any filters''' if self._parent and filters.keys(): raise WoeidError("Unexpected API usage: %s"%"woeid/parent doesn't support filters") if self._ancestors and filters.keys(): raise WoeidError("Unexpected API usage: %s"%"woeid/ancestors doesn't support filters") if self._siblings and filters.keys(): raise WoeidError("Unexpected API usage: %s"%"woeid/siblings doesn't support filters") if self._common and filters.keys(): raise WoeidError("Unexpected API usage: %s"%"woeid1/common/woeid2 doesn't support filters") '''/belongtos and /descendants and /children support .type filter''' if self._belongtos and (filters.HasAnd() or filters.HasDegree() or filters.HasQ() or filters.HasWoeid()): raise WoeidError("Unexpected API usage: %s"%"woeid/belongtos supports .type filter only") if self._descendants and (filters.HasAnd() or filters.HasDegree() or filters.HasQ() or filters.HasWoeid()): raise WoeidError("Unexpected API usage: %s"%"woeid/descendants supports .type filter only") if self._children and (filters.HasWoeid() or filters.HasQ() or filters.HasAnd()): raise WoeidError("Unexpected API usage: %s"%"woeid/children supports .degree or .type filters only") '''/neighbors support .degree filter''' if self._neighbors and (filters.HasWoeid() or filters.HasType() or filters.HasQ() or filters.HasAnd()): raise WoeidError("Unexpected API usage: %s"%"woeid/neighbors supports .degree filter only")