Changeset 36:416eae5bd1b5 in livinglogic.python.nightshade

Show
Ignore:
Timestamp:
03/12/07 18:57:31 (13 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Enhance docstrings.

Add stuff required for an official release (README, NEWS.xml, INSTALL.xml)

Retry calling the procedure in more error situations.

Files:
3 added
3 modified

Legend:

Unmodified
Added
Removed
  • Makefile

    r21 r36  
    1313 
    1414 
    15 livinglogic: 
     15text: 
     16    python$(PYVERSION) `which doc2txt.py` --title "History" NEWS.xml NEWS 
     17    python$(PYVERSION) `which doc2txt.py` --title "Requirements and installation" INSTALL.xml INSTALL 
     18 
     19 
     20dist: text 
     21    rm -rf dist/* 
     22    python$(PYVERSION) setup.py sdist --formats=bztar,gztar 
     23    python$(PYVERSION) setup.py sdist --formats=zip 
     24    python$(PYVERSION) setup.py bdist --formats=egg 
     25    cd dist && scp.py -v -uftp -gftp *.tar.gz *.tar.bz2 *.zip *.egg root@isar.livinglogic.de:~ftp/pub/livinglogic/nightshade/ 
     26 
     27 
     28register: 
     29    python$(PYVERSION) setup.py register 
     30 
     31 
     32livinglogic: text 
    1633    rm -rf dist/* 
    1734    python$(PYVERSION) setup.py sdist --formats=bztar,gztar 
     
    2138 
    2239 
     40upload: text 
     41    python$(PYVERSION) setup.py sdist --formats=bztar,gztar upload 
     42    python$(PYVERSION) setup.py sdist --formats=zip upload 
     43    python$(PYVERSION) setup.py bdist --formats=egg upload 
     44 
     45 
     46windist: wintext 
     47    rm -rf dist/* 
     48    python$(PYVERSION) setup.py bdist --formats=wininst 
     49    cd dist && python$(PYVERSION) -mscp -v -uftp -gftp *.exe root@isar.livinglogic.de:~ftp/pub/livinglogic/orasql/ 
     50 
     51 
     52winupload: wintext 
     53    python$(PYVERSION) setup.py bdist --formats=wininst upload 
     54 
     55 
    2356winlivinglogic: wintext 
    2457    python$(PYVERSION) setup.py bdist --formats=wininst 
  • setup.py

    r34 r36  
    4848args = dict( 
    4949    name="ll-nightshade", 
    50     version="0.5.2", 
     50    version="0.6", 
    5151    description="Serve the output of TOXIC functions/procedures with CherryPy", 
    5252    long_description=DESCRIPTION, 
    5353    author=u"Walter Doerwald", 
    5454    author_email="walter@livinglogic.de", 
    55     #url="http://www.livinglogic.de/Python/nightshade/", 
    56     #download_url="http://www.livinglogic.de/Python/nightshade/Download.html", 
     55    url="http://www.livinglogic.de/Python/nightshade/", 
     56    download_url="http://www.livinglogic.de/Python/nightshade/Download.html", 
    5757    license="Python", 
    5858    classifiers=[c for c in CLASSIFIERS.strip().splitlines() if c.strip() and not c.strip().startswith("#")], 
     
    6161    package_dir={"": "src"}, 
    6262    install_requires=[ 
    63         "ll-orasql >= 1.12", 
     63        "ll-orasql >= 1.17.3", 
    6464    ], 
    6565    namespace_packages=["ll"], 
  • src/ll/nightshade.py

    r35 r36  
    11# -*- coding: iso-8859-1 -*- 
     2 
     3""" 
     4<par>This module provides a class <pyref class="Call"><class>Call</class></pyref> 
     5that can be used to wrap <class>Procedure</class> or <class>Function<class> 
     6object from <pyref module="ll.orasql"><module>ll.orasql</module></pyref>. This 
     7makes it possible to use PL/SQL procedures as 
     8<link href="http://www.cherrypy.org/">CherryPy</link> response handlers.<par> 
     9<par>For example, you might have the following PL/SQL function:</par> 
     10<prog><[![CDATA[ 
     11create or replace function helloworld 
     12( 
     13    who varchar2 
     14) 
     15return varchar2 
     16as 
     17begin 
     18    return '<html><head><title>Hello ' || who || '</title></head><body><h1>Hello, ' || who || '!</h1></body></html>'; 
     19end; 
     20]]></prog> 
     21<par>Using this function as a CherryPy response handler can be done like this:</par> 
     22<prog> 
     23import cherrypy 
     24 
     25from ll import orasql, nightshade 
     26 
     27 
     28proc = nightshade.Call(orasql.Function("helloworld"), connectstring="user/pwd") 
     29 
     30class HelloWorld(object): 
     31    @cherrypy.expose 
     32    def default(self, who="World"): 
     33        cherrypy.response.headers["Content-Type"] = "text/html" 
     34        return proc(who=who) 
     35 
     36cherrypy.quickstart(HelloWorld()) 
     37""" 
    238 
    339import time, datetime, threading 
     
    1551 
    1652class UTC(datetime.tzinfo): 
     53    """ 
     54    Timezone object for UTC 
     55    """ 
    1756    def utcoffset(self, dt): 
    1857        return datetime.timedelta(0) 
     
    2867 
    2968def getnow(): 
     69    """ 
     70    Get the current date and time as a <class>datetime.datetime</class> 
     71    object in UTC with timezone info. 
     72    """ 
    3073    return datetime.datetime.utcnow().replace(tzinfo=utc) 
    3174 
     
    5194    <par>Decorator that adds caching to a CherryPy handler.</par> 
    5295     
    53     <par>Calling a <class>cache</class> object is callable will cache return 
    54     values of the decorated function for a certain amount of time. You can pass 
     96    <par>Calling a <class>cache</class> object will cache return values 
     97    of the decorated function for a certain amount of time. You can pass 
    5598    the timespan either via <arg>timedelta</arg> (which must be a 
    5699    <class>datetime.timedelta</class> object), or via <arg>timedeltaargs</arg> 
     
    101144def conditional(func): 
    102145    """ 
    103     <par>Decorator that adds handling of  conditional <lit>GET</lit>s to a CherryPy handler.</par> 
     146    <par>Decorator that adds handling of conditional <lit>GET</lit>s to a CherryPy handler.</par> 
    104147     
    105148    <par>The decorated function will correctly handle the <lit>If-Modified-Since</lit> 
     
    139182 
    140183    <par><class>Call</class> object wraps a procedure or function object from 
    141     <pyref module="ll.orasql"><module>ll.orasql</module></pyref> and make it 
     184    <pyref module="ll.orasql"><module>ll.orasql</module></pyref> and makes it 
    142185    callable just like a CherryPy handler. 
    143186    """ 
     187    _badoracleexceptions = set(( 
     188        28,    # your session has been killed 
     189        1012,  # not logged on 
     190        1014,  # Oracle shutdown in progress 
     191        1033,  # Oracle startup or shutdown in progress 
     192        1034,  # Oracle not available 
     193        1035,  # Oracle only available to users with RESTRICTED SESSION privilege 
     194        1089,  # immediate shutdown in progress - no operations are permitted 
     195        1090,  # Shutdown in progress - connection is not permitted 
     196        1092,  # ORACLE instance terminated. Disconnection forced 
     197        3106,  # fatal two-task communication protocol error 
     198        3113,  # end-of-file on communication channel 
     199        3114,  # not connected to ORACLE 
     200        3135,  # connection lost contact 
     201        12154, # TNS:could not resolve the connect identifier specified 
     202        12540, # TNS:internal limit restriction exceeded 
     203        12541, # TNS:no listener 
     204        12543, # TNS:destination host unreachable 
     205    )) 
     206 
    144207    def __init__(self, callable, pool=None, connectstring=None): 
    145208        """ 
     
    175238 
    176239    def _isbadoracleexception(self, exc): 
    177         strexc = str(exc) 
    178         return ("ORA-00028" in strexc or # your session has been killed 
    179                 "ORA-01012" in strexc or # not logged on 
    180                 "ORA-03113" in strexc or # end-of-file on communication channel 
    181                 "ORA-03114" in strexc or # not connected to ORACLE 
    182                 "ORA-03135" in strexc) # connection lost contact 
     240        if exc.args: 
     241            code = getattr(exc[0], "code", 0) 
     242            if code in self._badoracleexceptions: 
     243                return True 
     244        return False 
    183245 
    184246    def __call__(self, *args, **kwargs): 
    185247        """ 
    186         Call the procedure/function with the arguments <arg>args</arg> and 
     248        <par>Call the procedure/function with the arguments <arg>args</arg> and 
    187249        <arg>kwargs</arg> mapping Python function arguments to Oracle procedure/function 
    188250        arguments. On return from the procedure the <lit>out</lit> parameter is 
    189251        mapped to the CherryPy response body, and the parameters <lit>expires</lit> 
    190         (the number of days from now), <lit>lastmodified</lit> (a date in UTV), 
     252        (the number of days from now), <lit>lastmodified</lit> (a date in UTC), 
    191253        <lit>mimetype</lit> (a string), <lit>encoding</lit> (a string) and 
    192254        <lit>etag</lit> (a string) are mapped to the appropriate CherryPy response 
    193         headers. If <lit>etag</lit> is not specified a value is calculated. 
     255        headers. If <lit>etag</lit> is not specified a value is calculated.</par> 
     256        <par>If the procedure/function raised a PL/SQL exception with a code between 
     257        20200 and 20599, 20000 will be substracted from this value and the resulting 
     258        value will be used as the HTTP repsonse code, i.e. 20404 will give a 
     259        "Not Found" response. 
    194260        """ 
    195261