⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dibbler.py

📁 用python实现的邮件过滤器
💻 PY
📖 第 1 页 / 共 3 页
字号:
"""*Introduction*Dibbler is a Python web application framework.  It lets you create web-basedapplications by writing independent plug-in modules that don't require anynetworking code.  Dibbler takes care of the HTTP side of things, leaving youto write the application code.*Plugins and Methlets*Dibbler uses a system of plugins to implement the application logic.  Eachpage maps to a 'methlet', which is a method of a plugin object that servesthat page, and is named after the page it serves.  The address`http://server/spam` calls the methlet `onSpam`.  `onHome` is a reservedmethlet name for the home page, `http://server/`.  For resources that need afile extension (eg. images) you can use a URL such as `http://server/eggs.gif`to map to the `onEggsGif` methlet.  All the registered plugins are searchedfor the appropriate methlet, so you can combine multiple plugins to buildyour application.A methlet needs to call `self.writeOKHeaders('text/html')` followed by`self.write(content)`.  You can pass whatever content-type you like to`writeOKHeaders`, so serving images, PDFs, etc. is no problem.  If a methletwants to return an HTTP error code, it should call (for example)`self.writeError(403, "Forbidden")` instead of `writeOKHeaders`and `write`.  If it wants to write its own headers (for instance to returna redirect) it can simply call `write` with the full HTTP response.If a methlet raises an exception, it is automatically turned into a "500Server Error" page with a full traceback in it.*Parameters*Methlets can take parameters, the values of which are taken from formparameters submitted by the browser.  So if your form says`<form action='subscribe'><input type="text" name="email"/> ...` then yourmethlet should look like `def onSubscribe(self, email=None)`.  It's goodpractice to give all the parameters default values, in case the user navigatesto that URL without submitting a form, or submits the form without filling inany parameters.  If you have lots of parameters, or their names are determinedat runtime, you can define your methlet like this:`def onComplex(self, **params)` to get a dictionary of parameters.*Example*Here's a web application server that serves a calendar for a given year:>>> import Dibbler, calendar>>> class Calendar(Dibbler.HTTPPlugin):...     _form = '''<html><body><h3>Calendar Server</h3>...                <form action='/'>...                Year: <input type='text' name='year' size='4'>...                <input type='submit' value='Go'></form>...                <pre>%s</pre></body></html>'''......     def onHome(self, year=None):...         if year:...             result = calendar.calendar(int(year))...         else:...             result = ""...         self.writeOKHeaders('text/html')...         self.write(self._form % result)...>>> httpServer = Dibbler.HTTPServer(8888)>>> httpServer.register(Calendar())>>> Dibbler.run(launchBrowser=True)Your browser will start, and you can ask for a calendar for the year ofyour choice.  If you don't want to start the browser automatically, just call`run()` with no arguments - the application is available athttp://localhost:8888/ .  You'll have to kill the server manually because itprovides no way to stop it; a real application would have some kind of'shutdown' methlet that called `sys.exit()`.By combining Dibbler with an HTML manipulation library likePyMeld (shameless plug - see http://entrian.com/PyMeld for details) you cankeep the HTML and Python code separate.*Building applications*You can run several plugins together like this:>>> httpServer = Dibbler.HTTPServer()>>> httpServer.register(plugin1, plugin2, plugin3)>>> Dibbler.run()...so many plugin objects, each implementing a different set of pages,can cooperate to implement a web application.  See also the `HTTPServer`documentation for details of how to run multiple `Dibbler` environmentssimultaneously in different threads.*Controlling connections*There are times when your code needs to be informed the moment an incomingconnection is received, before any HTTP conversation begins.  For instance,you might want to only accept connections from `localhost` for securityreasons.  If this is the case, your plugin should implement the`onIncomingConnection` method.  This will be passed the incoming socketbefore any reads or writes have taken place, and should return True to allowthe connection through or False to reject it.  Here's an implementation ofthe `localhost`-only idea:>>> def onIncomingConnection(self, clientSocket):>>>     return clientSocket.getpeername()[0] == clientSocket.getsockname()[0]*Advanced usage: Dibbler Contexts*If you want to run several independent Dibbler environments (in differentthreads for example) then each should use its own `Context`.  Normallyyou'd say something like:>>> httpServer = Dibbler.HTTPServer()>>> httpServer.register(MyPlugin())>>> Dibbler.run()but that's only safe to do from one thread.  Instead, you can say:>>> myContext = Dibbler.Context()>>> httpServer = Dibbler.HTTPServer(context=myContext)>>> httpServer.register(MyPlugin())>>> Dibbler.run(myContext)in as many threads as you like.*Dibbler and asyncore*If this section means nothing to you, you can safely ignore it.Dibbler is built on top of Python's asyncore library, which means that itintegrates into other asyncore-based applications, and you can write otherasyncore-based components and run them as part of the same application.By default, Dibbler uses the default asyncore socket map.  This means that`Dibbler.run()` also runs your asyncore-based components, provided they'reusing the default socket map.  If you want to tell Dibbler to use adifferent socket map, either to co-exist with other asyncore-based componentsusing that map or to insulate Dibbler from such components by using adifferent map, you need to use a `Dibbler.Context`.  If you're using your ownsocket map, give it to the context: `context = Dibbler.Context(myMap)`.  Ifyou want Dibbler to use its own map: `context = Dibbler.Context({})`.You can either call `Dibbler.run(context)` to run the async loop, or call`asyncore.loop()` directly - the only difference is that the former has afew more options, like launching the web browser automatically.*Self-test*Running `Dibbler.py` directly as a script runs the example calendar serverplus a self-test."""# Dibbler is released under the Python Software Foundation license; see# http://www.python.org/__author__ = "Richie Hindle <richie@entrian.com>"__credits__ = "Tim Stone"try:    import cStringIO as StringIOexcept ImportError:    import StringIOimport os, sys, re, time, traceback, md5, base64import socket, asyncore, asynchat, cgi, urlparse, webbrowsertry:    True, Falseexcept NameError:    # Maintain compatibility with Python 2.2    True, False = 1, 0try:    "".rstrip("abc")except TypeError:    # rstrip(chars) requires Python 2.2.2 or higher.  Apart from that    # we probably work with Python 2.2 (and say we do), so provide the    # ability to do this for that case.    RSTRIP_CHARS_AVAILABLE = Falseelse:    RSTRIP_CHARS_AVAILABLE = Trueclass BrighterAsyncChat(asynchat.async_chat):    """An asynchat.async_chat that doesn't give spurious warnings on    receiving an incoming connection, lets SystemExit cause an exit, can    flush its output, and will correctly remove itself from a non-default    socket map on `close()`."""    def __init__(self, conn=None, map=None):        """See `asynchat.async_chat`."""        asynchat.async_chat.__init__(self, conn)        self.__map = map        self._closed = False    def handle_connect(self):        """Suppresses the asyncore "unhandled connect event" warning."""        pass    def handle_error(self):        """Let SystemExit cause an exit."""        type, v, t = sys.exc_info()        if type == SystemExit:            raise        else:            asynchat.async_chat.handle_error(self)    def flush(self):        """Flush everything in the output buffer."""        # We check self._closed here because of the case where        # self.initiate_send() raises an exception, causing self.close()        # to be called.  If we didn't check, we could end up in an infinite        # loop.        while (self.producer_fifo or self.ac_out_buffer) and not self._closed:            self.initiate_send()    def close(self):        """Remove this object from the correct socket map."""        self._closed = True        self.del_channel(self.__map)        self.socket.close()class Context:    """See the main documentation for details of `Dibbler.Context`."""    def __init__(self, asyncMap=asyncore.socket_map):        self._HTTPPort = None  # Stores the port for `run(launchBrowser=True)`        self._map = asyncMap    def pop(self, key):        return self._map.pop(key)    def keys(self):        return self._map.keys()    def __len__(self):        return len(self._map)_defaultContext = Context()class Listener(asyncore.dispatcher):    """Generic listener class used by all the different types of server.    Listens for incoming socket connections and calls a factory function    to create handlers for them."""    def __init__(self, port, factory, factoryArgs,                 socketMap=_defaultContext._map):        """Creates a listener object, which will listen for incoming        connections when Dibbler.run is called:         o port: The TCP/IP (address, port) to listen on. Usually '' -           meaning bind to all IP addresses that the machine has - will be           passed as the address.  If `port` is just an int, an address of           '' will be assumed.         o factory: The function to call to create a handler (can be a class           name).         o factoryArgs: The arguments to pass to the handler factory.  For           proper context support, this should include a `context` argument

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -