def _opencage_geocode(self, location): location = location.lower() apikey = self.registryValue('apikeys.opencage') if not apikey: raise callbacks.Error("No OpenCage API key.") url = "https://api.opencagedata.com/geocode/v1/json?q={0}&key={1}&abbrv=1&limit=1".format( utils.web.urlquote(location), apikey) self.log.debug('NuWeather: using url %s (geocoding)', url) f = utils.web.getUrl(url, headers=HEADERS).decode('utf-8') data = json.loads(f) if data['status']['message'] != "OK": raise callbacks.Error("{0} from OpenCage for location {1}".format( data['status']['message'], location)) data = data['results'][0] lat = data['geometry']['lat'] lon = data['geometry']['lng'] display_name = data['formatted'] place_id = data['annotations']['geohash'] self.log.debug( 'NuWeather: saving %s,%s (place_id %s, %s) for location %s from OpenCage', lat, lon, place_id, display_name, location) result = (lat, lon, display_name, place_id, "OpenCage") return result
def _googlemaps_geocode(self, location): location = location.lower() apikey = self.registryValue('apikeys.googlemaps') if not apikey: raise callbacks.Error("No Google Maps API key.") url = "https://maps.googleapis.com/maps/api/geocode/json?address={0}&key={1}".format( utils.web.urlquote(location), apikey) self.log.debug('NuWeather: using url %s (geocoding)', url) f = utils.web.getUrl(url, headers=HEADERS).decode('utf-8') data = json.loads(f) if data['status'] != "OK": raise callbacks.Error( "{0} from Google Maps for location {1}".format( data['status'], location)) data = data['results'][0] lat = data['geometry']['location']['lat'] lon = data['geometry']['location']['lng'] display_name = data['formatted_address'] place_id = data['place_id'] self.log.debug( 'NuWeather: saving %s,%s (place_id %s, %s) for location %s from Google Maps', lat, lon, place_id, display_name, location) result = (lat, lon, display_name, place_id, "Google\xa0Maps") return result
def _weatherstack_geocode(self, location): location = location.lower() apikey = self.registryValue('apikeys.weatherstack') if not apikey: raise callbacks.Error("No weatherstack API key.") url = "http://api.weatherstack.com/current?access_key={0}&query={1}".format( apikey, utils.web.urlquote(location)) self.log.debug('NuWeather: using url %s (geocoding)', url) f = utils.web.getUrl(url, headers=HEADERS).decode('utf-8') data = json.loads(f) if data.get('error'): raise callbacks.Error( "{0} From weatherstack for location {1}".format( data['error']['info'], location)) lat = data['location']['lat'] lon = data['location']['lon'] display_name = data['request']['query'] place_id = "{0},{1}".format(lat, lon) self.log.debug( 'NuWeather: saving %s,%s (place_id %s,%s) for location %s from weatherstack', lat, lon, place_id, display_name, location) result = (lat, lon, display_name, place_id, "weatherstack") return result
def assert_feed_does_not_exist(self, name, url=None): if self.isCommandMethod(name): s = format(_('I already have a command in this plugin named %s.'), name) raise callbacks.Error(s) if url: feed = self.feeds.get(url) if feed and feed.name != feed.url: s = format(_('I already have a feed with that URL named %s.'), feed.name) raise callbacks.Error(s)
def makeFeedCommand(self, name, url): docstring = format( """[<number of headlines>] Reports the titles for %s at the RSS feed %u. If <number of headlines> is given, returns only that many headlines. RSS feeds are only looked up every supybot.plugins.RSS.waitPeriod seconds, which defaults to 1800 (30 minutes) since that's what most websites prefer. """, name, url) if url not in self.locks: self.locks[url] = threading.RLock() if self.isCommandMethod(name): s = format('I already have a command in this plugin named %s.', name) raise callbacks.Error(s) def f(self, irc, msg, args): args.insert(0, url) self.rss(irc, msg, args) f = utils.python.changeFunctionName(f, name, docstring) f = types.MethodType(f, self) self.feedNames[name] = (url, f) self._registerFeed(name, url)
def _getDb(self, channel, debug=False): if channel in self.dbs: return self.dbs[channel] try: import sqlalchemy as sql self.sql = sql except ImportError: raise callbacks.Error('You need to have SQLAlchemy installed to use this ' \ 'plugin. Download it at <http://www.sqlalchemy.org/>') filename = plugins.makeChannelFilename(self.filename, channel) engine = sql.create_engine(self.engine + filename, echo=debug) metadata = sql.MetaData() firsts = sql.Table('firsts', metadata, sql.Column('id', sql.Integer, primary_key=True), sql.Column('first', sql.Text, unique=True), sql.Column('count', sql.Integer, default=1), ) lasts = sql.Table('lasts', metadata, sql.Column('id', sql.Integer, primary_key=True), sql.Column('last', sql.Text, unique=True), sql.Column('count', sql.Integer, default=1), ) pairs = sql.Table('pairs', metadata, sql.Column('id', sql.Integer, primary_key=True), sql.Column('first', sql.Text, default=sql.null), sql.Column('second', sql.Text, default=sql.null), sql.Column('follow', sql.Text, default=sql.null), sql.Column('count', sql.Integer, default=1), sql.UniqueConstraint('first', 'second', 'follow'), ) metadata.create_all(engine) self.dbs[channel] = (engine, firsts, lasts, pairs) return self.dbs[channel]
def _format(self, data, forecast=False): """ Formats and returns current conditions. """ # Work around IRC length limits for config opts... data['c'] = data['current'] data['f'] = data.get('forecast') flat_data = flatten_subdicts(data) if flat_data.get('url'): flat_data['url'] = utils.str.url(flat_data['url']) forecast_available = bool(data.get('forecast')) if forecast: # --forecast option was given if forecast_available: fmt = self.registryValue( 'outputFormat.forecast', dynamic.msg.args[0]) or DEFAULT_FORECAST_FORMAT else: raise callbacks.Error( _("Extended forecast info is not available from this backend." )) else: if forecast_available: fmt = self.registryValue('outputFormat', dynamic.msg.args[0]) or DEFAULT_FORMAT else: fmt = self.registryValue( 'outputFormat.currentOnly', dynamic.msg.args[0]) or DEFAULT_FORMAT_CURRENTONLY template = string.Template(fmt) return template.safe_substitute(flat_data)
def _geocode(self, location, geobackend=None): geocode_backend = geobackend or self.registryValue( 'geocodeBackend', dynamic.msg.args[0]) if geocode_backend not in GEOCODE_BACKENDS: raise callbacks.Error( _("Unknown geocode backend %r. Valid ones are: %s") % (geocode_backend, ', '.join(GEOCODE_BACKENDS))) result_pair = str( (location, geocode_backend)) # escape for json purposes if result_pair in self.geocode_db: self.log.debug('NuWeather: using cached latlon %s for location %r', self.geocode_db[result_pair], location) return self.geocode_db[result_pair] elif location in self.geocode_db: # Old DBs from < 2019-03-14 only had one field storing location, and always # used OSM/Nominatim. Remove these old entries and regenerate them. self.log.debug('NuWeather: deleting outdated cached location %r', location) del self.geocode_db[location] backend_func = getattr(self, '_%s_geocode' % geocode_backend) result = backend_func(location) self.geocode_db[result_pair] = result # Cache result persistently return result
def _nominatim_geocode(self, location): location = location.lower() url = 'https://nominatim.openstreetmap.org/search/%s?format=jsonv2' % utils.web.urlquote(location) self.log.debug('NuWeather: using url %s (geocoding)', url) # Custom User agent & caching are required for Nominatim per https://operations.osmfoundation.org/policies/nominatim/ f = utils.web.getUrl(url, headers=HEADERS).decode('utf-8') data = json.loads(f) if not data: raise callbacks.Error("Unknown location %s from OSM/Nominatim" % location) data = data[0] # Limit location verbosity to 3 divisions (e.g. City, Province/State, Country) display_name = data['display_name'] display_name_parts = display_name.split(', ') if len(display_name_parts) > 3: if display_name_parts[-2].isdigit(): # Try to remove ZIP code-like divisions display_name_parts.pop(-2) display_name = ', '.join([display_name_parts[0]] + display_name_parts[-2:]) lat = data['lat'] lon = data['lon'] osm_id = data.get('osm_id') self.log.debug('NuWeather: saving %s,%s (osm_id %s, %s) for location %s from OSM/Nominatim', lat, lon, osm_id, display_name, location) result = (lat, lon, display_name, osm_id, "OSM/Nominatim") return result
def _getIrc(self, network): irc = world.getIrc(network) if irc: return irc else: raise callbacks.Error('I\'m not currently connected to %s.' % network)
def get_file_opener(extension): if extension == 'lz4': try: return lz4.frame.open except AttributeError: raise callbacks.Error( _('Cannot open lz4 file, python3-lz4 0.23.1 or higher ' 'is required.'))
def _darksky_fetcher(self, location, geobackend=None): """Grabs weather data from Dark Sky.""" apikey = self.registryValue('apikeys.darksky') if not apikey: raise callbacks.Error(_("Please configure the Dark Sky API key in plugins.nuweather.apikeys.darksky.")) # Convert location to lat,lon first latlon = self._geocode(location, geobackend=geobackend) if not latlon: raise callbacks.Error("Unknown location %s." % location) lat, lon, display_name, geocodeid, geocode_backend = latlon # Request US units - this is reflected (mi, mph) and processed in our output format as needed url = 'https://api.darksky.net/forecast/%s/%s,%s?units=us&exclude=minutely' % (apikey, lat, lon) self.log.debug('NuWeather: using url %s', url) f = utils.web.getUrl(url, headers=HEADERS).decode('utf-8') data = json.loads(f, strict=False) currentdata = data['currently'] # N.B. Dark Sky docs tell to not expect any values to exist except the timestamp attached to the response return { 'location': display_name, 'poweredby': 'Dark\xa0Sky+' + geocode_backend, 'url': 'https://darksky.net/forecast/%s,%s' % (lat, lon), 'current': { 'condition': currentdata.get('summary', 'N/A'), 'temperature': self._format_temp(f=currentdata.get('temperature')), 'feels_like': self._format_temp(f=currentdata.get('apparentTemperature')), 'humidity': self._format_percentage(currentdata.get('humidity')), 'precip': self._format_precip(mm=currentdata.get('precipIntensity')), 'wind': self._format_distance(mi=currentdata.get('windSpeed', 0), speed=True), 'wind_dir': self._wind_direction(currentdata.get('windBearing')), 'uv': self._format_uv(currentdata.get('uvIndex')), 'visibility': self._format_distance(mi=currentdata['visibility']), }, 'forecast': [{'dayname': self._get_dayname(forecastdata['time'], idx, tz=data['timezone']), 'max': self._format_temp(f=forecastdata['temperatureHigh']), 'min': self._format_temp(f=forecastdata['temperatureLow']), 'summary': forecastdata['summary'].rstrip('.')} for idx, forecastdata in enumerate(data['daily']['data'])] }
def setUp(self): super().setUp() self.myVerbose = verbosity.MESSAGES apikey = os.environ.get('AQICN_APIKEY') if not apikey: e = ("The aqicn API key has not been set. Please set the AQICN_APIKEY environment variable " "and try again.") raise callbacks.Error(e) conf.supybot.plugins.AQI.apikey.setValue(apikey)
def _getSkype(self): if self._skype is None: username = self.registryValue("auth.username") password = self.registryValue("auth.password") if not username or not password: raise callbacks.Error( _("Missing Skype username and/or password. " "Configure them in supybot.plugins.SkypeRelay.auth.username " "supybot.plugins.SkypeRelay.auth.password.")) self._skype = Skype() self._skype.conn.liveLogin(username, password) return self._skype
def getChannel(irc, msg, args): """Returns the channel the msg came over or the channel given in args. If the channel was given in args, args is modified (the channel is removed). """ if args and msg.channel: if conf.supybot.reply.requireChannelCommandsToBeSentInChannel(): if args[0] != msg.channel: s = 'Channel commands must be sent in the channel to which ' \ 'they apply; if this is not the behavior you desire, ' \ 'ask the bot\'s administrator to change the registry ' \ 'variable ' \ 'supybot.reply.requireChannelCommandsToBeSentInChannel ' \ 'to False.' raise callbacks.Error(s) return args.pop(0) elif msg.channel: return msg.channel else: raise callbacks.Error('Command must be sent in a channel or ' \ 'include a channel in its arguments.')
def get_file_opener(extension): """Returns a callable suitable for opening a file with the provided extension.""" if extension == 'lz4': try: return lz4.frame.open except AttributeError: raise callbacks.Error( _('Cannot open lz4 file, python3-lz4 0.23.1 or higher ' 'is required.')) elif extension == 'diff_Index': return None else: raise ValueError( 'Cannot open .%s files, unknown extension' % extension)
def _weatherstack_fetcher(self, location, geobackend=None): """Grabs weather data from weatherstack (formerly Apixu).""" apikey = self.registryValue('apikeys.weatherstack') if not apikey: raise callbacks.Error( _("Please configure the weatherstack API key in plugins.nuweather.apikeys.weatherstack . " "Apixu users please see https://github.com/apilayer/weatherstack#readme" )) # HTTPS is not supported on free accounts. Don't ask me why url = 'http://api.weatherstack.com/current?' + utils.web.urlencode( { 'access_key': apikey, 'query': location, 'units': 'f', }) self.log.debug('NuWeather: using url %s', url) f = utils.web.getUrl(url, headers=HEADERS).decode('utf-8') data = json.loads(f) currentdata = data['current'] return { 'location': data['request']['query'], 'poweredby': 'weatherstack', 'url': '', 'current': { 'condition': currentdata['weather_descriptions'][0], 'temperature': self._format_temp(f=currentdata['temperature']), 'feels_like': self._format_temp(f=currentdata['feelslike']), 'humidity': self._format_percentage(currentdata['humidity']), 'precip': self._format_precip(inches=currentdata['precip']), 'wind': self._format_distance(mi=currentdata['wind_speed'], speed=True), 'wind_dir': currentdata['wind_dir'], 'uv': self._format_uv(currentdata['uv_index']), 'visibility': self._format_distance(mi=currentdata.get('visibility')), } }
def _wuac(self, q, return_names=False): """Internal helper to find locations via Wunderground's GeoLookup API. Previous versions of this plugin used the Autocompete API instead.""" if q.startswith('zmw:'): # If we're given a ZMW code, just return it as is. return [q] apikey = self.registryValue('apiKey') if not apikey: raise callbacks.Error( "No Wunderground API key was defined; set " "the 'plugins.Weather.apiKey' config variable.") url = 'http://api.wunderground.com/api/%s/geolookup/q/%s.json' % ( apikey, utils.web.urlquote(q)) self.log.debug("Weather: GeoLookup URL %s", url) page = utils.web.getUrl(url, timeout=5) data = json.loads(page.decode('utf-8')) if data.get('location'): # This form is used when there's only one result. zmw = 'zmw:{zip}.{magic}.{wmo}'.format(**data['location']) if return_names: name = self._format_geolookup_name(data['location']) return [(name, zmw)] else: return [zmw] else: if data['response'].get('error'): errdata = data['response']['error'] raise WeatherAPIError( 'Error in _wuac step: [%s] %s' % (errdata.get('type', 'N/A'), errdata.get('description', 'No message specified'))) # This form of result is returned there are multiple places matching a query results = data['response'].get('results') if not results: return [] if return_names: results = [(self._format_geolookup_name(result), 'zmw:' + result['zmw']) for result in results] else: results = [('zmw:' + result['zmw']) for result in results] return results
def _apixu_fetcher(self, location, geobackend=None): """Grabs weather data from Apixu.""" apikey = self.registryValue('apikeys.apixu') if not apikey: raise callbacks.Error(_("Please configure the apixu API key in plugins.nuweather.apikeys.apixu.")) url = 'https://api.apixu.com/v1/forecast.json?' + utils.web.urlencode({ 'key': apikey, 'q': location, 'days': 5 }) self.log.debug('NuWeather: using url %s', url) f = utils.web.getUrl(url, headers=HEADERS).decode('utf-8') data = json.loads(f) locationdata = data['location'] if locationdata['region']: location = "%s, %s, %s" % (locationdata['name'], locationdata['region'], locationdata['country']) else: location = "%s, %s" % (locationdata['name'], locationdata['country']) currentdata = data['current'] return { 'location': location, 'poweredby': 'Apixu', 'url': '', 'current': { 'condition': currentdata['condition']['text'], 'temperature': self._format_temp(currentdata['temp_f'], currentdata['temp_c']), 'feels_like': self._format_temp(currentdata['feelslike_f'], currentdata['feelslike_c']), 'humidity': self._format_percentage(currentdata['humidity']), 'precip': self._format_precip(currentdata['precip_mm'], currentdata['precip_in']), 'wind': self._format_distance(currentdata['wind_mph'], currentdata['wind_kph'], speed=True), 'wind_dir': currentdata['wind_dir'], 'uv': self._format_uv(currentdata['uv']), 'visibility': self._format_distance(currentdata.get('vis_miles'), currentdata.get('vis_km')), }, 'forecast': [{'dayname': self._get_dayname(forecastdata['date_epoch'], idx, tz=locationdata['tz_id']), 'max': self._format_temp(forecastdata['day']['maxtemp_f'], forecastdata['day']['maxtemp_c']), 'min': self._format_temp(forecastdata['day']['mintemp_f'], forecastdata['day']['mintemp_c']), 'summary': forecastdata['day']['condition']['text']} for idx, forecastdata in enumerate(data['forecast']['forecastday'])] }
def search(self, query, channel, options={}): """Perform a search using Google's AJAX API. search("search phrase", options={}) Valid options are: smallsearch - True/False (Default: False) filter - {active,moderate,off} (Default: "moderate") language - Restrict search to documents in the given language (Default: "lang_en") """ ref = self.registryValue('referer') if not ref: ref = 'http://%s/%s' % (dynamic.irc.server, dynamic.irc.nick) headers = dict(utils.web.defaultHeaders) headers['Referer'] = ref opts = {'q': query, 'v': '1.0'} for (k, v) in options.items(): if k == 'smallsearch': if v: opts['rsz'] = 'small' else: opts['rsz'] = 'large' elif k == 'filter': opts['safe'] = v elif k == 'language': opts['lr'] = v defLang = self.registryValue('defaultLanguage', channel) if 'lr' not in opts and defLang: opts['lr'] = defLang if 'safe' not in opts: opts['safe'] = self.registryValue('searchFilter', dynamic.channel) if 'rsz' not in opts: opts['rsz'] = 'large' text = utils.web.getUrl('%s?%s' % (self._gsearchUrl, utils.web.urlencode(opts)), headers=headers).decode('utf8') data = json.loads(text) if data['responseStatus'] != 200: self.log.info("Google: unhandled error message: ", text) raise callbacks.Error(data['responseDetails']) return data
def getFeed(self, url): def error(s): return {'items': [{'title': s}]} try: # This is the most obvious place to acquire the lock, because a # malicious user could conceivably flood the bot with rss commands # and DoS the website in question. self.acquireLock(url) if self.willGetNewFeed(url): results = {} try: self.log.debug('Downloading new feed from %u', url) results = feedparser.parse(url) if 'bozo_exception' in results and not results['entries']: raise results['bozo_exception'] except feedparser.sgmllib.SGMLParseError: self.log.exception('Uncaught exception from feedparser:') raise callbacks.Error('Invalid (unparsable) RSS feed.') except socket.timeout: return error('Timeout downloading feed.') except Exception as e: # These seem mostly harmless. We'll need reports of a # kind that isn't. self.log.debug('Allowing bozo_exception %r through.', e) if results.get('feed', {}) and self.getHeadlines(results): self.cachedFeeds[url] = results self.lastRequest[url] = time.time() else: self.log.debug('Not caching results; feed is empty.') try: return self.cachedFeeds[url] except KeyError: wait = self.registryValue('waitPeriod') # If there's a problem retrieving the feed, we should back off # for a little bit before retrying so that there is time for # the error to be resolved. self.lastRequest[url] = time.time() - .5 * wait return error('Unable to download feed.') finally: self.releaseLock(url)
import resource as R import supybot.utils as utils from supybot.commands import * import supybot.plugins as plugins import supybot.ircutils as ircutils import supybot.callbacks as callbacks from cStringIO import StringIO try: import sandbox as S except ImportError: print('You need pysandbox in order to run SupySandbox plugin ' '[http://github.com/haypo/pysandbox].') raise except SyntaxError: raise callbacks.Error('the pysandbox is not compatible with your Python ' 'version.') class SandboxError(Exception): pass def createSandboxConfig(): cfg = S.SandboxConfig( 'stdout', 'stderr', 'regex', 'unicodedata', # flow wants u'\{ATOM SYMBOL}' :-) 'future', #'code', 'time',
import html.entities as htmlentitydefs from imp import reload try: from supybot.i18n import PluginInternationalization from supybot.i18n import internationalizeDocstring _ = PluginInternationalization('Twitter') except: # This are useless functions that's allow to run the plugin on a bot # without the i18n plugin _ = lambda x: x internationalizeDocstring = lambda x: x try: import twitter except ImportError: raise callbacks.Error('You need the python-twitter library.') except Exception as e: raise callbacks.Error('Unknown exception importing twitter: %r' % e) reload(twitter) if not hasattr(twitter, '__version__') or \ twitter.__version__.split('.') < ['0', '8', '0']: raise ImportError('You current version of python-twitter is to old, ' 'you need at least version 0.8.0, because older ' 'versions do not support OAuth authentication.') class ExtendedApi(twitter.Api): """Api with retweet support.""" def PostRetweet(self, id): '''Retweet a tweet with the Retweet API
import supybot.utils as utils from supybot.commands import * import supybot.plugins as plugins import supybot.ircutils as ircutils import supybot.callbacks as callbacks try: from supybot.i18n import PluginInternationalization _ = PluginInternationalization('PypySandbox') except ImportError: # Placeholder that allows to run the plugin on a bot # without the i18n module _ = lambda x: x if not hasattr(subprocess, 'TimeoutExpired'): raise callbacks.Error('Python >= 3.3 is required.') if not hasattr(tempfile, 'TemporaryDirectory'): # You have some weird setup... raise callbacks.Error('Python >= 3.2 is required.') class TimeoutException(Exception): pass SOURCE_PREFIX = """ try: """ SOURCE_SUFFIX = """ except Exception as e:
import supybot.plugins as plugins import supybot.ircutils as ircutils import supybot.callbacks as callbacks try: from supybot.i18n import PluginInternationalization _ = PluginInternationalization('Markovgen') except ImportError: # Placeholder that allows to run the plugin on a bot # without the i18n module _ = lambda x: x try: import markovgen except ImportError: raise callbacks.Error('Cannot load markovgen library. Make sure you ' 'installed it (%s -m pip install markovgen).' % sys.executable) from imp import reload as r r(markovgen) MATCH_MESSAGE_STRIPNICK = re.compile('^(<[^ ]+> )?(?P<message>.*)$') CHANNELLOGER_REGEXP_BASE = re.compile('^[^ ]* (<[^ ]+> )?(?P<message>.*)$') CHANNELLOGER_REGEXP_STRIPNICK = re.compile( '^[^ ]* (<[^ ]+> )?(<[^ ]+> )?(?P<message>.*)$') def get_channelloger_extracter(stripRelayedNick): @markovgen.mixed_encoding_extracting def channelloger_extracter(x): regexp = CHANNELLOGER_REGEXP_STRIPNICK if stripRelayedNick else \
def _checkNotChannel(self, irc, msg, password='******'): if password and irc.isChannel(msg.args[0]): raise callbacks.Error(conf.supybot.replies.requiresPrivacy())
from supybot.commands import * import supybot.plugins as plugins import supybot.ircutils as ircutils import supybot.callbacks as callbacks try: from supybot.i18n import PluginInternationalization _ = PluginInternationalization('Markovgen') except ImportError: # Placeholder that allows to run the plugin on a bot # without the i18n module _ = lambda x: x try: import markovgen except ImportError: raise callbacks.Error('Cannot load markovgen library. Make sure you ' 'installed it.') from imp import reload as r r(markovgen) MATCH_MESSAGE_STRIPNICK = re.compile('^(<[^ ]+> )?(?P<message>.*)$') CHANNELLOGER_REGEXP_BASE = re.compile('^[^ ]* (<[^ ]+> )?(?P<message>.*)$') CHANNELLOGER_REGEXP_STRIPNICK = re.compile( '^[^ ]* (<[^ ]+> )?(<[^ ]+> )?(?P<message>.*)$') def get_channelloger_extracter(stripRelayedNick): @markovgen.mixed_encoding_extracting def channelloger_extracter(x): regexp = CHANNELLOGER_REGEXP_STRIPNICK if stripRelayedNick else \ CHANNELLOGER_REGEXP_BASE
from supybot.i18n import PluginInternationalization _ = PluginInternationalization('Aka') try: import sqlite3 except ImportError: sqlite3 = None try: import sqlalchemy import sqlalchemy.ext import sqlalchemy.ext.declarative except ImportError: sqlalchemy = None if not (sqlite3 or sqlalchemy): raise callbacks.Error('You have to install python-sqlite3 or ' 'python-sqlalchemy in order to load this plugin.') available_db = {} class Alias(object): __slots__ = ('name', 'alias', 'locked', 'locked_by', 'locked_at') def __init__(self, name, alias): self.name = name self.alias = alias self.locked = False self.locked_by = None self.locked_at = None def __repr__(self): return "<Alias('%r', '%r')>" % (self.name, self.alias) if sqlite3: class SQLiteAkaDB(object):
import html.entities as htmlentitydefs from imp import reload try: from supybot.i18n import PluginInternationalization from supybot.i18n import internationalizeDocstring _ = PluginInternationalization('Twitter') except: # This are useless functions that's allow to run the plugin on a bot # without the i18n plugin _ = lambda x: x internationalizeDocstring = lambda x: x try: import twitter except ImportError: raise callbacks.Error('You need the python-twitter library.') reload(twitter) if not hasattr(twitter, '__version__') or \ twitter.__version__.split('.') < ['0', '8', '0']: raise ImportError('You current version of python-twitter is to old, ' 'you need at least version 0.8.0, because older ' 'versions do not support OAuth authentication.') class ExtendedApi(twitter.Api): """Api with retweet support.""" def PostRetweet(self, id): '''Retweet a tweet with the Retweet API The twitter.Api instance must be authenticated.
from supybot.commands import * import supybot.plugins as plugins import supybot.ircmsgs as ircmsgs import supybot.ircutils as ircutils import supybot.callbacks as callbacks try: from supybot.i18n import PluginInternationalization _ = PluginInternationalization('SilencePlugin') except: # Placeholder that allows to run the plugin on a bot # without the i18n module _ = lambda x: x if not hasattr(callbacks.Commands, 'pre_command_callbacks'): raise callbacks.Error('Your version of Supybot is not compatible with ' 'this plugin (it does not have support for ' 'pre-command-call callbacks).') plugin_class_name_tag = 'SilencePlugin__originated_from' class IrcMsg(ircmsgs.IrcMsg): def __init__(self2, *args, **kwargs): super(IrcMsg, self2).__init__(*args, **kwargs) plugin = None f = sys._getframe().f_back while f: if 'irc' in f.f_locals and \ isinstance(f.f_locals['self'], callbacks.Commands): plugin = f.f_locals['self'] break