Merge pull request #364 from niphlod/enhancement/docstrings

docstrings fixes
This commit is contained in:
mdipierro
2014-01-28 13:41:41 -08:00
4 changed files with 155 additions and 137 deletions

View File

@@ -2,12 +2,12 @@
# -*- coding: utf-8 -*-
"""
This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
| This file is part of the web2py Web Framework
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
Basic caching classes and methods
=================================
---------------------------------
- Cache - The generic caching object interfacing with the others
- CacheInRam - providing caching in ram
@@ -42,57 +42,56 @@ __all__ = ['Cache', 'lazy_cache']
DEFAULT_TIME_EXPIRE = 300
class CacheAbstract(object):
"""
Abstract class for cache implementations.
Main function is now to provide referenced api documentation.
Main function just provides referenced api documentation.
Use CacheInRam or CacheOnDisk instead which are derived from this class.
Attentions, Michele says:
There are signatures inside gdbm files that are used directly
by the python gdbm adapter that often are lagging behind in the
detection code in python part.
On every occasion that a gdbm store is probed by the python adapter,
the probe fails, because gdbm file version is newer.
Using gdbm directly from C would work, because there is backward
compatibility, but not from python!
The .shelve file is discarded and a new one created (with new
signature) and it works until it is probed again...
The possible consequences are memory leaks and broken sessions.
Note:
Michele says: there are signatures inside gdbm files that are used
directly by the python gdbm adapter that often are lagging behind in the
detection code in python part.
On every occasion that a gdbm store is probed by the python adapter,
the probe fails, because gdbm file version is newer.
Using gdbm directly from C would work, because there is backward
compatibility, but not from python!
The .shelve file is discarded and a new one created (with new
signature) and it works until it is probed again...
The possible consequences are memory leaks and broken sessions.
"""
cache_stats_name = 'web2py_cache_statistics'
def __init__(self, request=None):
"""
Parameters
----------
request:
the global request object
"""Initializes the object
Args:
request: the global request object
"""
raise NotImplementedError
def __call__(self, key, f,
time_expire=DEFAULT_TIME_EXPIRE):
"""
Tries retrieve the value corresponding to `key` from the cache of the
object exists and if it did not expire, else it called the function `f`
and stores the output in the cache corresponding to `key`. In the case
the output of the function is returned.
Tries to retrieve the value corresponding to `key` from the cache if the
object exists and if it did not expire, else it calls the function `f`
and stores the output in the cache corresponding to `key`. It always
returns the function that is returned.
:param key: the key of the object to be store or retrieved
:param f: the function, whose output is to be cached
:param time_expire: expiration of the cache in microseconds
Args:
key(str): the key of the object to be stored or retrieved
f(function): the function whose output is to be cached.
- `time_expire` is used to compare the current time with the time when
the requested object was last saved in cache. It does not affect
future requests.
- Setting `time_expire` to 0 or negative value forces the cache to
refresh.
If `f` is `None` the cache is cleared.
time_expire(int): expiration of the cache in seconds.
If the function `f` is `None` the cache is cleared.
It's used to compare the current time with the time
when the requested object was last saved in cache. It does not
affect future requests. Setting `time_expire` to 0 or negative
value forces the cache to refresh.
"""
raise NotImplementedError
@@ -101,11 +100,9 @@ class CacheAbstract(object):
Clears the cache of all keys that match the provided regular expression.
If no regular expression is provided, it clears all entries in cache.
Parameters
----------
regex:
if provided, only keys matching the regex will be cleared.
Otherwise all keys are cleared.
Args:
regex: if provided, only keys matching the regex will be cleared,
otherwise all keys are cleared.
"""
raise NotImplementedError
@@ -114,12 +111,9 @@ class CacheAbstract(object):
"""
Increments the cached value for the given key by the amount in value
Parameters
----------
key:
key for the cached object to be incremeneted
value:
amount of the increment (defaults to 1, can be negative)
Args:
key(str): key for the cached object to be incremeneted
value(int): amount of the increment (defaults to 1, can be negative)
"""
raise NotImplementedError
@@ -187,12 +181,17 @@ class CacheInRam(CacheAbstract):
time_expire=DEFAULT_TIME_EXPIRE,
destroyer=None):
"""
Attention! cache.ram does not copy the cached object. It just stores a reference to it.
Turns out the deepcopying the object has some problems:
1) would break backward compatibility
2) would be limiting because people may want to cache live objects
3) would work unless we deepcopy no storage and retrival which would make things slow.
Anyway. You can deepcopy explicitly in the function generating the value to be cached.
Attention! cache.ram does not copy the cached object.
It just stores a reference to it. Turns out the deepcopying the object
has some problems:
- would break backward compatibility
- would be limiting because people may want to cache live objects
- would work unless we deepcopy no storage and retrival which would make
things slow.
Anyway. You can deepcopy explicitly in the function generating the value
to be cached.
"""
self.initialize()
@@ -419,10 +418,8 @@ class Cache(object):
def __init__(self, request):
"""
Parameters
----------
request:
the global request object
Args:
request: the global request object
"""
# GAE will have a special caching
if have_settings and settings.global_settings.web2py_runtime_gae:
@@ -444,24 +441,30 @@ class Cache(object):
prefix=None, session=False, vars=True, lang=True,
user_agent=False, public=True, valid_statuses=None,
quick=None):
"""
Experimental!
"""Better fit for caching an action
Warning:
Experimental!
Currently only HTTP 1.1 compliant
reference : http://code.google.com/p/doctype-mirror/wiki/ArticleHttpCaching
time_expire: same as @cache
cache_model: same as @cache
prefix: add a prefix to the calculated key
session: adds response.session_id to the key
vars: adds request.env.query_string
lang: adds T.accepted_language
user_agent: if True, adds is_mobile and is_tablet to the key.
Pass a dict to use all the needed values (uses str(.items())) (e.g. user_agent=request.user_agent())
used only if session is not True
public: if False forces the Cache-Control to be 'private'
valid_statuses: by default only status codes starting with 1,2,3 will be cached.
pass an explicit list of statuses on which turn the cache on
quick: Session,Vars,Lang,User-agent,Public:
fast overrides with initial strings, e.g. 'SVLP' or 'VLP', or 'VLP'
Args:
time_expire(int): same as @cache
cache_model(str): same as @cache
prefix(str): add a prefix to the calculated key
session(bool): adds response.session_id to the key
vars(bool): adds request.env.query_string
lang(bool): adds T.accepted_language
user_agent(bool or dict): if True, adds is_mobile and is_tablet to the key.
Pass a dict to use all the needed values (uses str(.items()))
(e.g. user_agent=request.user_agent()). Used only if session is
not True
public(bool): if False forces the Cache-Control to be 'private'
valid_statuses: by default only status codes starting with 1,2,3 will be cached.
pass an explicit list of statuses on which turn the cache on
quick: Session,Vars,Lang,User-agent,Public:
fast overrides with initials, e.g. 'SVLP' or 'VLP', or 'VLP'
"""
from gluon import current
from gluon.http import HTTP
@@ -561,33 +564,32 @@ class Cache(object):
"""
Decorator function that can be used to cache any function/method.
Example::
Args:
key(str) : the key of the object to be store or retrieved
time_expire(int) : expiration of the cache in seconds
`time_expire` is used to compare the current time with the time
when the requested object was last saved in cache.
It does not affect future requests.
Setting `time_expire` to 0 or negative value forces the cache to
refresh.
cache_model(str): can be "ram", "disk" or other (like "memcache").
Defaults to "ram"
@cache('key', 5000, cache.ram)
def f():
return time.ctime()
When the function f is called, web2py tries to retrieve
the value corresponding to `key` from the cache of the
When the function `f` is called, web2py tries to retrieve
the value corresponding to `key` from the cache if the
object exists and if it did not expire, else it calles the function `f`
and stores the output in the cache corresponding to `key`. In the case
the output of the function is returned.
:param key: the key of the object to be store or retrieved
:param time_expire: expiration of the cache in microseconds
:param cache_model: "ram", "disk", or other
(like "memcache" if defined). It defaults to "ram".
Example: ::
Notes
-----
`time_expire` is used to compare the curret time with the time when the
requested object was last saved in cache. It does not affect future
requests.
Setting `time_expire` to 0 or negative value forces the cache to
refresh.
@cache('key', 5000, cache.ram)
def f():
return time.ctime()
If the function `f` is an action, we suggest using
@cache.client instead
Note:
If the function `f` is an action, we suggest using
@cache.action instead
"""
def tmp(func, cache=self, cache_model=cache_model):
@@ -606,11 +608,13 @@ class Cache(object):
def lazy_cache(key=None, time_expire=None, cache_model='ram'):
"""
can be used to cache any function including in modules,
Can be used to cache any function including ones in modules,
as long as the cached function is only called within a web2py request
if a key is not provided, one is generated from the function name
the time_expire defaults to None (no cache expiration)
if cache_model is "ram" then the model is current.cache.ram, etc.
If a key is not provided, one is generated from the function name
`time_expire` defaults to None (no cache expiration)
If cache_model is "ram" then the model is current.cache.ram, etc.
"""
def decorator(f, key=key, time_expire=time_expire, cache_model=cache_model):
key = key or repr(f)

View File

@@ -2,19 +2,19 @@
# -*- coding: utf-8 -*-
"""
This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
| This file is part of the web2py Web Framework
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
Functions required to execute app components
============================================
--------------------------------------------
FOR INTERNAL USE ONLY
Note:
FOR INTERNAL USE ONLY
"""
from os import stat
import thread
import logging
from gluon.fileutils import read_file
cfs = {} # for speed-up
@@ -26,11 +26,12 @@ def getcfs(key, filename, filter=None):
Caches the *filtered* file `filename` with `key` until the file is
modified.
:param key: the cache key
:param filename: the file to cache
:param filter: is the function used for filtering. Normally `filename` is a
.py file and `filter` is a function that bytecode compiles the file.
In this way the bytecode compiled file is cached. (Default = None)
Args:
key(str): the cache key
filename: the file to cache
filter: is the function used for filtering. Normally `filename` is a
.py file and `filter` is a function that bytecode compiles the file.
In this way the bytecode compiled file is cached. (Default = None)
This is used on Google App Engine since pyc files cannot be saved.
"""

View File

@@ -2,14 +2,15 @@
# -*- coding: utf-8 -*-
"""
This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
| This file is part of the web2py Web Framework
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
Functions required to execute app components
============================================
--------------------------------------------
FOR INTERNAL USE ONLY
Note:
FOR INTERNAL USE ONLY
"""
import re
@@ -125,16 +126,27 @@ def LOAD(c=None, f='index', args=None, vars=None,
extension=None, target=None, ajax=False, ajax_trap=False,
url=None, user_signature=False, timeout=None, times=1,
content='loading...', **attr):
""" LOAD a component into the action's document
""" LOADs a component into the action's document
Timing options:
-times: An integer or string ("infinity"/"continuous")
specifies how many times the component is requested
-timeout (milliseconds): specifies the time to wait before
starting the request or the frequency if times is greater than
1 or "infinity".
Timing options default to the normal behavior. The component
is added on page loading without delay.
Args:
c(str): controller
f(str): function
args(tuple or list): arguments
vars(dict): vars
extension(str): extension
target(str): id of the target
ajax(bool): True to enable AJAX bahaviour
ajax_trap(bool): True if `ajax` is set to `True`, traps
both links and forms "inside" the target
url(str): overrides `c`,`f`,`args` and `vars`
user_signature(bool): adds hmac signature to all links
with a key that is different for every user
timeout(int): in milliseconds, specifies the time to wait before
starting the request or the frequency if times is greater than
1 or "infinity"
times(integer or str): how many times the component will be requested
"infinity" or "continuous" are accepted to reload indefinitely the
component
"""
from html import TAG, DIV, URL, SCRIPT, XML
if args is None:
@@ -440,7 +452,8 @@ def read_pyc(filename):
Read the code inside a bytecode compiled file if the MAGIC number is
compatible
:returns: a code object
Returns:
a code object
"""
data = read_file(filename, 'rb')
if not is_gae and data[:4] != imp.get_magic():
@@ -518,7 +531,7 @@ def run_models_in(environment):
folder = environment['request'].folder
c = environment['request'].controller
f = environment['request'].function
f = environment['request'].function
response = environment['response']
path = pjoin(folder, 'models')
@@ -528,7 +541,7 @@ def run_models_in(environment):
models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0), model_cmp)
else:
models = sorted(listdir(path, '^\w+\.py$', 0, sort=False), model_cmp_sep)
models_to_run = None
models_to_run = None
for model in models:
if response.models_to_run != models_to_run:
regex = models_to_run = response.models_to_run[:]
@@ -540,7 +553,7 @@ def run_models_in(environment):
fname = model[n:-4].replace('.','/')+'.py'
else:
n = len(path)+1
fname = model[n:].replace(os.path.sep,'/')
fname = model[n:].replace(os.path.sep,'/')
if not regex.search(fname) and c != 'appadmin':
continue
elif compiled:
@@ -573,7 +586,7 @@ def run_controller_in(controller, function, environment):
filename = pjoin(path, 'controllers_%s_%s.pyc'
% (controller, function))
### end for backward compatibility
if not os.path.exists(filename):
if not os.path.exists(filename):
raise HTTP(404,
rewrite.THREAD_LOCAL.routes.error_message % badf,
web2py_error=badf)

View File

@@ -2,22 +2,22 @@
# -*- coding: utf-8 -*-
"""
This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
| This file is part of the web2py Web Framework
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
CONTENT_TYPE dictionary created against freedesktop.org' shared mime info
CONTENT_TYPE dictionary created against freedesktop.org's shared mime info
database version 1.1.
Deviations from official standards:
- '.md': 'application/x-genesis-rom' --> 'text/x-markdown'
- '.png': 'image/x-apple-ios-png' --> 'image/png'
- .md: application/x-genesis-rom --> text/x-markdown
- .png: image/x-apple-ios-png --> image/png
Additions:
- '.load': 'text/html'
- '.json': 'application/json'
- '.jsonp': 'application/jsonp'
- '.pickle': 'application/python-pickle'
- '.w2p': 'application/w2p'
- .load: text/html
- .json: application/json
- .jsonp: application/jsonp
- .pickle: application/python-pickle
- .w2p': application/w2p
"""
__all__ = ['contenttype']