commit 6662af0e9dbdcb0f0ee89a35215a3c0ed4860f9e Author: Alec Leamas Date: Thu Mar 14 13:37:05 2013 +0100 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..d60b47a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Insert a description of your plugin here, with any notes, etc. about using it. diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..68bf798 --- /dev/null +++ b/__init__.py @@ -0,0 +1,67 @@ +### +# Copyright (c) 2013, Alec Leamas +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +""" +Listen for data on a TCP port and forward to designated channel(s). +""" + +# pylint: disable=C0103 + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.unknown + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +# This is a url where the most recent plugin package can be downloaded. +__url__ = '' # 'http://supybot.com/Members/yourname/Irccat/download' + +import config +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +if world.testing: + import test + +Class = plugin.Class +configure = config.configure + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/config.py b/config.py new file mode 100644 index 0000000..1bdd91d --- /dev/null +++ b/config.py @@ -0,0 +1,97 @@ +### +# Copyright (c) 2013, Alec Leamas +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +''' Plugin registry initialization and access. ''' + +import supybot.conf as conf +import supybot.registry as registry + +_PW_TEXT = "Section password" + +_CHANNELS_TXT = "List of channels to be fed by thi section" + +_SECTION_OPTS = { + 'password': + lambda: registry.String('', _PW_TEXT), + 'channels': + lambda: registry.SpaceSeparatedListOfStrings('', _CHANNELS_TXT) +} + + +def sect_option(section_name, option): + ''' Return section-specific option, registering on the fly. ''' + sections = global_option('sections') + try: + section = sections.get(section_name) + except registry.NonExistentRegistryEntry: + section = conf.registerGroup(sections, section_name) + try: + return section.get(option) + except registry.NonExistentRegistryEntry: + conf.registerGlobalValue(section, option, _SECTION_OPTS[option]()) + return section.get(option) + + +def unregister_section(section_name): + ''' Unregister section from supybot registry. ''' + try: + global_option('sections').unregister(section_name) + except registry.NonExistentRegistryEntry: + pass + + +def configure(advanced): + ''' Not used ATM ''' + # This will be called by supybot to configure this module. advanced is + # a bool that specifies whether the user identified himself as an advanced + # user or not. You should effect your configuration by manipulating the + # registry as appropriate. + ### from supybot.questions import expect, anything, something, yn + conf.registerPlugin('Irccat', True) + + +def global_option(option): + ''' Return a overall plugin option (registered at load time). ''' + return conf.supybot.plugins.get('irccat').get(option) + + +# This is where your configuration variables (if any) should go. For example: +# conf.registerGlobalValue(Irccat, 'someConfigVariableName', +# registry.Boolean(False, """Help for someConfigVariableName.""")) + +Irccat = conf.registerPlugin('Irccat') + +conf.registerGroup(Irccat, 'sections') + +conf.registerGlobalValue(Irccat, 'port', + registry.NonNegativeInteger(12345, + "The TCP port irccat will listen to.")) + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/local/__init__.py b/local/__init__.py new file mode 100644 index 0000000..e86e97b --- /dev/null +++ b/local/__init__.py @@ -0,0 +1 @@ +# Stub so local is a module, used for third-party modules diff --git a/pep8.conf b/pep8.conf new file mode 100644 index 0000000..94268e7 --- /dev/null +++ b/pep8.conf @@ -0,0 +1,2 @@ +[pep8] +ignore=E221,E251,E125,E126,E127,E128,E272,E124 diff --git a/plugin.py b/plugin.py new file mode 100644 index 0000000..e685abb --- /dev/null +++ b/plugin.py @@ -0,0 +1,93 @@ +### +# Copyright (c) 2013, Alec Leamas +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# https://chris-lamb.co.uk/posts/irccat-plugin-supybot +# http://www.jibble.org/pircbot.php + +''' Main plugin module. See README for usage and configuration. ''' + +from twisted.internet import reactor, protocol +from twisted.protocols import basic + +from supybot import callbacks +#from supybot import ircutils +from supybot import ircmsgs +#from supybot import log +#from supybot import plugins +#from supybot import utils +from supybot.commands import threading + +import config + + +class IrccatProtocol(basic.LineOnlyReceiver): + ''' Line protocol: parse line, forward to channel(s). ''' + delimiter = '\n' + + def __init__(self, irc): + self.irc = irc + + def lineReceived(self, text): + ''' Handle one line of input from client. ''' + self.irc.queueMsg(ircmsgs.notice('#al-bot-test', text)) + + +class IrccatFactory(protocol.Factory): + ''' Twisted factory producing a Protocol using buildProtocol. ''' + + def __init__(self, irc): + self.irc = irc + + def buildProtocol(self, addr): + return IrccatProtocol(self.irc) + + +class Irccat(callbacks.Plugin): + ''' Main plugin. ''' + # pylint: disable=E1101,R0904 + + threaded = True + + def __init__(self, irc): + callbacks.Plugin.__init__(self, irc) + port = config.global_option('port').value + self.server = reactor.listenTCP(port, IrccatFactory(irc)) + kwargs_ = {'installSignalHandlers': False} + self.thread = threading.Thread(target = reactor.run, kwargs = kwargs_) + self.thread.start() + + def die(self): + ''' Tear down reactor thread and die. ''' + reactor.callFromThread(reactor.stop) + self.thread.join() + callbacks.Plugin.die(self) + +Class = Irccat + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/pylint.conf b/pylint.conf new file mode 100644 index 0000000..99bdb09 --- /dev/null +++ b/pylint.conf @@ -0,0 +1,270 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add files or directories to the blacklist. hey should be base names, not +# paths. +ignore=test.py + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). +disable=R0903,W0141,W0232,E1103,I0011,W0311,W0403,W0613,R0201 + +#E1103: *%s %r has no %r member (but some types could not be inferred)* +# Adds noise like "type list has no member split()", not useful +# +#R0903: *Too few public methods (%s/%s)*. Useless, warns for good code. +# +#W0141: *Used builtin function %r*. Warns for map(), filter() etc. +# Useless, there's nothing wrong with these +# +#W0232: *Class has no __init__ method*. This not an error in any way! +# +#W0403: Warns for import paths. Doesn't work hereA +# +#W0613: Unused arguments warning. Will always happen here due to protyping +# in plugin methods. +#R0201: Method could be a function. Also happens due to plugin prototyping. + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Include message's id in output +include-ids=yes + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (RP0004). +comment=no + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,TODO + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +## Default only allows CAPS, but singletons should be CamelCase. +const-rgx=(([A-Z_][A-Za-z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][A-Za-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][A-Za-z0-9_]*$ + +# Regular expression which should only match correct variable names +## Original: variable-rgx=[a-z_][a-z0-9_]{2,30}$. Disallows short variable +## names, but such are actually useful in some contexts. +variable-rgx=[A-Za-z0-9_]*$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_,ok + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[DESIGN] + +# Maximum number of arguments for function / method +## Locally raised from 5 to 8, once again plugin prototyping has some costs. +max-args=8 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +## Defaault is 7. Not much we can do with the plugin inhertitance chain. +max-parents=8 + +# Maximum number of attributes for a class (see R0902). +max-attributes=8 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/test.py b/test.py new file mode 100644 index 0000000..91f3514 --- /dev/null +++ b/test.py @@ -0,0 +1,48 @@ +### +# Copyright (c) 2013, Alec Leamas +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +# Unused wildcard imports: +# pylint: disable=W0614,W0401 +# Missing docstrings: +# pylint: disable=C0111 +# supybot's typenames are irregular +# pylint: disable=C0103 +# Too many public methods: +# pylint: disable=R0904 + + +from supybot.test import * + + +class IrccatTestCase(PluginTestCase): + plugins = ('Irccat',) + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: