mirror of
https://github.com/Mikaela/Limnoria.git
synced 2025-01-11 12:42:34 +01:00
Removed spaces at the end of lines.
This commit is contained in:
parent
9dc1221045
commit
ca646716b1
7956
others/SOAP.py
7956
others/SOAP.py
File diff suppressed because it is too large
Load Diff
550
others/amazon.py
550
others/amazon.py
@ -1,275 +1,275 @@
|
||||
"""Python wrapper for Amazon web APIs
|
||||
|
||||
This module allows you to access Amazon's web APIs,
|
||||
to do things like search Amazon and get the results programmatically.
|
||||
Described here:
|
||||
http://www.amazon.com/webservices
|
||||
|
||||
You need a Amazon-provided license key to use these services.
|
||||
Follow the link above to get one. These functions will look in
|
||||
several places (in this order) for the license key:
|
||||
- the "license_key" argument of each function
|
||||
- the module-level LICENSE_KEY variable (call setLicense once to set it)
|
||||
- an environment variable called AMAZON_LICENSE_KEY
|
||||
- a file called ".amazonkey" in the current directory
|
||||
- a file called "amazonkey.txt" in the current directory
|
||||
- a file called ".amazonkey" in your home directory
|
||||
- a file called "amazonkey.txt" in your home directory
|
||||
- a file called ".amazonkey" in the same directory as amazon.py
|
||||
- a file called "amazonkey.txt" in the same directory as amazon.py
|
||||
|
||||
Sample usage:
|
||||
>>> import amazon
|
||||
>>> amazon.setLicense('...') # must get your own key!
|
||||
>>> pythonBooks = amazon.searchByKeyword('Python')
|
||||
>>> pythonBooks[0].ProductName
|
||||
u'Learning Python (Help for Programmers)'
|
||||
>>> pythonBooks[0].URL
|
||||
...
|
||||
>>> pythonBooks[0].OurPrice
|
||||
...
|
||||
|
||||
Other available functions:
|
||||
- browseBestSellers
|
||||
- searchByASIN
|
||||
- searchByUPC
|
||||
- searchByAuthor
|
||||
- searchByArtist
|
||||
- searchByActor
|
||||
- searchByDirector
|
||||
- searchByManufacturer
|
||||
- searchByListMania
|
||||
- searchSimilar
|
||||
|
||||
Other usage notes:
|
||||
- Most functions can take product_line as well, see source for possible values
|
||||
- All functions can take type="lite" to get less detail in results
|
||||
- All functions can take page=N to get second, third, fourth page of results
|
||||
- All functions can take license_key="XYZ", instead of setting it globally
|
||||
- All functions can take http_proxy="http://x/y/z" which overrides your system setting
|
||||
"""
|
||||
|
||||
__author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
|
||||
__version__ = "0.4"
|
||||
__cvsversion__ = "$Revision$"[11:-2]
|
||||
__date__ = "$Date$"[7:-2]
|
||||
__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
|
||||
__license__ = "Python"
|
||||
|
||||
from xml.dom import minidom
|
||||
import os, sys, getopt, cgi, urllib
|
||||
try:
|
||||
import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py
|
||||
timeoutsocket.setDefaultSocketTimeout(10)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
LICENSE_KEY = None
|
||||
HTTP_PROXY = None
|
||||
|
||||
# don't touch the rest of these constants
|
||||
class AmazonError(Exception): pass
|
||||
class NoLicenseKey(Exception): pass
|
||||
_amazonfile1 = ".amazonkey"
|
||||
_amazonfile2 = "amazonkey.txt"
|
||||
_licenseLocations = (
|
||||
(lambda key: key, 'passed to the function in license_key variable'),
|
||||
(lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'),
|
||||
(lambda key: os.environ.get('AMAZON_LICENSE_KEY', None), 'an environment variable called AMAZON_LICENSE_KEY'),
|
||||
(lambda key: _contentsOf(os.getcwd(), _amazonfile1), '%s in the current directory' % _amazonfile1),
|
||||
(lambda key: _contentsOf(os.getcwd(), _amazonfile2), '%s in the current directory' % _amazonfile2),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile1), '%s in your home directory' % _amazonfile1),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile2), '%s in your home directory' % _amazonfile2),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _amazonfile1), '%s in the amazon.py directory' % _amazonfile1),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _amazonfile2), '%s in the amazon.py directory' % _amazonfile2)
|
||||
)
|
||||
|
||||
## administrative functions
|
||||
def version():
|
||||
print """PyAmazon %(__version__)s
|
||||
%(__copyright__)s
|
||||
released %(__date__)s
|
||||
""" % globals()
|
||||
|
||||
## utility functions
|
||||
def setLicense(license_key):
|
||||
"""set license key"""
|
||||
global LICENSE_KEY
|
||||
LICENSE_KEY = license_key
|
||||
|
||||
def getLicense(license_key = None):
|
||||
"""get license key
|
||||
|
||||
license key can come from any number of locations;
|
||||
see module docs for search order"""
|
||||
for get, location in _licenseLocations:
|
||||
rc = get(license_key)
|
||||
if rc: return rc
|
||||
raise NoLicenseKey, 'get a license key at http://www.amazon.com/webservices'
|
||||
|
||||
def setProxy(http_proxy):
|
||||
"""set HTTP proxy"""
|
||||
global HTTP_PROXY
|
||||
HTTP_PROXY = http_proxy
|
||||
|
||||
def getProxy(http_proxy = None):
|
||||
"""get HTTP proxy"""
|
||||
return http_proxy or HTTP_PROXY
|
||||
|
||||
def getProxies(http_proxy = None):
|
||||
http_proxy = getProxy(http_proxy)
|
||||
if http_proxy:
|
||||
proxies = {"http": http_proxy}
|
||||
else:
|
||||
proxies = None
|
||||
return proxies
|
||||
|
||||
def _contentsOf(dirname, filename):
|
||||
filename = os.path.join(dirname, filename)
|
||||
if not os.path.exists(filename): return None
|
||||
fsock = open(filename)
|
||||
contents = fsock.read()
|
||||
fsock.close()
|
||||
return contents
|
||||
|
||||
def _getScriptDir():
|
||||
if __name__ == '__main__':
|
||||
return os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
else:
|
||||
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
|
||||
|
||||
class Bag: pass
|
||||
|
||||
def unmarshal(element):
|
||||
rc = Bag()
|
||||
if isinstance(element, minidom.Element) and (element.tagName == 'Details'):
|
||||
rc.URL = element.attributes["url"].value
|
||||
childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)]
|
||||
if childElements:
|
||||
for child in childElements:
|
||||
key = child.tagName
|
||||
if hasattr(rc, key):
|
||||
if type(getattr(rc, key)) <> type([]):
|
||||
setattr(rc, key, [getattr(rc, key)])
|
||||
setattr(rc, key, getattr(rc, key) + [unmarshal(child)])
|
||||
else:
|
||||
setattr(rc, key, unmarshal(child))
|
||||
else:
|
||||
rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)])
|
||||
if element.tagName == 'SalesRank':
|
||||
rc = int(rc.replace(',', ''))
|
||||
return rc
|
||||
|
||||
def buildURL(search_type, keyword, product_line, type, page, license_key):
|
||||
url = "http://xml.amazon.com/onca/xml?v=1.0&f=xml&t=webservices-20"
|
||||
url += "&dev-t=%s" % license_key.strip()
|
||||
url += "&type=%s" % type
|
||||
if page:
|
||||
url += "&page=%s" % page
|
||||
if product_line:
|
||||
url += "&mode=%s" % product_line
|
||||
url += "&%s=%s" % (search_type, urllib.quote(keyword))
|
||||
# print url
|
||||
return url
|
||||
|
||||
## main functions
|
||||
def search(search_type, keyword, product_line, type="heavy", page=None,
|
||||
license_key = None, http_proxy = None):
|
||||
"""search Amazon
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.amazon.com/webservices
|
||||
to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
keyword - keyword to search
|
||||
search_type - in (KeywordSearch, BrowseNodeSearch, AsinSearch, UpcSearch, AuthorSearch, ArtistSearch, ActorSearch, DirectorSearch, ManufacturerSearch, ListManiaSearch, SimilaritySearch)
|
||||
product_line - type of product to search for. restrictions based on search_type
|
||||
UpcSearch - in (music, classical)
|
||||
AuthorSearch - must be "books"
|
||||
ArtistSearch - in (music, classical)
|
||||
ActorSearch - in (dvd, vhs, video)
|
||||
DirectorSearch - in (dvd, vhs, video)
|
||||
ManufacturerSearch - in (electronics, kitchen, videogames, software, photo, pc-hardware)
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: list of Bags, each Bag may contain the following attributes:
|
||||
Asin - Amazon ID ("ASIN" number) of this item
|
||||
Authors - list of authors
|
||||
Availability - "available", etc.
|
||||
BrowseList - list of related categories
|
||||
Catalog - catalog type ("Book", etc)
|
||||
CollectiblePrice - ?, format "$34.95"
|
||||
ImageUrlLarge - URL of large image of this item
|
||||
ImageUrlMedium - URL of medium image of this item
|
||||
ImageUrlSmall - URL of small image of this item
|
||||
Isbn - ISBN number
|
||||
ListPrice - list price, format "$34.95"
|
||||
Lists - list of ListMania lists that include this item
|
||||
Manufacturer - manufacturer
|
||||
Media - media ("Paperback", "Audio CD", etc)
|
||||
NumMedia - number of different media types in which this item is available
|
||||
OurPrice - Amazon price, format "$24.47"
|
||||
ProductName - name of this item
|
||||
ReleaseDate - release date, format "09 April, 1999"
|
||||
Reviews - reviews (AvgCustomerRating, plus list of CustomerReview with Rating, Summary, Content)
|
||||
SalesRank - sales rank (integer)
|
||||
SimilarProducts - list of Product, which is ASIN number
|
||||
ThirdPartyNewPrice - ?, format "$34.95"
|
||||
URL - URL of this item
|
||||
"""
|
||||
license_key = getLicense(license_key)
|
||||
url = buildURL(search_type, keyword, product_line, type, page, license_key)
|
||||
proxies = getProxies(http_proxy)
|
||||
u = urllib.FancyURLopener(proxies)
|
||||
usock = u.open(url)
|
||||
xmldoc = minidom.parse(usock)
|
||||
usock.close()
|
||||
data = unmarshal(xmldoc).ProductInfo
|
||||
if hasattr(data, 'ErrorMsg'):
|
||||
raise AmazonError, data.ErrorMsg
|
||||
else:
|
||||
return data.Details
|
||||
|
||||
def searchByKeyword(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("KeywordSearch", keyword, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def browseBestSellers(browse_node, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("BrowseNodeSearch", browse_node, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByASIN(ASIN, type="heavy", license_key=None, http_proxy=None):
|
||||
return search("AsinSearch", ASIN, None, type, None, license_key, http_proxy)
|
||||
|
||||
def searchByUPC(UPC, type="heavy", license_key=None, http_proxy=None):
|
||||
return search("UpcSearch", UPC, None, type, None, license_key, http_proxy)
|
||||
|
||||
def searchByAuthor(author, type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("AuthorSearch", author, "books", type, page, license_key, http_proxy)
|
||||
|
||||
def searchByArtist(artist, product_line="music", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
if product_line not in ("music", "classical"):
|
||||
raise AmazonError, "product_line must be in ('music', 'classical')"
|
||||
return search("ArtistSearch", artist, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByActor(actor, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
if product_line not in ("dvd", "vhs", "video"):
|
||||
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
|
||||
return search("ActorSearch", actor, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByDirector(director, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
if product_line not in ("dvd", "vhs", "video"):
|
||||
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
|
||||
return search("DirectorSearch", director, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByManufacturer(manufacturer, product_line="pc-hardware", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
if product_line not in ("electronics", "kitchen", "videogames", "software", "photo", "pc-hardware"):
|
||||
raise AmazonError, "product_line must be in ('electronics', 'kitchen', 'videogames', 'software', 'photo', 'pc-hardware')"
|
||||
return search("ManufacturerSearch", manufacturer, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByListMania(listManiaID, type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("ListManiaSearch", listManiaID, None, type, page, license_key, http_proxy)
|
||||
|
||||
def searchSimilar(ASIN, type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("SimilaritySearch", ASIN, None, type, page, license_key, http_proxy)
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
"""Python wrapper for Amazon web APIs
|
||||
|
||||
This module allows you to access Amazon's web APIs,
|
||||
to do things like search Amazon and get the results programmatically.
|
||||
Described here:
|
||||
http://www.amazon.com/webservices
|
||||
|
||||
You need a Amazon-provided license key to use these services.
|
||||
Follow the link above to get one. These functions will look in
|
||||
several places (in this order) for the license key:
|
||||
- the "license_key" argument of each function
|
||||
- the module-level LICENSE_KEY variable (call setLicense once to set it)
|
||||
- an environment variable called AMAZON_LICENSE_KEY
|
||||
- a file called ".amazonkey" in the current directory
|
||||
- a file called "amazonkey.txt" in the current directory
|
||||
- a file called ".amazonkey" in your home directory
|
||||
- a file called "amazonkey.txt" in your home directory
|
||||
- a file called ".amazonkey" in the same directory as amazon.py
|
||||
- a file called "amazonkey.txt" in the same directory as amazon.py
|
||||
|
||||
Sample usage:
|
||||
>>> import amazon
|
||||
>>> amazon.setLicense('...') # must get your own key!
|
||||
>>> pythonBooks = amazon.searchByKeyword('Python')
|
||||
>>> pythonBooks[0].ProductName
|
||||
u'Learning Python (Help for Programmers)'
|
||||
>>> pythonBooks[0].URL
|
||||
...
|
||||
>>> pythonBooks[0].OurPrice
|
||||
...
|
||||
|
||||
Other available functions:
|
||||
- browseBestSellers
|
||||
- searchByASIN
|
||||
- searchByUPC
|
||||
- searchByAuthor
|
||||
- searchByArtist
|
||||
- searchByActor
|
||||
- searchByDirector
|
||||
- searchByManufacturer
|
||||
- searchByListMania
|
||||
- searchSimilar
|
||||
|
||||
Other usage notes:
|
||||
- Most functions can take product_line as well, see source for possible values
|
||||
- All functions can take type="lite" to get less detail in results
|
||||
- All functions can take page=N to get second, third, fourth page of results
|
||||
- All functions can take license_key="XYZ", instead of setting it globally
|
||||
- All functions can take http_proxy="http://x/y/z" which overrides your system setting
|
||||
"""
|
||||
|
||||
__author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
|
||||
__version__ = "0.4"
|
||||
__cvsversion__ = "$Revision$"[11:-2]
|
||||
__date__ = "$Date$"[7:-2]
|
||||
__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
|
||||
__license__ = "Python"
|
||||
|
||||
from xml.dom import minidom
|
||||
import os, sys, getopt, cgi, urllib
|
||||
try:
|
||||
import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py
|
||||
timeoutsocket.setDefaultSocketTimeout(10)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
LICENSE_KEY = None
|
||||
HTTP_PROXY = None
|
||||
|
||||
# don't touch the rest of these constants
|
||||
class AmazonError(Exception): pass
|
||||
class NoLicenseKey(Exception): pass
|
||||
_amazonfile1 = ".amazonkey"
|
||||
_amazonfile2 = "amazonkey.txt"
|
||||
_licenseLocations = (
|
||||
(lambda key: key, 'passed to the function in license_key variable'),
|
||||
(lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'),
|
||||
(lambda key: os.environ.get('AMAZON_LICENSE_KEY', None), 'an environment variable called AMAZON_LICENSE_KEY'),
|
||||
(lambda key: _contentsOf(os.getcwd(), _amazonfile1), '%s in the current directory' % _amazonfile1),
|
||||
(lambda key: _contentsOf(os.getcwd(), _amazonfile2), '%s in the current directory' % _amazonfile2),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile1), '%s in your home directory' % _amazonfile1),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile2), '%s in your home directory' % _amazonfile2),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _amazonfile1), '%s in the amazon.py directory' % _amazonfile1),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _amazonfile2), '%s in the amazon.py directory' % _amazonfile2)
|
||||
)
|
||||
|
||||
## administrative functions
|
||||
def version():
|
||||
print """PyAmazon %(__version__)s
|
||||
%(__copyright__)s
|
||||
released %(__date__)s
|
||||
""" % globals()
|
||||
|
||||
## utility functions
|
||||
def setLicense(license_key):
|
||||
"""set license key"""
|
||||
global LICENSE_KEY
|
||||
LICENSE_KEY = license_key
|
||||
|
||||
def getLicense(license_key = None):
|
||||
"""get license key
|
||||
|
||||
license key can come from any number of locations;
|
||||
see module docs for search order"""
|
||||
for get, location in _licenseLocations:
|
||||
rc = get(license_key)
|
||||
if rc: return rc
|
||||
raise NoLicenseKey, 'get a license key at http://www.amazon.com/webservices'
|
||||
|
||||
def setProxy(http_proxy):
|
||||
"""set HTTP proxy"""
|
||||
global HTTP_PROXY
|
||||
HTTP_PROXY = http_proxy
|
||||
|
||||
def getProxy(http_proxy = None):
|
||||
"""get HTTP proxy"""
|
||||
return http_proxy or HTTP_PROXY
|
||||
|
||||
def getProxies(http_proxy = None):
|
||||
http_proxy = getProxy(http_proxy)
|
||||
if http_proxy:
|
||||
proxies = {"http": http_proxy}
|
||||
else:
|
||||
proxies = None
|
||||
return proxies
|
||||
|
||||
def _contentsOf(dirname, filename):
|
||||
filename = os.path.join(dirname, filename)
|
||||
if not os.path.exists(filename): return None
|
||||
fsock = open(filename)
|
||||
contents = fsock.read()
|
||||
fsock.close()
|
||||
return contents
|
||||
|
||||
def _getScriptDir():
|
||||
if __name__ == '__main__':
|
||||
return os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
else:
|
||||
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
|
||||
|
||||
class Bag: pass
|
||||
|
||||
def unmarshal(element):
|
||||
rc = Bag()
|
||||
if isinstance(element, minidom.Element) and (element.tagName == 'Details'):
|
||||
rc.URL = element.attributes["url"].value
|
||||
childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)]
|
||||
if childElements:
|
||||
for child in childElements:
|
||||
key = child.tagName
|
||||
if hasattr(rc, key):
|
||||
if type(getattr(rc, key)) <> type([]):
|
||||
setattr(rc, key, [getattr(rc, key)])
|
||||
setattr(rc, key, getattr(rc, key) + [unmarshal(child)])
|
||||
else:
|
||||
setattr(rc, key, unmarshal(child))
|
||||
else:
|
||||
rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)])
|
||||
if element.tagName == 'SalesRank':
|
||||
rc = int(rc.replace(',', ''))
|
||||
return rc
|
||||
|
||||
def buildURL(search_type, keyword, product_line, type, page, license_key):
|
||||
url = "http://xml.amazon.com/onca/xml?v=1.0&f=xml&t=webservices-20"
|
||||
url += "&dev-t=%s" % license_key.strip()
|
||||
url += "&type=%s" % type
|
||||
if page:
|
||||
url += "&page=%s" % page
|
||||
if product_line:
|
||||
url += "&mode=%s" % product_line
|
||||
url += "&%s=%s" % (search_type, urllib.quote(keyword))
|
||||
# print url
|
||||
return url
|
||||
|
||||
## main functions
|
||||
def search(search_type, keyword, product_line, type="heavy", page=None,
|
||||
license_key = None, http_proxy = None):
|
||||
"""search Amazon
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.amazon.com/webservices
|
||||
to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
keyword - keyword to search
|
||||
search_type - in (KeywordSearch, BrowseNodeSearch, AsinSearch, UpcSearch, AuthorSearch, ArtistSearch, ActorSearch, DirectorSearch, ManufacturerSearch, ListManiaSearch, SimilaritySearch)
|
||||
product_line - type of product to search for. restrictions based on search_type
|
||||
UpcSearch - in (music, classical)
|
||||
AuthorSearch - must be "books"
|
||||
ArtistSearch - in (music, classical)
|
||||
ActorSearch - in (dvd, vhs, video)
|
||||
DirectorSearch - in (dvd, vhs, video)
|
||||
ManufacturerSearch - in (electronics, kitchen, videogames, software, photo, pc-hardware)
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: list of Bags, each Bag may contain the following attributes:
|
||||
Asin - Amazon ID ("ASIN" number) of this item
|
||||
Authors - list of authors
|
||||
Availability - "available", etc.
|
||||
BrowseList - list of related categories
|
||||
Catalog - catalog type ("Book", etc)
|
||||
CollectiblePrice - ?, format "$34.95"
|
||||
ImageUrlLarge - URL of large image of this item
|
||||
ImageUrlMedium - URL of medium image of this item
|
||||
ImageUrlSmall - URL of small image of this item
|
||||
Isbn - ISBN number
|
||||
ListPrice - list price, format "$34.95"
|
||||
Lists - list of ListMania lists that include this item
|
||||
Manufacturer - manufacturer
|
||||
Media - media ("Paperback", "Audio CD", etc)
|
||||
NumMedia - number of different media types in which this item is available
|
||||
OurPrice - Amazon price, format "$24.47"
|
||||
ProductName - name of this item
|
||||
ReleaseDate - release date, format "09 April, 1999"
|
||||
Reviews - reviews (AvgCustomerRating, plus list of CustomerReview with Rating, Summary, Content)
|
||||
SalesRank - sales rank (integer)
|
||||
SimilarProducts - list of Product, which is ASIN number
|
||||
ThirdPartyNewPrice - ?, format "$34.95"
|
||||
URL - URL of this item
|
||||
"""
|
||||
license_key = getLicense(license_key)
|
||||
url = buildURL(search_type, keyword, product_line, type, page, license_key)
|
||||
proxies = getProxies(http_proxy)
|
||||
u = urllib.FancyURLopener(proxies)
|
||||
usock = u.open(url)
|
||||
xmldoc = minidom.parse(usock)
|
||||
usock.close()
|
||||
data = unmarshal(xmldoc).ProductInfo
|
||||
if hasattr(data, 'ErrorMsg'):
|
||||
raise AmazonError, data.ErrorMsg
|
||||
else:
|
||||
return data.Details
|
||||
|
||||
def searchByKeyword(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("KeywordSearch", keyword, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def browseBestSellers(browse_node, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("BrowseNodeSearch", browse_node, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByASIN(ASIN, type="heavy", license_key=None, http_proxy=None):
|
||||
return search("AsinSearch", ASIN, None, type, None, license_key, http_proxy)
|
||||
|
||||
def searchByUPC(UPC, type="heavy", license_key=None, http_proxy=None):
|
||||
return search("UpcSearch", UPC, None, type, None, license_key, http_proxy)
|
||||
|
||||
def searchByAuthor(author, type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("AuthorSearch", author, "books", type, page, license_key, http_proxy)
|
||||
|
||||
def searchByArtist(artist, product_line="music", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
if product_line not in ("music", "classical"):
|
||||
raise AmazonError, "product_line must be in ('music', 'classical')"
|
||||
return search("ArtistSearch", artist, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByActor(actor, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
if product_line not in ("dvd", "vhs", "video"):
|
||||
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
|
||||
return search("ActorSearch", actor, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByDirector(director, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
if product_line not in ("dvd", "vhs", "video"):
|
||||
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
|
||||
return search("DirectorSearch", director, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByManufacturer(manufacturer, product_line="pc-hardware", type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
if product_line not in ("electronics", "kitchen", "videogames", "software", "photo", "pc-hardware"):
|
||||
raise AmazonError, "product_line must be in ('electronics', 'kitchen', 'videogames', 'software', 'photo', 'pc-hardware')"
|
||||
return search("ManufacturerSearch", manufacturer, product_line, type, page, license_key, http_proxy)
|
||||
|
||||
def searchByListMania(listManiaID, type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("ListManiaSearch", listManiaID, None, type, page, license_key, http_proxy)
|
||||
|
||||
def searchSimilar(ASIN, type="heavy", page=1, license_key=None, http_proxy=None):
|
||||
return search("SimilaritySearch", ASIN, None, type, page, license_key, http_proxy)
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
866
others/google.py
866
others/google.py
@ -1,433 +1,433 @@
|
||||
"""Python wrapper for Google web APIs
|
||||
|
||||
This module allows you to access Google's web APIs through SOAP,
|
||||
to do things like search Google and get the results programmatically.
|
||||
Described here:
|
||||
http://www.google.com/apis/
|
||||
|
||||
You need a Google-provided license key to use these services.
|
||||
Follow the link above to get one. These functions will look in
|
||||
several places (in this order) for the license key:
|
||||
- the "license_key" argument of each function
|
||||
- the module-level LICENSE_KEY variable (call setLicense once to set it)
|
||||
- an environment variable called GOOGLE_LICENSE_KEY
|
||||
- a file called ".googlekey" in the current directory
|
||||
- a file called "googlekey.txt" in the current directory
|
||||
- a file called ".googlekey" in your home directory
|
||||
- a file called "googlekey.txt" in your home directory
|
||||
- a file called ".googlekey" in the same directory as google.py
|
||||
- a file called "googlekey.txt" in the same directory as google.py
|
||||
|
||||
Sample usage:
|
||||
>>> import google
|
||||
>>> google.setLicense('...') # must get your own key!
|
||||
>>> data = google.doGoogleSearch('python')
|
||||
>>> data.meta.searchTime
|
||||
0.043221000000000002
|
||||
>>> data.results[0].URL
|
||||
'http://www.python.org/'
|
||||
>>> data.results[0].title
|
||||
'<b>Python</b> Language Website'
|
||||
|
||||
See documentation of SearchResultsMetaData and SearchResult classes
|
||||
for other available attributes.
|
||||
"""
|
||||
|
||||
__author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
|
||||
__version__ = "0.5.2"
|
||||
__cvsversion__ = "$Revision$"[11:-2]
|
||||
__date__ = "$Date$"[7:-2]
|
||||
__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
|
||||
__license__ = "Python"
|
||||
__credits__ = """David Ascher, for the install script
|
||||
Erik Max Francis, for the command line interface
|
||||
Michael Twomey, for HTTP proxy support"""
|
||||
|
||||
import SOAP
|
||||
import os, sys, getopt
|
||||
|
||||
LICENSE_KEY = None
|
||||
HTTP_PROXY = None
|
||||
|
||||
# don't touch the rest of these constants
|
||||
class NoLicenseKey(Exception): pass
|
||||
_url = 'http://api.google.com/search/beta2'
|
||||
_namespace = 'urn:GoogleSearch'
|
||||
_false = SOAP.booleanType(0)
|
||||
_true = SOAP.booleanType(1)
|
||||
_googlefile1 = ".googlekey"
|
||||
_googlefile2 = "googlekey.txt"
|
||||
_licenseLocations = (
|
||||
(lambda key: key, 'passed to the function in license_key variable'),
|
||||
(lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'),
|
||||
(lambda key: os.environ.get('GOOGLE_LICENSE_KEY', None), 'an environment variable called GOOGLE_LICENSE_KEY'),
|
||||
(lambda key: _contentsOf(os.getcwd(), _googlefile1), '%s in the current directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(os.getcwd(), _googlefile2), '%s in the current directory' % _googlefile2),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _googlefile1), '%s in your home directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _googlefile2), '%s in your home directory' % _googlefile2),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _googlefile1), '%s in the google.py directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _googlefile2), '%s in the google.py directory' % _googlefile2)
|
||||
)
|
||||
|
||||
## administrative functions
|
||||
def version():
|
||||
print """PyGoogle %(__version__)s
|
||||
%(__copyright__)s
|
||||
released %(__date__)s
|
||||
|
||||
Thanks to:
|
||||
%(__credits__)s""" % globals()
|
||||
|
||||
def usage():
|
||||
program = os.path.basename(sys.argv[0])
|
||||
print """Usage: %(program)s [options] [querytype] query
|
||||
|
||||
options:
|
||||
-k, --key= <license key> Google license key (see important note below)
|
||||
-1, -l, --lucky show only first hit
|
||||
-m, --meta show meta information
|
||||
-r, --reverse show results in reverse order
|
||||
-x, --proxy= <url> use HTTP proxy
|
||||
-h, --help print this help
|
||||
-v, --version print version and copyright information
|
||||
-t, --test run test queries
|
||||
|
||||
querytype:
|
||||
-s, --search= <query> search (default)
|
||||
-c, --cache= <url> retrieve cached page
|
||||
-p, --spelling= <word> check spelling
|
||||
|
||||
IMPORTANT NOTE: all Google functions require a valid license key;
|
||||
visit http://www.google.com/apis/ to get one. %(program)s will look in
|
||||
these places (in order) and use the first license key it finds:
|
||||
* the key specified on the command line""" % vars()
|
||||
for get, location in _licenseLocations[2:]:
|
||||
print " *", location
|
||||
|
||||
## utility functions
|
||||
def setLicense(license_key):
|
||||
"""set license key"""
|
||||
global LICENSE_KEY
|
||||
LICENSE_KEY = license_key
|
||||
|
||||
def getLicense(license_key = None):
|
||||
"""get license key
|
||||
|
||||
license key can come from any number of locations;
|
||||
see module docs for search order"""
|
||||
for get, location in _licenseLocations:
|
||||
rc = get(license_key)
|
||||
if rc: return rc
|
||||
usage()
|
||||
raise NoLicenseKey, 'get a license key at http://www.google.com/apis/'
|
||||
|
||||
def setProxy(http_proxy):
|
||||
"""set HTTP proxy"""
|
||||
global HTTP_PROXY
|
||||
HTTP_PROXY = http_proxy
|
||||
|
||||
def getProxy(http_proxy = None):
|
||||
"""get HTTP proxy"""
|
||||
return http_proxy or HTTP_PROXY
|
||||
|
||||
def _contentsOf(dirname, filename):
|
||||
filename = os.path.join(dirname, filename)
|
||||
if not os.path.exists(filename): return None
|
||||
fsock = open(filename)
|
||||
contents = fsock.read()
|
||||
fsock.close()
|
||||
return contents
|
||||
|
||||
def _getScriptDir():
|
||||
if __name__ == '__main__':
|
||||
return os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
else:
|
||||
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
|
||||
|
||||
def _marshalBoolean(value):
|
||||
if value:
|
||||
return _true
|
||||
else:
|
||||
return _false
|
||||
|
||||
## output formatters
|
||||
def makeFormatter(outputFormat):
|
||||
classname = "%sOutputFormatter" % outputFormat.capitalize()
|
||||
return globals()[classname]()
|
||||
|
||||
def output(results, params):
|
||||
formatter = makeFormatter(params.get("outputFormat", "text"))
|
||||
outputmethod = getattr(formatter, params["func"])
|
||||
outputmethod(results, params)
|
||||
|
||||
class OutputFormatter:
|
||||
def boil(self, data):
|
||||
if type(data) == type(u""):
|
||||
return data.encode("ISO-8859-1", "replace")
|
||||
else:
|
||||
return data
|
||||
|
||||
class TextOutputFormatter(OutputFormatter):
|
||||
def common(self, data, params):
|
||||
if params.get("showMeta", 0):
|
||||
meta = data.meta
|
||||
for category in meta.directoryCategories:
|
||||
print "directoryCategory: %s" % self.boil(category["fullViewableName"])
|
||||
for attr in [node for node in dir(meta) if node <> "directoryCategories" and node[:2] <> '__']:
|
||||
print "%s:" % attr, self.boil(getattr(meta, attr))
|
||||
|
||||
def doGoogleSearch(self, data, params):
|
||||
results = data.results
|
||||
if params.get("feelingLucky", 0):
|
||||
results = results[:1]
|
||||
if params.get("reverseOrder", 0):
|
||||
results.reverse()
|
||||
for result in results:
|
||||
for attr in dir(result):
|
||||
if attr == "directoryCategory":
|
||||
print "directoryCategory:", self.boil(result.directoryCategory["fullViewableName"])
|
||||
elif attr[:2] <> '__':
|
||||
print "%s:" % attr, self.boil(getattr(result, attr))
|
||||
print
|
||||
self.common(data, params)
|
||||
|
||||
def doGetCachedPage(self, data, params):
|
||||
print data
|
||||
self.common(data, params)
|
||||
|
||||
doSpellingSuggestion = doGetCachedPage
|
||||
|
||||
## search results classes
|
||||
class _SearchBase:
|
||||
def __init__(self, params):
|
||||
for k, v in params.items():
|
||||
if isinstance(v, SOAP.structType):
|
||||
v = v._asdict
|
||||
try:
|
||||
if isinstance(v[0], SOAP.structType):
|
||||
v = [node._asdict for node in v]
|
||||
except:
|
||||
pass
|
||||
self.__dict__[str(k)] = v
|
||||
|
||||
class SearchResultsMetaData(_SearchBase):
|
||||
"""metadata of search query results
|
||||
|
||||
Available attributes:
|
||||
documentFiltering - flag indicates whether duplicate page filtering was perfomed in this search
|
||||
searchComments - human-readable informational message (example: "'the' is a very common word
|
||||
and was not included in your search")
|
||||
estimatedTotalResultsCount - estimated total number of results for this query
|
||||
estimateIsExact - flag indicates whether estimatedTotalResultsCount is an exact value
|
||||
searchQuery - search string that initiated this search
|
||||
startIndex - index of first result returned (zero-based)
|
||||
endIndex - index of last result returned (zero-based)
|
||||
searchTips - human-readable informational message on how to use Google bette
|
||||
directoryCategories - list of dictionaries like this:
|
||||
{'fullViewableName': Open Directory category,
|
||||
'specialEncoding': encoding scheme of this directory category}
|
||||
searchTime - total search time, in seconds
|
||||
"""
|
||||
pass
|
||||
|
||||
class SearchResult(_SearchBase):
|
||||
"""search result
|
||||
|
||||
Available attributes:
|
||||
URL - URL
|
||||
title - title (HTML)
|
||||
snippet - snippet showing query context (HTML)
|
||||
cachedSize - size of cached version of this result, (KB)
|
||||
relatedInformationPresent - flag indicates that the "related:" keyword is supported for this URL
|
||||
hostName: When filtering occurs, a maximum of two results from any given host is returned.
|
||||
When this occurs, the second resultElement that comes from that host contains
|
||||
the host name in this parameter.
|
||||
directoryCategory: dictionary like this:
|
||||
{'fullViewableName': Open Directory category,
|
||||
'specialEncoding': encoding scheme of this directory category}
|
||||
directoryTitle: Open Directory title of this result (or blank)
|
||||
summary - Open Directory summary for this result (or blank)
|
||||
"""
|
||||
pass
|
||||
|
||||
class SearchReturnValue:
|
||||
"""complete search results for a single query
|
||||
|
||||
Available attributes:
|
||||
meta - SearchResultsMetaData
|
||||
results - list of SearchResult
|
||||
"""
|
||||
def __init__(self, metadata, results):
|
||||
self.meta = metadata
|
||||
self.results = results
|
||||
|
||||
## main functions
|
||||
def doGoogleSearch(q, start=0, maxResults=10, filter=1, restrict='',
|
||||
safeSearch=0, language='', inputencoding='', outputencoding='',
|
||||
license_key = None, http_proxy = None):
|
||||
"""search Google
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
q - search string. Anything you could type at google.com, you can pass here.
|
||||
See http://www.google.com/help/features.html for examples of advanced features.
|
||||
start (optional) - zero-based index of first desired result (for paging through
|
||||
multiple pages of results)
|
||||
maxResults (optional) - maximum number of results, currently capped at 10
|
||||
filter (optional) - set to 1 to filter out similar results, set to 0 to see everything
|
||||
restrict (optional) - restrict results by country or topic. Examples:
|
||||
Ukraine - search only sites located in Ukraine
|
||||
linux - search Linux sites only
|
||||
mac - search Mac sites only
|
||||
bsd - search FreeBSD sites only
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for more advanced examples and a full list of country codes and topics.
|
||||
safeSearch (optional) - set to 1 to filter results with SafeSearch (no adult material)
|
||||
language (optional) - restricts search to documents in one or more languages. Example:
|
||||
lang_en - only return pages in English
|
||||
lang_fr - only return pages in French
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for more advanced examples and a full list of language codes.
|
||||
inputencoding (optional) - sets the character encoding of q parameter
|
||||
outputencoding (optional) - sets the character encoding of the returned results
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for a full list of encodings.
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: SearchReturnValue
|
||||
.meta - SearchMetaData
|
||||
.results - list of SearchResult
|
||||
See documentation of these individual classes for list of available attributes
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
filter = _marshalBoolean(filter)
|
||||
safeSearch = _marshalBoolean(safeSearch)
|
||||
data = remoteserver.doGoogleSearch(license_key, q, start, maxResults, filter, restrict,
|
||||
safeSearch, language, inputencoding, outputencoding)
|
||||
metadata = data._asdict
|
||||
del metadata["resultElements"]
|
||||
metadata = SearchResultsMetaData(metadata)
|
||||
results = [SearchResult(node._asdict) for node in data.resultElements]
|
||||
return SearchReturnValue(metadata, results)
|
||||
|
||||
def doGetCachedPage(url, license_key = None, http_proxy = None):
|
||||
"""get page from Google cache
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
url - address of page to get
|
||||
license_key (optional) - Google license key
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: string, text of cached page
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
return remoteserver.doGetCachedPage(license_key, url)
|
||||
|
||||
def doSpellingSuggestion(phrase, license_key = None, http_proxy = None):
|
||||
"""get spelling suggestions from Google
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
phrase - word or phrase to spell-check
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: text of suggested replacement, or None
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
return remoteserver.doSpellingSuggestion(license_key, phrase)
|
||||
|
||||
## functional test suite (see googletest.py for unit test suite)
|
||||
def test():
|
||||
try:
|
||||
getLicense(None)
|
||||
except NoLicenseKey:
|
||||
return
|
||||
print "Searching for Python at google.com..."
|
||||
data = doGoogleSearch("Python")
|
||||
output(data, {"func": "doGoogleSearch"})
|
||||
|
||||
print "\nSearching for 5 _French_ pages about Python, encoded in ISO-8859-1..."
|
||||
data = doGoogleSearch("Python", language='lang_fr', outputencoding='ISO-8859-1', maxResults=5)
|
||||
output(data, {"func": "doGoogleSearch"})
|
||||
|
||||
phrase = "Pyhton programming languager"
|
||||
print "\nTesting spelling suggetions for '%s'..." % phrase
|
||||
data = doSpellingSuggestion(phrase)
|
||||
output(data, {"func": "doSpellingSuggestion"})
|
||||
|
||||
## main driver for command-line use
|
||||
def main(argv):
|
||||
if not argv:
|
||||
usage()
|
||||
return
|
||||
q = None
|
||||
func = None
|
||||
http_proxy = None
|
||||
license_key = None
|
||||
feelingLucky = 0
|
||||
showMeta = 0
|
||||
reverseOrder = 0
|
||||
runTest = 0
|
||||
outputFormat = "text"
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, "s:c:p:k:lmrx:hvt1",
|
||||
["search=", "cache=", "spelling=", "key=", "lucky", "meta", "reverse", "proxy=", "help", "version", "test"])
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
for opt, arg in opts:
|
||||
if opt in ("-s", "--search"):
|
||||
q = arg
|
||||
func = "doGoogleSearch"
|
||||
elif opt in ("-c", "--cache"):
|
||||
q = arg
|
||||
func = "doGetCachedPage"
|
||||
elif opt in ("-p", "--spelling"):
|
||||
q = arg
|
||||
func = "doSpellingSuggestion"
|
||||
elif opt in ("-k", "--key"):
|
||||
license_key = arg
|
||||
elif opt in ("-l", "-1", "--lucky"):
|
||||
feelingLucky = 1
|
||||
elif opt in ("-m", "--meta"):
|
||||
showMeta = 1
|
||||
elif opt in ("-r", "--reverse"):
|
||||
reverseOrder = 1
|
||||
elif opt in ("-x", "--proxy"):
|
||||
http_proxy = arg
|
||||
elif opt in ("-h", "--help"):
|
||||
usage()
|
||||
elif opt in ("-v", "--version"):
|
||||
version()
|
||||
elif opt in ("-t", "--test"):
|
||||
runTest = 1
|
||||
if runTest:
|
||||
setLicense(license_key)
|
||||
setProxy(http_proxy)
|
||||
test()
|
||||
if args and not q:
|
||||
q = args[0]
|
||||
func = "doGoogleSearch"
|
||||
if func:
|
||||
results = globals()[func](q, http_proxy=http_proxy, license_key=license_key)
|
||||
output(results, locals())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
"""Python wrapper for Google web APIs
|
||||
|
||||
This module allows you to access Google's web APIs through SOAP,
|
||||
to do things like search Google and get the results programmatically.
|
||||
Described here:
|
||||
http://www.google.com/apis/
|
||||
|
||||
You need a Google-provided license key to use these services.
|
||||
Follow the link above to get one. These functions will look in
|
||||
several places (in this order) for the license key:
|
||||
- the "license_key" argument of each function
|
||||
- the module-level LICENSE_KEY variable (call setLicense once to set it)
|
||||
- an environment variable called GOOGLE_LICENSE_KEY
|
||||
- a file called ".googlekey" in the current directory
|
||||
- a file called "googlekey.txt" in the current directory
|
||||
- a file called ".googlekey" in your home directory
|
||||
- a file called "googlekey.txt" in your home directory
|
||||
- a file called ".googlekey" in the same directory as google.py
|
||||
- a file called "googlekey.txt" in the same directory as google.py
|
||||
|
||||
Sample usage:
|
||||
>>> import google
|
||||
>>> google.setLicense('...') # must get your own key!
|
||||
>>> data = google.doGoogleSearch('python')
|
||||
>>> data.meta.searchTime
|
||||
0.043221000000000002
|
||||
>>> data.results[0].URL
|
||||
'http://www.python.org/'
|
||||
>>> data.results[0].title
|
||||
'<b>Python</b> Language Website'
|
||||
|
||||
See documentation of SearchResultsMetaData and SearchResult classes
|
||||
for other available attributes.
|
||||
"""
|
||||
|
||||
__author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
|
||||
__version__ = "0.5.2"
|
||||
__cvsversion__ = "$Revision$"[11:-2]
|
||||
__date__ = "$Date$"[7:-2]
|
||||
__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
|
||||
__license__ = "Python"
|
||||
__credits__ = """David Ascher, for the install script
|
||||
Erik Max Francis, for the command line interface
|
||||
Michael Twomey, for HTTP proxy support"""
|
||||
|
||||
import SOAP
|
||||
import os, sys, getopt
|
||||
|
||||
LICENSE_KEY = None
|
||||
HTTP_PROXY = None
|
||||
|
||||
# don't touch the rest of these constants
|
||||
class NoLicenseKey(Exception): pass
|
||||
_url = 'http://api.google.com/search/beta2'
|
||||
_namespace = 'urn:GoogleSearch'
|
||||
_false = SOAP.booleanType(0)
|
||||
_true = SOAP.booleanType(1)
|
||||
_googlefile1 = ".googlekey"
|
||||
_googlefile2 = "googlekey.txt"
|
||||
_licenseLocations = (
|
||||
(lambda key: key, 'passed to the function in license_key variable'),
|
||||
(lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'),
|
||||
(lambda key: os.environ.get('GOOGLE_LICENSE_KEY', None), 'an environment variable called GOOGLE_LICENSE_KEY'),
|
||||
(lambda key: _contentsOf(os.getcwd(), _googlefile1), '%s in the current directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(os.getcwd(), _googlefile2), '%s in the current directory' % _googlefile2),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _googlefile1), '%s in your home directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _googlefile2), '%s in your home directory' % _googlefile2),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _googlefile1), '%s in the google.py directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _googlefile2), '%s in the google.py directory' % _googlefile2)
|
||||
)
|
||||
|
||||
## administrative functions
|
||||
def version():
|
||||
print """PyGoogle %(__version__)s
|
||||
%(__copyright__)s
|
||||
released %(__date__)s
|
||||
|
||||
Thanks to:
|
||||
%(__credits__)s""" % globals()
|
||||
|
||||
def usage():
|
||||
program = os.path.basename(sys.argv[0])
|
||||
print """Usage: %(program)s [options] [querytype] query
|
||||
|
||||
options:
|
||||
-k, --key= <license key> Google license key (see important note below)
|
||||
-1, -l, --lucky show only first hit
|
||||
-m, --meta show meta information
|
||||
-r, --reverse show results in reverse order
|
||||
-x, --proxy= <url> use HTTP proxy
|
||||
-h, --help print this help
|
||||
-v, --version print version and copyright information
|
||||
-t, --test run test queries
|
||||
|
||||
querytype:
|
||||
-s, --search= <query> search (default)
|
||||
-c, --cache= <url> retrieve cached page
|
||||
-p, --spelling= <word> check spelling
|
||||
|
||||
IMPORTANT NOTE: all Google functions require a valid license key;
|
||||
visit http://www.google.com/apis/ to get one. %(program)s will look in
|
||||
these places (in order) and use the first license key it finds:
|
||||
* the key specified on the command line""" % vars()
|
||||
for get, location in _licenseLocations[2:]:
|
||||
print " *", location
|
||||
|
||||
## utility functions
|
||||
def setLicense(license_key):
|
||||
"""set license key"""
|
||||
global LICENSE_KEY
|
||||
LICENSE_KEY = license_key
|
||||
|
||||
def getLicense(license_key = None):
|
||||
"""get license key
|
||||
|
||||
license key can come from any number of locations;
|
||||
see module docs for search order"""
|
||||
for get, location in _licenseLocations:
|
||||
rc = get(license_key)
|
||||
if rc: return rc
|
||||
usage()
|
||||
raise NoLicenseKey, 'get a license key at http://www.google.com/apis/'
|
||||
|
||||
def setProxy(http_proxy):
|
||||
"""set HTTP proxy"""
|
||||
global HTTP_PROXY
|
||||
HTTP_PROXY = http_proxy
|
||||
|
||||
def getProxy(http_proxy = None):
|
||||
"""get HTTP proxy"""
|
||||
return http_proxy or HTTP_PROXY
|
||||
|
||||
def _contentsOf(dirname, filename):
|
||||
filename = os.path.join(dirname, filename)
|
||||
if not os.path.exists(filename): return None
|
||||
fsock = open(filename)
|
||||
contents = fsock.read()
|
||||
fsock.close()
|
||||
return contents
|
||||
|
||||
def _getScriptDir():
|
||||
if __name__ == '__main__':
|
||||
return os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
else:
|
||||
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
|
||||
|
||||
def _marshalBoolean(value):
|
||||
if value:
|
||||
return _true
|
||||
else:
|
||||
return _false
|
||||
|
||||
## output formatters
|
||||
def makeFormatter(outputFormat):
|
||||
classname = "%sOutputFormatter" % outputFormat.capitalize()
|
||||
return globals()[classname]()
|
||||
|
||||
def output(results, params):
|
||||
formatter = makeFormatter(params.get("outputFormat", "text"))
|
||||
outputmethod = getattr(formatter, params["func"])
|
||||
outputmethod(results, params)
|
||||
|
||||
class OutputFormatter:
|
||||
def boil(self, data):
|
||||
if type(data) == type(u""):
|
||||
return data.encode("ISO-8859-1", "replace")
|
||||
else:
|
||||
return data
|
||||
|
||||
class TextOutputFormatter(OutputFormatter):
|
||||
def common(self, data, params):
|
||||
if params.get("showMeta", 0):
|
||||
meta = data.meta
|
||||
for category in meta.directoryCategories:
|
||||
print "directoryCategory: %s" % self.boil(category["fullViewableName"])
|
||||
for attr in [node for node in dir(meta) if node <> "directoryCategories" and node[:2] <> '__']:
|
||||
print "%s:" % attr, self.boil(getattr(meta, attr))
|
||||
|
||||
def doGoogleSearch(self, data, params):
|
||||
results = data.results
|
||||
if params.get("feelingLucky", 0):
|
||||
results = results[:1]
|
||||
if params.get("reverseOrder", 0):
|
||||
results.reverse()
|
||||
for result in results:
|
||||
for attr in dir(result):
|
||||
if attr == "directoryCategory":
|
||||
print "directoryCategory:", self.boil(result.directoryCategory["fullViewableName"])
|
||||
elif attr[:2] <> '__':
|
||||
print "%s:" % attr, self.boil(getattr(result, attr))
|
||||
print
|
||||
self.common(data, params)
|
||||
|
||||
def doGetCachedPage(self, data, params):
|
||||
print data
|
||||
self.common(data, params)
|
||||
|
||||
doSpellingSuggestion = doGetCachedPage
|
||||
|
||||
## search results classes
|
||||
class _SearchBase:
|
||||
def __init__(self, params):
|
||||
for k, v in params.items():
|
||||
if isinstance(v, SOAP.structType):
|
||||
v = v._asdict
|
||||
try:
|
||||
if isinstance(v[0], SOAP.structType):
|
||||
v = [node._asdict for node in v]
|
||||
except:
|
||||
pass
|
||||
self.__dict__[str(k)] = v
|
||||
|
||||
class SearchResultsMetaData(_SearchBase):
|
||||
"""metadata of search query results
|
||||
|
||||
Available attributes:
|
||||
documentFiltering - flag indicates whether duplicate page filtering was perfomed in this search
|
||||
searchComments - human-readable informational message (example: "'the' is a very common word
|
||||
and was not included in your search")
|
||||
estimatedTotalResultsCount - estimated total number of results for this query
|
||||
estimateIsExact - flag indicates whether estimatedTotalResultsCount is an exact value
|
||||
searchQuery - search string that initiated this search
|
||||
startIndex - index of first result returned (zero-based)
|
||||
endIndex - index of last result returned (zero-based)
|
||||
searchTips - human-readable informational message on how to use Google bette
|
||||
directoryCategories - list of dictionaries like this:
|
||||
{'fullViewableName': Open Directory category,
|
||||
'specialEncoding': encoding scheme of this directory category}
|
||||
searchTime - total search time, in seconds
|
||||
"""
|
||||
pass
|
||||
|
||||
class SearchResult(_SearchBase):
|
||||
"""search result
|
||||
|
||||
Available attributes:
|
||||
URL - URL
|
||||
title - title (HTML)
|
||||
snippet - snippet showing query context (HTML)
|
||||
cachedSize - size of cached version of this result, (KB)
|
||||
relatedInformationPresent - flag indicates that the "related:" keyword is supported for this URL
|
||||
hostName: When filtering occurs, a maximum of two results from any given host is returned.
|
||||
When this occurs, the second resultElement that comes from that host contains
|
||||
the host name in this parameter.
|
||||
directoryCategory: dictionary like this:
|
||||
{'fullViewableName': Open Directory category,
|
||||
'specialEncoding': encoding scheme of this directory category}
|
||||
directoryTitle: Open Directory title of this result (or blank)
|
||||
summary - Open Directory summary for this result (or blank)
|
||||
"""
|
||||
pass
|
||||
|
||||
class SearchReturnValue:
|
||||
"""complete search results for a single query
|
||||
|
||||
Available attributes:
|
||||
meta - SearchResultsMetaData
|
||||
results - list of SearchResult
|
||||
"""
|
||||
def __init__(self, metadata, results):
|
||||
self.meta = metadata
|
||||
self.results = results
|
||||
|
||||
## main functions
|
||||
def doGoogleSearch(q, start=0, maxResults=10, filter=1, restrict='',
|
||||
safeSearch=0, language='', inputencoding='', outputencoding='',
|
||||
license_key = None, http_proxy = None):
|
||||
"""search Google
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
q - search string. Anything you could type at google.com, you can pass here.
|
||||
See http://www.google.com/help/features.html for examples of advanced features.
|
||||
start (optional) - zero-based index of first desired result (for paging through
|
||||
multiple pages of results)
|
||||
maxResults (optional) - maximum number of results, currently capped at 10
|
||||
filter (optional) - set to 1 to filter out similar results, set to 0 to see everything
|
||||
restrict (optional) - restrict results by country or topic. Examples:
|
||||
Ukraine - search only sites located in Ukraine
|
||||
linux - search Linux sites only
|
||||
mac - search Mac sites only
|
||||
bsd - search FreeBSD sites only
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for more advanced examples and a full list of country codes and topics.
|
||||
safeSearch (optional) - set to 1 to filter results with SafeSearch (no adult material)
|
||||
language (optional) - restricts search to documents in one or more languages. Example:
|
||||
lang_en - only return pages in English
|
||||
lang_fr - only return pages in French
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for more advanced examples and a full list of language codes.
|
||||
inputencoding (optional) - sets the character encoding of q parameter
|
||||
outputencoding (optional) - sets the character encoding of the returned results
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for a full list of encodings.
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: SearchReturnValue
|
||||
.meta - SearchMetaData
|
||||
.results - list of SearchResult
|
||||
See documentation of these individual classes for list of available attributes
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
filter = _marshalBoolean(filter)
|
||||
safeSearch = _marshalBoolean(safeSearch)
|
||||
data = remoteserver.doGoogleSearch(license_key, q, start, maxResults, filter, restrict,
|
||||
safeSearch, language, inputencoding, outputencoding)
|
||||
metadata = data._asdict
|
||||
del metadata["resultElements"]
|
||||
metadata = SearchResultsMetaData(metadata)
|
||||
results = [SearchResult(node._asdict) for node in data.resultElements]
|
||||
return SearchReturnValue(metadata, results)
|
||||
|
||||
def doGetCachedPage(url, license_key = None, http_proxy = None):
|
||||
"""get page from Google cache
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
url - address of page to get
|
||||
license_key (optional) - Google license key
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: string, text of cached page
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
return remoteserver.doGetCachedPage(license_key, url)
|
||||
|
||||
def doSpellingSuggestion(phrase, license_key = None, http_proxy = None):
|
||||
"""get spelling suggestions from Google
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
phrase - word or phrase to spell-check
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: text of suggested replacement, or None
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
return remoteserver.doSpellingSuggestion(license_key, phrase)
|
||||
|
||||
## functional test suite (see googletest.py for unit test suite)
|
||||
def test():
|
||||
try:
|
||||
getLicense(None)
|
||||
except NoLicenseKey:
|
||||
return
|
||||
print "Searching for Python at google.com..."
|
||||
data = doGoogleSearch("Python")
|
||||
output(data, {"func": "doGoogleSearch"})
|
||||
|
||||
print "\nSearching for 5 _French_ pages about Python, encoded in ISO-8859-1..."
|
||||
data = doGoogleSearch("Python", language='lang_fr', outputencoding='ISO-8859-1', maxResults=5)
|
||||
output(data, {"func": "doGoogleSearch"})
|
||||
|
||||
phrase = "Pyhton programming languager"
|
||||
print "\nTesting spelling suggetions for '%s'..." % phrase
|
||||
data = doSpellingSuggestion(phrase)
|
||||
output(data, {"func": "doSpellingSuggestion"})
|
||||
|
||||
## main driver for command-line use
|
||||
def main(argv):
|
||||
if not argv:
|
||||
usage()
|
||||
return
|
||||
q = None
|
||||
func = None
|
||||
http_proxy = None
|
||||
license_key = None
|
||||
feelingLucky = 0
|
||||
showMeta = 0
|
||||
reverseOrder = 0
|
||||
runTest = 0
|
||||
outputFormat = "text"
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, "s:c:p:k:lmrx:hvt1",
|
||||
["search=", "cache=", "spelling=", "key=", "lucky", "meta", "reverse", "proxy=", "help", "version", "test"])
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
for opt, arg in opts:
|
||||
if opt in ("-s", "--search"):
|
||||
q = arg
|
||||
func = "doGoogleSearch"
|
||||
elif opt in ("-c", "--cache"):
|
||||
q = arg
|
||||
func = "doGetCachedPage"
|
||||
elif opt in ("-p", "--spelling"):
|
||||
q = arg
|
||||
func = "doSpellingSuggestion"
|
||||
elif opt in ("-k", "--key"):
|
||||
license_key = arg
|
||||
elif opt in ("-l", "-1", "--lucky"):
|
||||
feelingLucky = 1
|
||||
elif opt in ("-m", "--meta"):
|
||||
showMeta = 1
|
||||
elif opt in ("-r", "--reverse"):
|
||||
reverseOrder = 1
|
||||
elif opt in ("-x", "--proxy"):
|
||||
http_proxy = arg
|
||||
elif opt in ("-h", "--help"):
|
||||
usage()
|
||||
elif opt in ("-v", "--version"):
|
||||
version()
|
||||
elif opt in ("-t", "--test"):
|
||||
runTest = 1
|
||||
if runTest:
|
||||
setLicense(license_key)
|
||||
setProxy(http_proxy)
|
||||
test()
|
||||
if args and not q:
|
||||
q = args[0]
|
||||
func = "doGoogleSearch"
|
||||
if func:
|
||||
results = globals()[func](q, http_proxy=http_proxy, license_key=license_key)
|
||||
output(results, locals())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -387,7 +387,7 @@ class Message:
|
||||
|
||||
def __contains__(self, name):
|
||||
return name.lower() in self.dict
|
||||
|
||||
|
||||
def __getitem__(self, name):
|
||||
"""Get a specific header, as from a dictionary."""
|
||||
return self.dict[name.lower()]
|
||||
|
1038
others/rssparser.py
1038
others/rssparser.py
File diff suppressed because it is too large
Load Diff
@ -263,7 +263,7 @@ class TestCase:
|
||||
def _fail(self, msg):
|
||||
"""Underlying implementation of failure."""
|
||||
raise self.failureException, msg
|
||||
|
||||
|
||||
def fail(self, msg=None):
|
||||
"""Fail immediately, with the given message."""
|
||||
global asserts
|
||||
|
@ -66,7 +66,7 @@ def findBiggestDollar(alias):
|
||||
return int(dollars[-1])
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def makeNewAlias(name, alias):
|
||||
if findAliasCommand(name, alias):
|
||||
raise RecursiveAlias
|
||||
@ -105,7 +105,7 @@ class Alias(callbacks.Privmsg):
|
||||
def __init__(self):
|
||||
callbacks.Privmsg.__init__(self)
|
||||
self.frozen = sets.Set()
|
||||
|
||||
|
||||
def freeze(self, irc, msg, args):
|
||||
"""<alias>
|
||||
|
||||
@ -133,7 +133,7 @@ class Alias(callbacks.Privmsg):
|
||||
else:
|
||||
irc.error(msg, 'There is no such alias.')
|
||||
unfreeze = privmsgs.checkCapability(unfreeze, 'admin')
|
||||
|
||||
|
||||
def alias(self, irc, msg, args):
|
||||
"""<name> <alias commands>
|
||||
|
||||
@ -164,7 +164,7 @@ class Alias(callbacks.Privmsg):
|
||||
print debug.exnToString(e)
|
||||
except:
|
||||
print 'exception raised'
|
||||
|
||||
|
||||
|
||||
def unalias(self, irc, msg, args):
|
||||
"""<name>
|
||||
@ -181,8 +181,8 @@ class Alias(callbacks.Privmsg):
|
||||
irc.error(msg, 'That alias is frozen.')
|
||||
else:
|
||||
irc.error(msg, 'There is no such alias.')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Class = Alias
|
||||
|
@ -111,7 +111,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler):
|
||||
)""")
|
||||
db.commit()
|
||||
return db
|
||||
|
||||
|
||||
def doPrivmsg(self, irc, msg):
|
||||
callbacks.PrivmsgCommandAndRegexp.doPrivmsg(self, irc, msg)
|
||||
if ircutils.isChannel(msg.args[0]):
|
||||
@ -174,7 +174,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler):
|
||||
except KeyError:
|
||||
pass
|
||||
db.commit()
|
||||
|
||||
|
||||
def doPart(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
db = self.getDb(channel)
|
||||
|
@ -30,7 +30,7 @@
|
||||
###
|
||||
|
||||
"""
|
||||
Handles standard CTCP responses to PING, TIME, SOURCE, VERSION, USERINFO,
|
||||
Handles standard CTCP responses to PING, TIME, SOURCE, VERSION, USERINFO,
|
||||
and FINGER.
|
||||
"""
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
###
|
||||
|
||||
"""
|
||||
Handles "factoids," little tidbits of information held in a database and
|
||||
Handles "factoids," little tidbits of information held in a database and
|
||||
available on demand via several commands.
|
||||
|
||||
Commands include:
|
||||
@ -59,7 +59,7 @@ class Factoids(ChannelDBHandler, callbacks.Privmsg):
|
||||
def __init__(self):
|
||||
ChannelDBHandler.__init__(self)
|
||||
callbacks.Privmsg.__init__(self)
|
||||
|
||||
|
||||
def makeDb(self, filename):
|
||||
if os.path.exists(filename):
|
||||
return sqlite.connect(filename)
|
||||
@ -120,7 +120,7 @@ class Factoids(ChannelDBHandler, callbacks.Privmsg):
|
||||
irc.reply(msg, conf.replySuccess)
|
||||
else:
|
||||
irc.error(msg, 'That factoid is locked.')
|
||||
|
||||
|
||||
def lookup(self, irc, msg, args):
|
||||
"[<channel>] (If not sent in the channel itself) <key> [<number>]"
|
||||
channel = privmsgs.getChannel(msg, args)
|
||||
@ -141,7 +141,7 @@ class Factoids(ChannelDBHandler, callbacks.Privmsg):
|
||||
else:
|
||||
factoid = results[number][0]
|
||||
irc.reply(msg, '%s/%s: %s' % (key, number, factoid))
|
||||
|
||||
|
||||
def lock(self, irc, msg, args):
|
||||
"[<channel>] (If not sent in the channel itself) <key>"
|
||||
channel = privmsgs.getChannel(msg, args)
|
||||
@ -155,7 +155,7 @@ class Factoids(ChannelDBHandler, callbacks.Privmsg):
|
||||
irc.reply(msg, conf.replySuccess)
|
||||
else:
|
||||
irc.error(msg, conf.replyNoCapability % capability)
|
||||
|
||||
|
||||
def unlock(self, irc, msg, args):
|
||||
"[<channel>] (If not sent in the channel itself) <key>"
|
||||
channel = privmsgs.getChannel(msg, args)
|
||||
@ -183,7 +183,7 @@ class Factoids(ChannelDBHandler, callbacks.Privmsg):
|
||||
irc.reply(msg, conf.replySuccess)
|
||||
else:
|
||||
irc.error(msg, conf.replyNoCapability % capability)
|
||||
|
||||
|
||||
def randomfactoid(self, irc, msg, args):
|
||||
"[<channel>] (If not sent in the channel itself)"
|
||||
channel = privmsgs.getChannel(msg, args)
|
||||
@ -226,7 +226,7 @@ class Factoids(ChannelDBHandler, callbacks.Privmsg):
|
||||
s = 'Key %r is %s and has %s factoids associated with it: %s' % \
|
||||
(key, locked and 'locked' or 'not locked', counter, '; '.join(L))
|
||||
irc.reply(msg, s)
|
||||
|
||||
|
||||
|
||||
|
||||
Class = Factoids
|
||||
|
@ -204,8 +204,8 @@ class FreeBSD(callbacks.Privmsg):
|
||||
'Please narrow your search.' % cursor.rowcount)
|
||||
else:
|
||||
irc.reply(msg, ', '.join(names))
|
||||
|
||||
|
||||
|
||||
|
||||
def numports(self, irc, msg, args):
|
||||
"""takes no arguments
|
||||
|
||||
@ -249,10 +249,10 @@ class FreeBSD(callbacks.Privmsg):
|
||||
categories = map(lambda t: t[0], cursor.fetchall())
|
||||
irc.reply(msg, '%s; Categories: %s; Maintainer: %s; Website: %s' %
|
||||
(info, ', '.join(categories), maintainer, website))
|
||||
|
||||
|
||||
|
||||
Class = FreeBSD
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
makeDb(dbFile, getIndex(), replace=True)
|
||||
|
@ -52,7 +52,7 @@ class Friendly(callbacks.PrivmsgRegexp):
|
||||
if match.group(1) == irc.nick:
|
||||
irc.queueMsg(ircmsgs.privmsg(msg.args[0], '%s!' % msg.nick))
|
||||
|
||||
|
||||
|
||||
Class = Friendly
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -122,7 +122,7 @@ class FunCommands(callbacks.Privmsg):
|
||||
irc.reply(msg, chr(i))
|
||||
except ValueError:
|
||||
irc.error(msg, 'That number doesn\'t map to an 8-bit character.')
|
||||
|
||||
|
||||
def base(self, irc, msg, args):
|
||||
"""<base> <number>
|
||||
|
||||
@ -154,7 +154,7 @@ class FunCommands(callbacks.Privmsg):
|
||||
LL.reverse()
|
||||
L.extend(LL)
|
||||
irc.reply(msg, ''.join(L))
|
||||
|
||||
|
||||
|
||||
def encode(self, irc, msg, args):
|
||||
"""<encoding> <text>
|
||||
@ -173,7 +173,7 @@ class FunCommands(callbacks.Privmsg):
|
||||
"""
|
||||
encoding, text = privmsgs.getArgs(args, needed=2)
|
||||
irc.reply(msg, text.decode(encoding).encode('utf-8'))
|
||||
|
||||
|
||||
def hexlify(self, irc, msg, args):
|
||||
"""<text>
|
||||
|
||||
@ -323,7 +323,7 @@ class FunCommands(callbacks.Privmsg):
|
||||
text = text.replace('x', 'kth')
|
||||
text = text.replace('X', 'KTH')
|
||||
irc.reply(msg, text)
|
||||
|
||||
|
||||
_leettrans = string.maketrans('oOaAeElBTiIts', '004433187!1+5')
|
||||
_leetres = ((re.compile(r'\b(?:(?:[yY][o0O][oO0uU])|u)\b'), 'j00'),
|
||||
(re.compile(r'fear'), 'ph33r'),
|
||||
@ -405,7 +405,7 @@ class FunCommands(callbacks.Privmsg):
|
||||
return '%s*i' % imag
|
||||
else:
|
||||
return '%s+%si' % (real, imag)
|
||||
|
||||
|
||||
def calc(self, irc, msg, args):
|
||||
"""<math expression>
|
||||
|
||||
@ -540,7 +540,7 @@ class FunCommands(callbacks.Privmsg):
|
||||
def lastfrom(self, irc, msg, args):
|
||||
"""[<channel>] <nick>
|
||||
|
||||
Returns the last message in <channel> from <nick>. <channel> is only
|
||||
Returns the last message in <channel> from <nick>. <channel> is only
|
||||
necessary if the message isn't sent in the channel itself.
|
||||
"""
|
||||
channel = privmsgs.getChannel(msg, args)
|
||||
@ -616,7 +616,7 @@ class FunCommands(callbacks.Privmsg):
|
||||
irc.error(msg, 'That function has no documentation.')
|
||||
return
|
||||
irc.reply(msg, s)
|
||||
|
||||
|
||||
|
||||
Class = FunCommands
|
||||
|
||||
|
@ -104,7 +104,7 @@ def addWord(db, word, commit=False):
|
||||
WHERE word=%s))""", word, sorted)
|
||||
if commit:
|
||||
db.commit()
|
||||
|
||||
|
||||
|
||||
class FunDB(callbacks.Privmsg):
|
||||
"""
|
||||
@ -119,7 +119,7 @@ class FunDB(callbacks.Privmsg):
|
||||
def die(self):
|
||||
self.db.commit()
|
||||
self.db.close()
|
||||
|
||||
|
||||
'''
|
||||
def praise(self, irc, msg, args):
|
||||
"""<something>
|
||||
@ -182,7 +182,7 @@ class FunDB(callbacks.Privmsg):
|
||||
irc.error(msg, 'There is no such insult.')
|
||||
else:
|
||||
irc.reply(msg, cursor.fetchone()[0])
|
||||
|
||||
|
||||
def addinsult(self, irc, msg, args):
|
||||
"""<insult>
|
||||
|
||||
@ -267,7 +267,7 @@ class FunDB(callbacks.Privmsg):
|
||||
irc.error(msg, 'There is no such excuse.')
|
||||
else:
|
||||
irc.reply(msg, cursor.fetchone()[0])
|
||||
|
||||
|
||||
def addexcuse(self, irc, msg, args):
|
||||
"""<excuse>
|
||||
|
||||
@ -294,7 +294,7 @@ class FunDB(callbacks.Privmsg):
|
||||
cursor.execute("""DELETE FROM excuses WHERE id=%s""", id)
|
||||
self.db.commit()
|
||||
irc.reply(msg, conf.replySuccess)
|
||||
|
||||
|
||||
def numexcuses(self, irc, msg, args):
|
||||
"""takes no arguments
|
||||
|
||||
@ -343,7 +343,7 @@ class FunDB(callbacks.Privmsg):
|
||||
irc.error(msg, 'There is no such lart.')
|
||||
else:
|
||||
irc.reply(msg, cursor.fetchone()[0])
|
||||
|
||||
|
||||
def addlart(self, irc, msg, args):
|
||||
"""<lart>
|
||||
|
||||
@ -377,7 +377,7 @@ class FunDB(callbacks.Privmsg):
|
||||
|
||||
def numlarts(self, irc, msg, args):
|
||||
"""takes no arguments
|
||||
|
||||
|
||||
Returns the number of larts currently in the database.
|
||||
"""
|
||||
cursor = self.db.cursor()
|
||||
@ -443,7 +443,7 @@ class FunDB(callbacks.Privmsg):
|
||||
else:
|
||||
(city, state) = cursor.fetchone()
|
||||
irc.reply(msg, '%s, %s' % (city, state))
|
||||
|
||||
|
||||
|
||||
def zipcodefor(self, irc, msg, args):
|
||||
"""<city> <state>
|
||||
@ -474,7 +474,7 @@ class FunDB(callbacks.Privmsg):
|
||||
random.shuffle(zipcodes)
|
||||
irc.reply(msg, '(%s shown of %s): %s' % \
|
||||
(len(zipcodes), cursor.rowcount, ', '.join(zipcodes)))
|
||||
|
||||
|
||||
Class = FunDB
|
||||
|
||||
|
||||
@ -520,5 +520,5 @@ if __name__ == '__main__':
|
||||
zipcode, city, state)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -116,8 +116,8 @@ class Gameknot(callbacks.PrivmsgCommandAndRegexp):
|
||||
raise callbacks.Error, 'The format of the page was odd.'
|
||||
except urllib2.URLError:
|
||||
raise callbacks.Error, 'Couldn\'t connect to gameknot.com'
|
||||
|
||||
|
||||
|
||||
|
||||
def gkstats(self, irc, msg, args):
|
||||
"""<name>
|
||||
|
||||
|
@ -212,7 +212,7 @@ class Http(callbacks.Privmsg):
|
||||
irc.error(msg, 'Couldn\'t open search page.')
|
||||
'''
|
||||
|
||||
|
||||
|
||||
_tempregex = re.compile('CLASS=obsTempTextA>(\d+)°F</b></td>',\
|
||||
re.IGNORECASE)
|
||||
_cityregex = re.compile(r'Local Forecast for (.*), (.*?) ')
|
||||
@ -263,7 +263,7 @@ class Http(callbacks.Privmsg):
|
||||
quote = utils.htmlToText(m.group(1))
|
||||
quote = ' // '.join(quote.splitlines())
|
||||
irc.reply(msg, quote)
|
||||
|
||||
|
||||
_acronymre = re.compile(r'<td[^w]+width="70[^>]+>(?:<b>)?([^<]+)(?:</b>)?')
|
||||
def acronym(self, irc, msg, args):
|
||||
"""<acronym>
|
||||
@ -321,7 +321,7 @@ class Http(callbacks.Privmsg):
|
||||
_debBranches = ('stable', 'testing', 'unstable', 'experimental')
|
||||
def debversion(self, irc, msg, args):
|
||||
"""<package name> [stable|testing|unstable|experimental]
|
||||
|
||||
|
||||
Returns the current version(s) of a Debian package in the given branch
|
||||
(if any, otherwise all available ones are displayed).
|
||||
"""
|
||||
@ -363,7 +363,7 @@ class Http(callbacks.Privmsg):
|
||||
(numberOfPackages, len(responses), ', '.join(responses))
|
||||
irc.reply(msg, s)
|
||||
|
||||
|
||||
|
||||
|
||||
Class = Http
|
||||
|
||||
|
@ -131,7 +131,7 @@ class Infobot(callbacks.PrivmsgRegexp):
|
||||
irc.queueMsg(ircmsgs.privmsg(nick, s))
|
||||
except KeyError:
|
||||
irc.reply(msg, 'I don\'t know anything about %s' % key)
|
||||
|
||||
|
||||
def factoid(self, irc, msg, match):
|
||||
r"^(no[ :,-]+)?(.+?)\s+(was|is|am|were|are)\s+(also\s+)?(.+?)(?!\?+)$"
|
||||
(correction, key, isAre, addition, value) = match.groups()
|
||||
@ -151,7 +151,7 @@ class Infobot(callbacks.PrivmsgRegexp):
|
||||
else:
|
||||
self.insertFactoid(key, isAre, value)
|
||||
irc.reply(msg, self.getRandomSaying('confirms'))
|
||||
|
||||
|
||||
def unknown(self, irc, msg, match):
|
||||
r"^(.+?)\?[?.! ]*$"
|
||||
key = match.group(1)
|
||||
@ -169,12 +169,12 @@ class Infobot(callbacks.PrivmsgRegexp):
|
||||
numAre = cursor.fetchone()[0]
|
||||
s = 'I have %s is factoids and %s are factoids' % (numIs, numAre)
|
||||
irc.reply(msg, s)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Class = Infobot
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if len(sys.argv) < 2 and sys.argv[1] not in ('is', 'are'):
|
||||
@ -202,5 +202,5 @@ if __name__ == '__main__':
|
||||
print 'Invalid line (%s): %r' %(debug.exnToString(e),line)
|
||||
db.commit()
|
||||
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -53,7 +53,7 @@ class KillBold(callbacks.Privmsg):
|
||||
return ircmsgs.privmsg(msg.args[0],msg.args[1].replace('\x02', ''))
|
||||
else:
|
||||
return msg
|
||||
|
||||
|
||||
Class = KillBold
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -39,12 +39,14 @@ Commands include:
|
||||
from baseplugin import *
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
import conf
|
||||
import ircdb
|
||||
import ircmsgs
|
||||
import privmsgs
|
||||
import ircutils
|
||||
import schedule
|
||||
import callbacks
|
||||
|
||||
def configure(onStart, afterConnect, advanced):
|
||||
@ -55,20 +57,21 @@ def configure(onStart, afterConnect, advanced):
|
||||
onStart.append('startnickserv %s %s' % (nick, password))
|
||||
|
||||
class NickServ(privmsgs.CapabilityCheckingPrivmsg):
|
||||
capability = 'owner'
|
||||
capability = 'admin'
|
||||
def __init__(self):
|
||||
callbacks.Privmsg.__init__(self)
|
||||
self.nickserv = ''
|
||||
|
||||
|
||||
def startnickserv(self, irc, msg, args):
|
||||
"<bot's nick> <password> <NickServ's nick (defaults to NickServ)>"
|
||||
"<bot's nick> <password> <NickServ's nick (defaults to NickServ)> " \
|
||||
"<ChanServ's nick (defaults to ChanServ)"
|
||||
if ircutils.isChannel(msg.args[0]):
|
||||
irc.error(msg, conf.replyRequiresPrivacy)
|
||||
return
|
||||
(self.nick, self.password, nickserv) = privmsgs.getArgs(args,
|
||||
needed=2,
|
||||
optional=1)
|
||||
(self.nick, self.password, nickserv, chanserv) = \
|
||||
privmsgs.getArgs(args, needed=2, optional=2)
|
||||
self.nickserv = nickserv or 'NickServ'
|
||||
self.chanserv = chanserv or 'ChanServ'
|
||||
self.sentGhost = False
|
||||
self._ghosted = re.compile('%s.*killed' % self.nick)
|
||||
irc.reply(msg, conf.replySuccess)
|
||||
@ -94,6 +97,19 @@ class NickServ(privmsgs.CapabilityCheckingPrivmsg):
|
||||
ghost = 'GHOST %s %s' % (self.nick, self.password)
|
||||
irc.queueMsg(ircmsgs.privmsg(self.nickserv, ghost))
|
||||
self.sentGhost = True
|
||||
def flipSentGhost():
|
||||
self.sentGhost = False
|
||||
schedule.addEvent(flipSentGhost, time.time() + 300)
|
||||
|
||||
def getops(self, irc, msg, args):
|
||||
"""[<channel>]
|
||||
|
||||
Attempts to get ops from ChanServ in <channel>. If no channel is
|
||||
given, the current channel is assumed.
|
||||
"""
|
||||
channel = privmsgs.getChannel(msg, args)
|
||||
irc.sendMsg(ircmsgs.privmsg(self.chanserv, 'op %s' % channel))
|
||||
|
||||
|
||||
|
||||
Class = NickServ
|
||||
|
@ -79,20 +79,20 @@ class Notes(callbacks.Privmsg):
|
||||
note TEXT
|
||||
)""")
|
||||
self.db.commit()
|
||||
|
||||
|
||||
def _addUser(self, username):
|
||||
"Not callable from channel, used to add users to database."
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute('INSERT INTO users VALUES (NULL, %s)', username)
|
||||
self.db.commit()
|
||||
|
||||
|
||||
def getUserId(self, username):
|
||||
"Returns the user id matching the given username from the users table."
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute('SELECT id FROM users where name=%s', username)
|
||||
if cursor.rowcount != 0:
|
||||
return cursor.fetchone()[0]
|
||||
else:
|
||||
else:
|
||||
raise KeyError, username
|
||||
|
||||
def getUserName(self, userid):
|
||||
@ -116,7 +116,7 @@ class Notes(callbacks.Privmsg):
|
||||
"Called when module is unloaded/reloaded."
|
||||
self.db.commit()
|
||||
self.db.close()
|
||||
|
||||
|
||||
def doJoin(self, irc, msg):
|
||||
try:
|
||||
name = ircdb.users.getUserName(msg.prefix)
|
||||
@ -151,7 +151,7 @@ class Notes(callbacks.Privmsg):
|
||||
|
||||
def sendnote(self, irc, msg, args):
|
||||
"""<recipient> <text>
|
||||
|
||||
|
||||
Sends a new note to the user specified.
|
||||
"""
|
||||
(name, note) = privmsgs.getArgs(args, needed=2)
|
||||
@ -165,13 +165,13 @@ class Notes(callbacks.Privmsg):
|
||||
self._addUser(recipient)
|
||||
senderId = self.getUserId(sender)
|
||||
recipId = self.getUserId(recipient)
|
||||
if ircutils.isChannel(msg.args[0]):
|
||||
if ircutils.isChannel(msg.args[0]):
|
||||
public = 1
|
||||
else:
|
||||
public = 0
|
||||
else:
|
||||
public = 0
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""INSERT INTO notes VALUES
|
||||
(NULL, %s, %s, %s, 0, 0, %s, %s)""",
|
||||
cursor.execute("""INSERT INTO notes VALUES
|
||||
(NULL, %s, %s, %s, 0, 0, %s, %s)""",
|
||||
senderId, recipId, int(time.time()),
|
||||
public, note)
|
||||
self.db.commit()
|
||||
@ -179,7 +179,7 @@ class Notes(callbacks.Privmsg):
|
||||
|
||||
def note(self, irc, msg, args):
|
||||
"""<note id>
|
||||
|
||||
|
||||
Retrieves a single note by unique note id.
|
||||
"""
|
||||
noteid = privmsgs.getArgs(args)
|
||||
@ -191,7 +191,7 @@ class Notes(callbacks.Privmsg):
|
||||
return
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""SELECT notes.note, notes.to_id, notes.from_id,
|
||||
notes.added_at, notes.public
|
||||
notes.added_at, notes.public
|
||||
FROM users, notes
|
||||
WHERE users.name=%s AND
|
||||
notes.to_id=users.id AND
|
||||
@ -216,7 +216,7 @@ class Notes(callbacks.Privmsg):
|
||||
|
||||
def notes(self, irc, msg, args):
|
||||
"""takes no arguments
|
||||
|
||||
|
||||
Retrieves all your unread notes.
|
||||
"""
|
||||
try:
|
||||
@ -275,7 +275,7 @@ class Notes(callbacks.Privmsg):
|
||||
ircutils.shrinkList(ids, ', ', 425)
|
||||
ids.reverse()
|
||||
irc.reply(msg, ', '.join(ids))
|
||||
|
||||
|
||||
|
||||
|
||||
Class = Notes
|
||||
|
@ -179,7 +179,7 @@ class Quotes(ChannelDBHandler, callbacks.Privmsg):
|
||||
irc.reply(msg, conf.replySuccess)
|
||||
else:
|
||||
irc.error(msg, conf.replyNoCapability % capability)
|
||||
|
||||
|
||||
|
||||
Class = Quotes
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -84,7 +84,7 @@ def configure(onStart, afterConnect, advanced):
|
||||
if infocmd:
|
||||
onStart.append('alias %s "rssinfo %s"' % (infocmd, url))
|
||||
onStart.append('freeze %s' % infocmd)
|
||||
|
||||
|
||||
|
||||
class RSS(callbacks.Privmsg):
|
||||
threaded = True
|
||||
@ -114,7 +114,7 @@ class RSS(callbacks.Privmsg):
|
||||
irc.error(msg, 'Error grabbing RSS feed')
|
||||
return
|
||||
irc.reply(msg, payload)
|
||||
|
||||
|
||||
def rssinfo(self, irc, msg, args):
|
||||
"""<url>
|
||||
|
||||
@ -142,7 +142,7 @@ class RSS(callbacks.Privmsg):
|
||||
# The rest of the entries are all available in the channel key
|
||||
response = 'Title: %s; URL: <%s>; ' \
|
||||
'Description: %s; Last updated %s.' % (
|
||||
info.get('title', 'unavailable').strip(),
|
||||
info.get('title', 'unavailable').strip(),
|
||||
info.get('link', 'unavailable').strip(),
|
||||
info.get('description', 'unavailable').strip(),
|
||||
when)
|
||||
|
@ -87,7 +87,7 @@ def configure(onStart, afterConnect, advanced):
|
||||
while yn('Would like to relay between any more channels?') == 'y':
|
||||
channel = anything('What channel?')
|
||||
afterConnect.append('relayjoin %s' % channel)
|
||||
|
||||
|
||||
|
||||
class Relay(callbacks.Privmsg):
|
||||
def __init__(self):
|
||||
@ -99,7 +99,7 @@ class Relay(callbacks.Privmsg):
|
||||
self.lastmsg = ircmsgs.ping('this is just a fake message')
|
||||
self.channels = sets.Set()
|
||||
self.abbreviations = {}
|
||||
|
||||
|
||||
def inFilter(self, irc, msg):
|
||||
if not isinstance(irc, irclib.Irc):
|
||||
irc = irc.getRealIrc()
|
||||
@ -110,7 +110,7 @@ class Relay(callbacks.Privmsg):
|
||||
self.ircstates[irc].addMsg(irc, self.lastmsg)
|
||||
self.lastmsg = msg
|
||||
return msg
|
||||
|
||||
|
||||
def startrelay(self, irc, msg, args):
|
||||
"""<network abbreviation for current server>
|
||||
|
||||
@ -131,7 +131,7 @@ class Relay(callbacks.Privmsg):
|
||||
|
||||
def relayconnect(self, irc, msg, args):
|
||||
"""<network abbreviation> <domain:port> (port defaults to 6667)
|
||||
|
||||
|
||||
Connects to another network at <domain:port>. The network
|
||||
abbreviation <network abbreviation> is used when relaying messages from
|
||||
that network to other networks.
|
||||
@ -267,7 +267,7 @@ class Relay(callbacks.Privmsg):
|
||||
do312 = do311
|
||||
do317 = do311
|
||||
do319 = do311
|
||||
|
||||
|
||||
def do318(self, irc, msg):
|
||||
if not isinstance(irc, irclib.Irc):
|
||||
irc = irc.getRealIrc()
|
||||
@ -289,7 +289,7 @@ class Relay(callbacks.Privmsg):
|
||||
s = '%s (%s) has been online since %s (idle for %s) and is on %s' % \
|
||||
(nick, hostmask, signon, idle, channels)
|
||||
replyIrc.reply(replyMsg, s)
|
||||
|
||||
|
||||
def _formatPrivmsg(self, nick, network, msg):
|
||||
# colorize nicks
|
||||
nick = ircutils.mircColor(nick, *ircutils.canonicalColor(nick))
|
||||
@ -358,7 +358,7 @@ class Relay(callbacks.Privmsg):
|
||||
for otherIrc in self.ircs.itervalues():
|
||||
if otherIrc != irc:
|
||||
otherIrc.queueMsg(ircmsgs.privmsg(channel, s))
|
||||
|
||||
|
||||
def doNick(self, irc, msg):
|
||||
if self.started:
|
||||
if not isinstance(irc, irclib.Irc):
|
||||
@ -386,7 +386,7 @@ class Relay(callbacks.Privmsg):
|
||||
for otherIrc in self.ircs.itervalues():
|
||||
if otherIrc != irc:
|
||||
otherIrc.queueMsg(ircmsgs.privmsg(channel, s))
|
||||
|
||||
|
||||
def outFilter(self, irc, msg):
|
||||
if not self.started:
|
||||
return msg
|
||||
@ -419,9 +419,9 @@ class Relay(callbacks.Privmsg):
|
||||
if otherIrc != irc:
|
||||
if otherIrc.state.getTopic(channel) != topic:
|
||||
otherIrc.queueMsg(ircmsgs.topic(channel, topic))
|
||||
|
||||
|
||||
return msg
|
||||
|
||||
Class = Relay
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -75,6 +75,6 @@ class ThreadedFunCommands(callbacks.Privmsg):
|
||||
beta = version.strip()
|
||||
irc.reply(msg, 'The latest stable kernel is %s; ' \
|
||||
'the latest beta kernel is %s.' % (stable, beta))
|
||||
|
||||
|
||||
Class = ThreadedFunCommands
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -119,7 +119,7 @@ class Topic(callbacks.Privmsg):
|
||||
except IndexError:
|
||||
irc.error(msg, 'That\'s not a valid index.')
|
||||
return
|
||||
|
||||
|
||||
def changetopic(self, irc, msg, args):
|
||||
"""[<channel>] <number> <regexp>
|
||||
|
||||
@ -159,7 +159,7 @@ class Topic(callbacks.Privmsg):
|
||||
topics.insert(number, newTopic)
|
||||
newTopic = self.topicSeparator.join(topics)
|
||||
irc.queueMsg(ircmsgs.topic(channel, newTopic))
|
||||
|
||||
|
||||
def removetopic(self, irc, msg, args):
|
||||
"[<channel>] (if not sent in the channel itself) <topic number>"
|
||||
channel = privmsgs.getChannel(msg, args)
|
||||
|
@ -58,7 +58,7 @@ class TwistedCommands(callbacks.Privmsg):
|
||||
failure.printDetailedTraceback()
|
||||
irc.error(msg, failure.getErrorMessage())
|
||||
return errback
|
||||
|
||||
|
||||
dictnumberre = re.compile('^\d+:\s*(.*)$')
|
||||
def dictCallback(self, irc, msg, word):
|
||||
def formatDictResults(definitions):
|
||||
@ -91,7 +91,7 @@ class TwistedCommands(callbacks.Privmsg):
|
||||
deferred = dict.define('dict.org', 2628, 'wn', word)
|
||||
deferred.addCallback(self.dictCallback(irc, msg, word))
|
||||
deferred.addErrback(self.defaultErrback(irc, msg))
|
||||
|
||||
|
||||
|
||||
class TwistedRegexp(callbacks.PrivmsgRegexp):
|
||||
def dccrecv(self, irc, msg, match):
|
||||
|
@ -187,8 +187,8 @@ class URLSnarfer(callbacks.Privmsg, ChannelDBHandler):
|
||||
else:
|
||||
(url,) = cursor.fetchone()
|
||||
irc.reply(msg, url)
|
||||
|
||||
|
||||
|
||||
|
||||
Class = URLSnarfer
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -61,7 +61,7 @@ def configure(onStart, afterConnect, advanced):
|
||||
print 'choose to install it later, and then the module will'
|
||||
print 'automatically work, as long as it is in the path of the'
|
||||
print 'user that supybot runs under.'
|
||||
print
|
||||
print
|
||||
|
||||
print 'The "progstats" command can reveal potentially sensitive'
|
||||
print 'information about your machine. Here\'s an example of its output:'
|
||||
@ -80,7 +80,7 @@ def progstats():
|
||||
os.getcwd(), " ".join(sys.argv),
|
||||
sys.version.translate(string.ascii, '\r\n'))
|
||||
return response
|
||||
|
||||
|
||||
|
||||
class Unix(callbacks.Privmsg):
|
||||
def __init__(self):
|
||||
@ -117,7 +117,7 @@ class Unix(callbacks.Privmsg):
|
||||
except KeyError:
|
||||
name = '(unknown)'
|
||||
irc.reply(msg, '%s (#%s): %s' % (name, i, os.strerror(i)))
|
||||
|
||||
|
||||
def progstats(self, irc, msg, args):
|
||||
"""takes no arguments
|
||||
|
||||
@ -144,7 +144,7 @@ class Unix(callbacks.Privmsg):
|
||||
salt = makeSalt()
|
||||
irc.reply(msg, crypt.crypt(password, salt))
|
||||
|
||||
def spell(self, irc, msg, args):
|
||||
def spell(self, irc, msg, args):
|
||||
"""<word>
|
||||
|
||||
Returns the result of passing <word> to aspell/ispell. The results
|
||||
@ -158,7 +158,7 @@ class Unix(callbacks.Privmsg):
|
||||
return
|
||||
self._spellWrite.write(word)
|
||||
self._spellWrite.write('\n')
|
||||
line = self._spellRead.readline()
|
||||
line = self._spellRead.readline()
|
||||
# aspell puts extra whitespace, ignore it
|
||||
while line == '\n':
|
||||
line = self._spellRead.readline()
|
||||
@ -178,7 +178,7 @@ class Unix(callbacks.Privmsg):
|
||||
else:
|
||||
resp = 'Something unexpected was seen in the [ai]spell output.'
|
||||
irc.reply(msg, resp)
|
||||
|
||||
|
||||
|
||||
Class = Unix
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -48,11 +48,11 @@ def configure(onStart, afterConnect, advanced):
|
||||
class Utilities(callbacks.Privmsg):
|
||||
def ignore(self, irc, msg, args):
|
||||
pass
|
||||
|
||||
|
||||
def shrink(self, irc, msg, args):
|
||||
text = privmsgs.getArgs(args)
|
||||
irc.reply(msg, text[:400])
|
||||
|
||||
|
||||
def strjoin(self, irc, msg, args):
|
||||
"<separator> <strings to join>"
|
||||
sep = args.pop(0)
|
||||
@ -128,7 +128,7 @@ class Utilities(callbacks.Privmsg):
|
||||
irc.error(msg, 'Invalid regexp: %s' % e.args[0])
|
||||
return
|
||||
irc.reply(msg, ' '.join(r.findall(text)))
|
||||
|
||||
|
||||
|
||||
|
||||
Class = Utilities
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -170,5 +170,5 @@ if __name__ == '__main__':
|
||||
print 'You\'re done! Now run the bot with the command line:'
|
||||
print 'src/bot.py conf/%s' % name
|
||||
print
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -131,7 +131,7 @@ class MiscCommands(callbacks.Privmsg):
|
||||
(command, simplehelp))
|
||||
else:
|
||||
irc.error(msg, 'That command has no help at all.')
|
||||
|
||||
|
||||
def bug(self, irc, msg, args):
|
||||
"""takes no arguments
|
||||
|
||||
|
@ -126,7 +126,7 @@ class AsyncoreDriver(asynchat.async_chat, object):
|
||||
def die(self):
|
||||
self.close()
|
||||
|
||||
|
||||
|
||||
class ReplListener(asyncore.dispatcher, object):
|
||||
def __init__(self, port=conf.telnetPort):
|
||||
asyncore.dispatcher.__init__(self)
|
||||
|
@ -98,7 +98,7 @@ def reply(msg, s):
|
||||
if len(m) > 512:
|
||||
m = reply(msg, 'My response would\'ve been too long.')
|
||||
return m
|
||||
|
||||
|
||||
class RateLimiter:
|
||||
lastRequest = {}
|
||||
def __init__(self):
|
||||
@ -232,8 +232,8 @@ def tokenize(s):
|
||||
raise SyntaxError, str(e)
|
||||
debug.msg('tokenize took %s seconds.' % (time.time() - start), 'verbose')
|
||||
return args
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class IrcObjectProxy:
|
||||
def __init__(self, irc, msg, args):
|
||||
@ -340,7 +340,7 @@ class CommandThread(threading.Thread):
|
||||
self.irc = irc
|
||||
self.msg = msg
|
||||
self.setDaemon(True)
|
||||
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
start = time.time()
|
||||
@ -356,7 +356,7 @@ class CommandThread(threading.Thread):
|
||||
debug.recoverableException()
|
||||
self.irc.error(self.msg, debug.exnToString(e))
|
||||
|
||||
|
||||
|
||||
class Privmsg(irclib.IrcCallback):
|
||||
"""Base class for all Privmsg handlers."""
|
||||
threaded = False
|
||||
@ -508,7 +508,7 @@ class PrivmsgCommandAndRegexp(Privmsg):
|
||||
method = getattr(self, name)
|
||||
r = re.compile(method.__doc__, self.flags)
|
||||
self.res.append((r, method))
|
||||
|
||||
|
||||
def doPrivmsg(self, irc, msg):
|
||||
if ircdb.checkIgnored(msg.prefix, msg.args[0]):
|
||||
return
|
||||
@ -528,10 +528,10 @@ class PrivmsgCommandAndRegexp(Privmsg):
|
||||
if msg:
|
||||
args = tokenize(s)
|
||||
self.Proxy(irc, msg, args)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -188,3 +188,6 @@ driverModule = 'asyncoreDrivers'
|
||||
###############################
|
||||
###############################
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ except ImportError:
|
||||
class conf:
|
||||
logDir = '.'
|
||||
detailedTracebacks = True
|
||||
|
||||
|
||||
import world
|
||||
|
||||
###
|
||||
|
@ -284,5 +284,5 @@ def partition(p, L):
|
||||
|
||||
def flip((x, y)):
|
||||
return (y, x)
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
@ -152,7 +152,7 @@ class UserCapabilitySet(CapabilitySet):
|
||||
capability = ircutils.toLower(capability)
|
||||
assert capability != '!owner', '"!owner" disallowed.'
|
||||
CapabilitySet.add(self, capability)
|
||||
|
||||
|
||||
class IrcUser(object):
|
||||
"""This class holds the capabilities and authentications for a user.
|
||||
"""
|
||||
@ -498,7 +498,7 @@ def _x(capability, ret):
|
||||
return not ret
|
||||
else:
|
||||
return ret
|
||||
|
||||
|
||||
def checkCapability(hostmask, capability, users=users, channels=channels):
|
||||
#debug.printf('*** checking %s for %s' % (hostmask, capability))
|
||||
if world.startup:
|
||||
@ -560,7 +560,7 @@ def checkCapability(hostmask, capability, users=users, channels=channels):
|
||||
else:
|
||||
#debug.printf('returning appropriate value given no good reason')
|
||||
return _x(capability, conf.defaultAllow)
|
||||
|
||||
|
||||
|
||||
def checkCapabilities(hostmask, capabilities, requireAll=False):
|
||||
"""Checks that a user has capabilities in a list.
|
||||
|
@ -227,7 +227,7 @@ class IrcState(IrcCommandDispatcher):
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
|
||||
def copy(self):
|
||||
ret = self.__class__()
|
||||
ret.history = copy.copy(self.history)
|
||||
|
@ -112,7 +112,7 @@ class IrcMsg(object):
|
||||
else:
|
||||
(self.nick, self.user, self.host) = (self.prefix,)*3
|
||||
self.args = tuple(self.args)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
if self._str is not None:
|
||||
return self._str
|
||||
@ -155,7 +155,7 @@ class IrcMsg(object):
|
||||
self._len += len(arg) + 1 # Remember space prior to the arg.
|
||||
self._len += 2 # For colon before the prefix and before the last arg.
|
||||
return self._len
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
return hash(self) == hash(other) and \
|
||||
self.command == other.command and \
|
||||
@ -249,7 +249,7 @@ def prettyPrint(msg, addRecipients=False):
|
||||
elif msg.command == 'TOPIC':
|
||||
s = '*** %s changes topic to %s' % (nickorprefix(), msg.args[1])
|
||||
return s
|
||||
|
||||
|
||||
###
|
||||
# Various IrcMsg functions
|
||||
###
|
||||
|
@ -309,7 +309,7 @@ class IrcString(str):
|
||||
|
||||
def __str__(self):
|
||||
return str(self.original)
|
||||
|
||||
|
||||
def __eq__(self, s):
|
||||
try:
|
||||
return toLower(s) == self.lowered
|
||||
|
@ -100,7 +100,7 @@ def getKeywordArgs(irc, msg, d=None):
|
||||
args.append(left)
|
||||
del args[0] # The command name itself.
|
||||
return (args, d)
|
||||
|
||||
|
||||
def checkCapability(f, capability):
|
||||
def newf(self, irc, msg, args):
|
||||
if ircdb.checkCapability(msg.prefix, capability):
|
||||
@ -225,7 +225,7 @@ class OwnerCommands(CapabilityCheckingPrivmsg):
|
||||
"""
|
||||
world.upkeep()
|
||||
irc.reply(msg, conf.replySuccess)
|
||||
|
||||
|
||||
def set(self, irc, msg, args):
|
||||
"""<name> <value>
|
||||
|
||||
@ -280,7 +280,7 @@ class OwnerCommands(CapabilityCheckingPrivmsg):
|
||||
world.superReload(__import__(name))
|
||||
irc.reply(msg, conf.replySuccess)
|
||||
'''
|
||||
|
||||
|
||||
def reload(self, irc, msg, args):
|
||||
"""<callback name>
|
||||
|
||||
@ -307,7 +307,7 @@ class OwnerCommands(CapabilityCheckingPrivmsg):
|
||||
irc.error(msg, 'No plugin %s exists.' % name)
|
||||
else:
|
||||
irc.error(msg, 'There was no callback %s.' % name)
|
||||
|
||||
|
||||
def unload(self, irc, msg, args):
|
||||
"""<callback name>
|
||||
|
||||
|
@ -47,7 +47,7 @@ class RTuple(tuple):
|
||||
return not tuple.__le__(self, other)
|
||||
def __cmp__(self, other):
|
||||
return -1*tuple.__cmp__(self, other)
|
||||
|
||||
|
||||
class Schedule(drivers.IrcDriver):
|
||||
def __init__(self):
|
||||
drivers.IrcDriver.__init__(self)
|
||||
|
@ -66,10 +66,10 @@ class RingBuffer(object):
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def __nonzero__(self):
|
||||
return len(self) > 0
|
||||
|
||||
|
||||
def __contains__(self, elt):
|
||||
return elt in self.L
|
||||
|
||||
@ -88,7 +88,7 @@ class RingBuffer(object):
|
||||
def extend(self, seq):
|
||||
for elt in seq:
|
||||
self.append(elt)
|
||||
|
||||
|
||||
def __getitem__(self, idx):
|
||||
if self.full:
|
||||
oidx = idx
|
||||
@ -226,7 +226,7 @@ class queue(object):
|
||||
return self.front[-(idx+1)]
|
||||
else:
|
||||
return self.back[(idx-len(self.front))]
|
||||
|
||||
|
||||
def __setitem__(self, oidx, value):
|
||||
if len(self) == 0:
|
||||
raise IndexError, 'queue index out of range'
|
||||
@ -272,7 +272,7 @@ class queue(object):
|
||||
self.front = L
|
||||
self.back = []
|
||||
|
||||
|
||||
|
||||
class MaxLengthQueue(queue):
|
||||
__slots__ = ('length',)
|
||||
def __init__(self, length, seq=()):
|
||||
@ -285,7 +285,7 @@ class MaxLengthQueue(queue):
|
||||
def __setstate__(self, (length, q)):
|
||||
self.length = length
|
||||
queue.__setstate__(self, q)
|
||||
|
||||
|
||||
def enqueue(self, elt):
|
||||
queue.enqueue(self, elt)
|
||||
if len(self) > self.length:
|
||||
|
@ -87,7 +87,7 @@ class SupyIrcProtocol(LineReceiver):
|
||||
self.transport.loseConnection()
|
||||
|
||||
reconnect = die
|
||||
|
||||
|
||||
|
||||
class SupyReconnectingFactory(ReconnectingClientFactory):
|
||||
maxDelay = 600
|
||||
@ -96,7 +96,7 @@ class SupyReconnectingFactory(ReconnectingClientFactory):
|
||||
self.irc = irc
|
||||
self.server = (server, port)
|
||||
reactor.connectTCP(server, port, self)
|
||||
|
||||
|
||||
|
||||
class MyShell(Shell):
|
||||
def checkUserAndPass(self, username, password):
|
||||
@ -112,13 +112,13 @@ class MyShell(Shell):
|
||||
return False
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
class MyShellFactory(ShellFactory):
|
||||
protocol = MyShell
|
||||
|
||||
if conf.telnetEnable and __name__ != '__main__':
|
||||
reactor.listenTCP(conf.telnetPort, MyShellFactory())
|
||||
|
||||
|
||||
|
||||
Driver = SupyReconnectingFactory
|
||||
|
||||
|
@ -160,8 +160,8 @@ class PluginTestCase(unittest.TestCase):
|
||||
self.assertEqual(len(expectedResponses), len(responses))
|
||||
for (m, expected) in zip(responses, expectedResponses):
|
||||
self.assertEqual(m.args[1], expected)
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
world.testing = True
|
||||
if len(sys.argv) > 1:
|
||||
|
@ -78,7 +78,7 @@ class FunCommandsTest(PluginTestCase):
|
||||
def testPydoc(self):
|
||||
self.assertNotError('pydoc str')
|
||||
self.assertError('pydoc foobar')
|
||||
|
||||
|
||||
def testOrd(self):
|
||||
for c in map(chr, range(256)):
|
||||
i = ord(c)
|
||||
|
@ -103,7 +103,7 @@ class UserCapabilitySetTestCase(unittest.TestCase):
|
||||
d.add('owner')
|
||||
self.failUnless(d.check('owner'))
|
||||
|
||||
|
||||
|
||||
|
||||
class CapabilitySetTestCase(unittest.TestCase):
|
||||
def testContains(self):
|
||||
@ -119,7 +119,7 @@ class CapabilitySetTestCase(unittest.TestCase):
|
||||
s.add('!foo')
|
||||
self.failUnless('foo' in s)
|
||||
self.failUnless('!foo' in s)
|
||||
|
||||
|
||||
def testCheck(self):
|
||||
s = ircdb.CapabilitySet()
|
||||
self.assertRaises(KeyError, s.check, 'foo')
|
||||
@ -146,7 +146,7 @@ class CapabilitySetTestCase(unittest.TestCase):
|
||||
s.add('foo')
|
||||
self.failUnless(s.check('foo'))
|
||||
self.failIf(s.check('!foo'))
|
||||
|
||||
|
||||
|
||||
class UserCapabilitySetTestCase(unittest.TestCase):
|
||||
def testOwner(self):
|
||||
@ -179,7 +179,7 @@ class IrcUserTestCase(unittest.TestCase):
|
||||
u.addCapability('owner')
|
||||
self.failUnless(u.checkCapability('foo'))
|
||||
self.failIf(u.checkCapability('!foo'))
|
||||
|
||||
|
||||
def testInitCapabilities(self):
|
||||
u = ircdb.IrcUser(capabilities=['foo'])
|
||||
self.failUnless(u.checkCapability('foo'))
|
||||
@ -211,7 +211,7 @@ class IrcUserTestCase(unittest.TestCase):
|
||||
u = ircdb.IrcUser(ignore=True)
|
||||
self.failIf(u.checkCapability('foo'))
|
||||
self.failUnless(u.checkCapability('!foo'))
|
||||
|
||||
|
||||
class IrcChannelTestCase(unittest.TestCase):
|
||||
def testInit(self):
|
||||
c = ircdb.IrcChannel()
|
||||
@ -240,7 +240,7 @@ class IrcChannelTestCase(unittest.TestCase):
|
||||
def testLobotomized(self):
|
||||
c = ircdb.IrcChannel(lobotomized=True)
|
||||
self.failUnless(c.checkIgnored(''))
|
||||
|
||||
|
||||
def testIgnored(self):
|
||||
prefix = 'foo!bar@baz'
|
||||
banmask = ircutils.banmask(prefix)
|
||||
@ -262,10 +262,10 @@ class UsersDictionaryTestCase(unittest.TestCase):
|
||||
fd.write('{}\n')
|
||||
fd.close()
|
||||
self.users = ircdb.UsersDictionary(self.filename)
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
os.remove(self.filename)
|
||||
|
||||
|
||||
def testGetSetDelUser(self):
|
||||
self.assertRaises(KeyError, self.users.getUser, 'foo')
|
||||
self.assertRaises(KeyError, self.users.getUser, 'foo!bar@baz')
|
||||
@ -283,7 +283,7 @@ class UsersDictionaryTestCase(unittest.TestCase):
|
||||
u.removeHostmask(banmask)
|
||||
u.addHostmask('*!*@*')
|
||||
self.assertRaises(ValueError, self.users.setUser, 'biff', u)
|
||||
|
||||
|
||||
|
||||
class CheckCapabilityTestCase(unittest.TestCase):
|
||||
filename = 'CheckCapabilityTestCase.conf'
|
||||
@ -334,7 +334,7 @@ class CheckCapabilityTestCase(unittest.TestCase):
|
||||
self.users.setUser('antichanfoo', antichanfoo)
|
||||
channel = ircdb.IrcChannel()
|
||||
self.channels.setChannel(self.channel, channel)
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
os.remove(self.filename)
|
||||
|
||||
@ -383,10 +383,10 @@ class CheckCapabilityTestCase(unittest.TestCase):
|
||||
def testJustChanFoo(self):
|
||||
self.channels.setChannel(self.channel, self.channelnothing)
|
||||
self.failUnless(self.checkCapability(self.justchanfoo, self.chancap))
|
||||
self.failIf(self.checkCapability(self.justchanfoo, self.antichancap))
|
||||
self.failIf(self.checkCapability(self.justchanfoo, self.antichancap))
|
||||
self.channelnothing.defaultAllow = not self.channelnothing.defaultAllow
|
||||
self.failUnless(self.checkCapability(self.justchanfoo, self.chancap))
|
||||
self.failIf(self.checkCapability(self.justchanfoo, self.antichancap))
|
||||
self.failIf(self.checkCapability(self.justchanfoo, self.antichancap))
|
||||
self.channels.setChannel(self.channel, self.channelanticap)
|
||||
self.failUnless(self.checkCapability(self.justchanfoo, self.chancap))
|
||||
self.failIf(self.checkCapability(self.justchanfoo, self.antichancap))
|
||||
|
@ -50,7 +50,7 @@ class IrcMsgQueueTestCase(unittest.TestCase):
|
||||
def testEmpty(self):
|
||||
q = irclib.IrcMsgQueue()
|
||||
self.failIf(q)
|
||||
|
||||
|
||||
def testEnqueueDequeue(self):
|
||||
q = irclib.IrcMsgQueue()
|
||||
q.enqueue(self.msg)
|
||||
@ -131,7 +131,7 @@ class ChannelTestCase(unittest.TestCase):
|
||||
self.failIf('quuz' in c.halfops)
|
||||
self.failIf('quuz' in c.voices)
|
||||
|
||||
|
||||
|
||||
class IrcStateTestCase(unittest.TestCase):
|
||||
class FakeIrc:
|
||||
nick = 'nick'
|
||||
@ -171,11 +171,11 @@ class IrcStateTestCase(unittest.TestCase):
|
||||
self.assertEqual(state1, state2)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
"""
|
||||
def testChannels(self):
|
||||
channel =
|
||||
channel =
|
||||
state = irclib.IrcState()
|
||||
state.addMsg(self.irc, ircmsgs.join('#foo'))
|
||||
"""
|
||||
|
@ -126,7 +126,7 @@ class FunctionsTestCase(unittest.TestCase):
|
||||
withException = ircmsgs.ban(channel, ban, exception)
|
||||
self.assertEqual(ircutils.separateModes(withException.args[1:]),
|
||||
[('+b', ban), ('+e', exception)])
|
||||
|
||||
|
||||
def testBans(self):
|
||||
channel = '#osu'
|
||||
bans = ['*!*@*', 'jemfinch!*@*']
|
||||
|
@ -84,14 +84,14 @@ class FunctionsTestCase(unittest.TestCase):
|
||||
self.assertEqual('\x03,5foo\x03', ircutils.mircColor(s, bg='brown'))
|
||||
self.assertEqual('\x036,7foo\x03',
|
||||
ircutils.mircColor(s, bg='orange', fg='purple'))
|
||||
|
||||
|
||||
def testMircColors(self):
|
||||
# Make sure all (k, v) pairs are also (v, k) pairs.
|
||||
for (k, v) in ircutils.mircColors.items():
|
||||
if k:
|
||||
self.assertEqual(ircutils.mircColors[v], k)
|
||||
|
||||
|
||||
|
||||
|
||||
def testSafeArgument(self):
|
||||
s = 'I have been running for 9 seconds'
|
||||
bolds = ircutils.bold(s)
|
||||
|
@ -63,8 +63,8 @@ class TestSchedule(unittest.TestCase):
|
||||
self.assertEqual(i[0], 11)
|
||||
time.sleep(3)
|
||||
self.assertEqual(i[0], 11)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
||||
|
@ -183,7 +183,7 @@ class RingBufferTestCase(unittest.TestCase):
|
||||
b = RingBuffer(100, range(10))
|
||||
b1 = RingBuffer(10, range(10))
|
||||
self.failIf(b == b1)
|
||||
|
||||
|
||||
def testIter(self):
|
||||
b = RingBuffer(3, range(3))
|
||||
L = []
|
||||
@ -214,7 +214,7 @@ class QueueTest(unittest.TestCase):
|
||||
self.assertRaises(IndexError, q.__getitem__, -(n+1))
|
||||
self.assertRaises(IndexError, q.__getitem__, n)
|
||||
self.assertEqual(q[3:7], queue([3, 4, 5, 6]))
|
||||
|
||||
|
||||
def testSetitem(self):
|
||||
q1 = queue()
|
||||
self.assertRaises(IndexError, q1.__setitem__, 0, 0)
|
||||
@ -224,7 +224,7 @@ class QueueTest(unittest.TestCase):
|
||||
for (i, elt) in enumerate(q2):
|
||||
q2[i] = elt*2
|
||||
self.assertEqual([x*2 for x in q1], list(q2))
|
||||
|
||||
|
||||
def testNonzero(self):
|
||||
q = queue()
|
||||
self.failIf(q, 'queue not zero after initialization')
|
||||
@ -301,7 +301,7 @@ class QueueTest(unittest.TestCase):
|
||||
self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue')
|
||||
q.enqueue((1,))
|
||||
self.assertEqual(q, eval(repr(q)), 'repr doesn\'t eval to same queue')
|
||||
|
||||
|
||||
def testEnqueueDequeue(self):
|
||||
q = queue()
|
||||
self.assertRaises(IndexError, q.dequeue)
|
||||
@ -360,7 +360,7 @@ class MaxLengthQueueTestCase(unittest.TestCase):
|
||||
q = MaxLengthQueue(3, (1, 2, 3))
|
||||
self.assertEqual(list(q), [1, 2, 3])
|
||||
self.assertRaises(TypeError, MaxLengthQueue, 3, 1, 2, 3)
|
||||
|
||||
|
||||
def testMaxLength(self):
|
||||
q = MaxLengthQueue(3)
|
||||
q.enqueue(1)
|
||||
|
Loading…
Reference in New Issue
Block a user