From 469750e22e765f051b459b378d0edc1ff060f4ce Mon Sep 17 00:00:00 2001 From: Dan Radez Date: Wed, 3 Apr 2024 12:04:58 -0400 Subject: [PATCH 01/69] Updates to satsify pep257 violations --- cherrypy/_cpcompat.py | 9 ++-- cherrypy/_cpdispatch.py | 21 ++++++-- cherrypy/_cperror.py | 19 ++++--- cherrypy/_cplogging.py | 14 ++++-- cherrypy/_cpmodpy.py | 10 ++++ cherrypy/_cpreqbody.py | 30 ++++++++--- cherrypy/_cprequest.py | 31 ++++++++++-- cherrypy/_cptools.py | 26 +++++++--- cherrypy/_cpwsgi.py | 50 ++++++++++++------- cherrypy/lib/auth_basic.py | 9 ++-- cherrypy/lib/auth_digest.py | 41 ++++++++++----- cherrypy/lib/caching.py | 4 +- cherrypy/lib/covercp.py | 10 +++- cherrypy/lib/cpstats.py | 21 +++++++- cherrypy/lib/cptools.py | 13 +++-- cherrypy/lib/encoding.py | 14 ++++++ cherrypy/lib/gctools.py | 10 ++++ cherrypy/lib/httputil.py | 31 +++++++++--- cherrypy/lib/jsontools.py | 5 +- cherrypy/lib/locking.py | 13 ++++- cherrypy/lib/profiler.py | 19 ++++++- cherrypy/lib/reprconf.py | 16 ++++-- cherrypy/lib/sessions.py | 46 ++++++++++++----- cherrypy/process/plugins.py | 22 ++++++-- cherrypy/process/servers.py | 22 ++++++-- cherrypy/process/win32.py | 10 ++++ cherrypy/test/__init__.py | 9 +++- cherrypy/test/_test_decorators.py | 8 +++ cherrypy/test/_test_states_demo.py | 9 ++++ cherrypy/test/benchmark.py | 21 ++++++-- cherrypy/test/checkerdemo.py | 2 + cherrypy/test/helper.py | 33 +++++++++--- cherrypy/test/logtest.py | 3 ++ cherrypy/test/modfastcgi.py | 7 +++ cherrypy/test/modfcgid.py | 6 +++ cherrypy/test/modpy.py | 6 +++ cherrypy/test/modwsgi.py | 4 ++ cherrypy/test/sessiondemo.py | 5 ++ cherrypy/test/webtest.py | 2 +- cherrypy/tutorial/__init__.py | 2 +- cherrypy/tutorial/tut01_helloworld.py | 3 +- cherrypy/tutorial/tut02_expose_methods.py | 15 ++++-- cherrypy/tutorial/tut03_get_and_post.py | 26 ++++++---- cherrypy/tutorial/tut04_complex_site.py | 11 +++- cherrypy/tutorial/tut05_derived_objects.py | 13 ++++- cherrypy/tutorial/tut06_default_method.py | 23 ++++++--- cherrypy/tutorial/tut07_sessions.py | 4 +- .../tutorial/tut08_generators_and_yield.py | 6 ++- cherrypy/tutorial/tut09_files.py | 7 ++- cherrypy/tutorial/tut10_http_errors.py | 9 ++-- 50 files changed, 593 insertions(+), 157 deletions(-) diff --git a/cherrypy/_cpcompat.py b/cherrypy/_cpcompat.py index a43f6d369..c955478b9 100644 --- a/cherrypy/_cpcompat.py +++ b/cherrypy/_cpcompat.py @@ -22,18 +22,14 @@ def ntob(n, encoding='ISO-8859-1'): - """Return the given native string as a byte string in the given - encoding. - """ + """Return given native string as a byte str in the given encoding.""" assert_native(n) # In Python 3, the native string type is unicode return n.encode(encoding) def ntou(n, encoding='ISO-8859-1'): - """Return the given native string as a unicode string with the given - encoding. - """ + """Return given native string as a unicode str in the given encoding.""" assert_native(n) # In Python 3, the native string type is unicode return n @@ -48,6 +44,7 @@ def tonative(n, encoding='ISO-8859-1'): def assert_native(n): + """Assert if native string.""" if not isinstance(n, str): raise TypeError('n must be a native str (got %s)' % type(n).__name__) diff --git a/cherrypy/_cpdispatch.py b/cherrypy/_cpdispatch.py index 5a3a8ad60..9373cccfd 100644 --- a/cherrypy/_cpdispatch.py +++ b/cherrypy/_cpdispatch.py @@ -25,6 +25,7 @@ class PageHandler(object): """Callable which sets response.body.""" def __init__(self, callable, *args, **kwargs): + """Initialize PageHandler.""" self.callable = callable self.args = args self.kwargs = kwargs @@ -36,6 +37,7 @@ def args(self): @args.setter def args(self, args): + """Setter for ordered args.""" cherrypy.serving.request.args = args return cherrypy.serving.request.args @@ -46,10 +48,12 @@ def kwargs(self): @kwargs.setter def kwargs(self, kwargs): + """Setter for named kwargs.""" cherrypy.serving.request.kwargs = kwargs return cherrypy.serving.request.kwargs def __call__(self): + """Call handler for PageHandler.""" try: return self.callable(*self.args, **self.kwargs) except TypeError: @@ -203,15 +207,18 @@ def test_callable_spec(callable, callable_args, callable_kwargs): import inspect except ImportError: def test_callable_spec(callable, args, kwargs): # noqa: F811 + """Test callable spec.""" return None else: def getargspec(callable): + """Get arg spec.""" return inspect.getfullargspec(callable)[:4] class LateParamPageHandler(PageHandler): + """LateParamPageHandler PageHandler class. - """When passing cherrypy.request.params to the page handler, we do not + When passing cherrypy.request.params to the page handler, we do not want to capture that dict too early; we want to give tools like the decoding tool a chance to modify the params dict in-between the lookup of the handler and the actual calling of the handler. This subclass @@ -221,7 +228,7 @@ class LateParamPageHandler(PageHandler): @property def kwargs(self): - """Page handler kwargs (with cherrypy.request.params copied in).""" + """Page handler kwargs with cherrypy.request.params copied in.""" kwargs = cherrypy.serving.request.params.copy() if self._kwargs: kwargs.update(self._kwargs) @@ -229,6 +236,7 @@ def kwargs(self): @kwargs.setter def kwargs(self, kwargs): + """Setter for kwargs.""" cherrypy.serving.request.kwargs = kwargs self._kwargs = kwargs @@ -238,6 +246,7 @@ def kwargs(self, kwargs): string.punctuation, '_' * len(string.punctuation)) def validate_translator(t): + """Validate translator.""" if not isinstance(t, str) or len(t) != 256: raise ValueError( 'The translate argument must be a str of len 256.') @@ -246,6 +255,7 @@ def validate_translator(t): string.punctuation, '_' * len(string.punctuation)) def validate_translator(t): + """Validate translator.""" if not isinstance(t, dict): raise ValueError('The translate argument must be a dict.') @@ -273,6 +283,7 @@ class Dispatcher(object): def __init__(self, dispatch_method_name=None, translate=punctuation_to_underscores): + """Initialize Dispatcher.""" validate_translator(translate) self.translate = translate if dispatch_method_name: @@ -389,8 +400,7 @@ def find_handler(self, path): object_trail.append([name, node, nodeconf, segleft]) def set_conf(): - """Collapse all object_trail config into cherrypy.request.config. - """ + """Collapse all object_trail conf into cherrypy.request.config.""" base = cherrypy.config.copy() # Note that we merge the config from each node # even if that node was None. @@ -505,10 +515,12 @@ def __init__(self, full_result=False, **mapper_options): self.mapper.controller_scan = self.controllers.keys def connect(self, name, route, controller, **kwargs): + """Connect.""" self.controllers[name] = controller self.mapper.connect(name, route, controller=name, **kwargs) def redirect(self, url): + """Redirect.""" raise cherrypy.HTTPRedirect(url) def __call__(self, path_info): @@ -602,6 +614,7 @@ def merge(nodeconf): def XMLRPCDispatcher(next_dispatcher=Dispatcher()): + """Xml RPC Dispatcher class.""" from cherrypy.lib import xmlrpcutil def xmlrpc_dispatch(path_info): diff --git a/cherrypy/_cperror.py b/cherrypy/_cperror.py index 203fabf5c..009123136 100644 --- a/cherrypy/_cperror.py +++ b/cherrypy/_cperror.py @@ -137,6 +137,7 @@ class Root: class CherryPyException(Exception): """A base class for CherryPy exceptions.""" + pass @@ -150,6 +151,7 @@ class InternalRedirect(CherryPyException): """ def __init__(self, path, query_string=''): + """Initialize InternalRedirect.""" self.request = cherrypy.serving.request self.query_string = query_string @@ -202,6 +204,7 @@ class HTTPRedirect(CherryPyException): """The encoding when passed urls are not native strings.""" def __init__(self, urls, status=None, encoding=None): + """Initialize HTTPRedirect.""" self.urls = abs_urls = [ # Note that urljoin will "do the right thing" whether url is: # 1. a complete URL with host (e.g. "http://www.example.com/test") @@ -227,7 +230,7 @@ def __init__(self, urls, status=None, encoding=None): @classproperty def default_status(cls): - """The default redirect status for the request. + """Redirect status for the request, this is the default handler. RFC 2616 indicates a 301 response code fits our goal; however, browser support for 301 is quite messy. Use 302/303 instead. See @@ -242,8 +245,9 @@ def status(self): return status def set_response(self): - """Modify cherrypy.response status, headers, and body to represent - self. + """Modify cherrypy.response to represent self. + + Modifies status, headers, and body. CherryPy uses this internally, but you can also use it to create an HTTPRedirect object and set its output without *raising* the @@ -366,6 +370,7 @@ class HTTPError(CherryPyException): """The HTTP Reason-Phrase string.""" def __init__(self, status=500, message=None): + """Initialize HTTPError.""" self.status = status try: self.code, self.reason, defaultmsg = _httputil.valid_status(status) @@ -381,8 +386,9 @@ def __init__(self, status=500, message=None): CherryPyException.__init__(self, status, message) def set_response(self): - """Modify cherrypy.response status, headers, and body to represent - self. + """Modify cherrypy.response to represent self. + + Modifies status, headers, and body. CherryPy uses this internally, but you can also use it to create an HTTPError object and set its output without *raising* the @@ -408,6 +414,7 @@ def set_response(self): _be_ie_unfriendly(self.code) def get_error_page(self, *args, **kwargs): + """Get error page.""" return get_error_page(*args, **kwargs) def __call__(self): @@ -432,6 +439,7 @@ class NotFound(HTTPError): """ def __init__(self, path=None): + """Initialize NotFound HTTPError.""" if path is None: request = cherrypy.serving.request path = request.script_name + request.path_info @@ -600,7 +608,6 @@ def bare_error(extrabody=None): is set in the body. If extrabody is a string, it will be appended as-is to the body. """ - # The whole point of this function is to be a last line-of-defense # in handling errors. That is, it must not raise any errors itself; # it cannot be allowed to fail. Therefore, don't add to it! diff --git a/cherrypy/_cplogging.py b/cherrypy/_cplogging.py index 754ac7bf9..ac9c6a571 100644 --- a/cherrypy/_cplogging.py +++ b/cherrypy/_cplogging.py @@ -1,4 +1,6 @@ """ +Cherrpy Logging module. + Simple config ============= @@ -126,12 +128,15 @@ class NullHandler(logging.Handler): """A no-op logging handler to silence the logging.lastResort handler.""" def handle(self, record): + """Handle stub.""" pass def emit(self, record): + """Emit stub.""" pass def createLock(self): + """Create Lock stub.""" self.lock = None @@ -167,6 +172,7 @@ class LogManager(object): """ def __init__(self, appid=None, logger_root='cherrypy'): + """Initialize LogManager.""" self.logger_root = logger_root self.appid = appid if appid is None: @@ -217,11 +223,11 @@ def error(self, msg='', context='', severity=logging.INFO, ) def __call__(self, *args, **kwargs): - """An alias for ``error``.""" + """Call handler, An alias for ``error``.""" return self.error(*args, **kwargs) def access(self): - """Write to the access log (in Apache/NCSA Combined Log format). + r"""Write to the access log (in Apache/NCSA Combined Log format). See the `apache documentation @@ -414,7 +420,7 @@ def wsgi(self, newvalue): class WSGIErrorHandler(logging.Handler): - "A handler class which writes logging records to environ['wsgi.errors']." + """Handler class that writes logging records to environ['wsgi.errors'].""" def flush(self): """Flushes the stream.""" @@ -450,6 +456,8 @@ def emit(self, record): class LazyRfc3339UtcTime(object): + """LazyRfc3339UtcTime class.""" + def __str__(self): """Return datetime in RFC3339 UTC Format.""" iso_formatted_now = datetime.datetime.now( diff --git a/cherrypy/_cpmodpy.py b/cherrypy/_cpmodpy.py index 7c01233d8..9fd2490cf 100644 --- a/cherrypy/_cpmodpy.py +++ b/cherrypy/_cpmodpy.py @@ -72,6 +72,7 @@ def setup_server(): def setup(req): + """Handle setup.""" from mod_python import apache # Run any setup functions defined by a "PythonOption cherrypy.setup" @@ -140,6 +141,7 @@ def __init__(self, req): def handler(req): + """Run handler.""" from mod_python import apache try: global _isSetUp @@ -251,6 +253,7 @@ def handler(req): def send_response(req, status, headers, body, stream=False): + """Handle sending response.""" # Set response status req.status = int(status[:3]) @@ -276,17 +279,20 @@ def send_response(req, status, headers, body, stream=False): import subprocess def popen(fullcmd): + """Open process.""" p = subprocess.Popen(fullcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) return p.stdout except ImportError: def popen(fullcmd): + """Open process.""" pipein, pipeout = os.popen4(fullcmd) return pipeout def read_process(cmd, args=''): + """Handle read process.""" fullcmd = '%s %s' % (cmd, args) pipeout = popen(fullcmd) try: @@ -305,6 +311,7 @@ def read_process(cmd, args=''): class ModPythonServer(object): + """Mod Python Server class.""" template = """ # Apache2 server configuration file for running CherryPy with mod_python. @@ -323,6 +330,7 @@ class ModPythonServer(object): def __init__(self, loc='/', port=80, opts=None, apache_path='apache', handler='cherrypy._cpmodpy::handler'): + """Initialize ModPythonServer.""" self.loc = loc self.port = port self.opts = opts @@ -330,6 +338,7 @@ def __init__(self, loc='/', port=80, opts=None, apache_path='apache', self.handler = handler def start(self): + """Handle start.""" opts = ''.join([' PythonOption %s %s\n' % (k, v) for k, v in self.opts]) conf_data = self.template % {'port': self.port, @@ -347,5 +356,6 @@ def start(self): return response def stop(self): + """Handle stop.""" os.popen('apache -k stop') self.ready = False diff --git a/cherrypy/_cpreqbody.py b/cherrypy/_cpreqbody.py index 7e0d98bee..672bb7e40 100644 --- a/cherrypy/_cpreqbody.py +++ b/cherrypy/_cpreqbody.py @@ -220,8 +220,7 @@ def process_multipart(entity): def process_multipart_form_data(entity): - """Read all multipart/form-data parts into entity.parts or entity.params. - """ + """Read multipart/form-data parts into entity.parts or entity.params.""" process_multipart(entity) kept_parts = [] @@ -248,7 +247,7 @@ def process_multipart_form_data(entity): def _old_process_multipart(entity): - """The behavior of 3.2 and lower. + """Behavior of 3.2 and lower. Deprecated and will be changed in 3.3. """ @@ -411,6 +410,7 @@ class Entity(object): """ def __init__(self, fp, headers, params=None, parts=None): + """Initialize Entity.""" # Make an instance-specific copy of the class processors # so Tools, etc. can replace them per-request. self.processors = self.processors.copy() @@ -479,24 +479,30 @@ def __init__(self, fp, headers, params=None, parts=None): self.filename = unquote(str(filename), encoding) def read(self, size=None, fp_out=None): + """Handle read.""" return self.fp.read(size, fp_out) def readline(self, size=None): + """Handle readline.""" return self.fp.readline(size) def readlines(self, sizehint=None): + """Handle readlines.""" return self.fp.readlines(sizehint) def __iter__(self): + """Handle iterations.""" return self def __next__(self): + """Handle next.""" line = self.readline() if not line: raise StopIteration return line def next(self): + """Handle next.""" return self.__next__() def read_into_file(self, fp_out=None): @@ -564,8 +570,10 @@ def process(self): proc(self) def default_proc(self): - """Called if a more-specific processor is not found for the - ``Content-Type``. + """Handle default proc. + + Called if a more-specific processor is not found for the + ``Content-Type`` """ # Leave the fp alone for someone else to read. This works fine # for request.body, but the Part subclasses need to override this @@ -614,6 +622,7 @@ class Part(Entity): """ def __init__(self, fp, headers, boundary): + """Initialize Part.""" Entity.__init__(self, fp, headers) self.boundary = boundary self.file = None @@ -621,11 +630,13 @@ def __init__(self, fp, headers, boundary): @classmethod def from_fp(cls, fp, boundary): + """Load from fp.""" headers = cls.read_headers(fp) return cls(fp, headers, boundary) @classmethod def read_headers(cls, fp): + """Read headers.""" headers = httputil.HeaderMap() while True: line = fp.readline() @@ -713,7 +724,9 @@ def read_lines_to_boundary(self, fp_out=None): return fp_out def default_proc(self): - """Called if a more-specific processor is not found for the + """Handle default proc. + + Called if a more-specific processor is not found for the ``Content-Type``. """ if self.filename: @@ -743,9 +756,11 @@ def read_into_file(self, fp_out=None): class SizedReader: + """SizedReader class.""" def __init__(self, fp, length, maxbytes, bufsize=DEFAULT_BUFFER_SIZE, has_trailers=False): + """Initialize SizedReader.""" # Wrap our fp in a buffer so peek() works self.fp = fp self.length = length @@ -773,7 +788,6 @@ def read(self, size=None, fp_out=None): object that supports the 'write' method; all bytes read will be written to the fp, and None is returned. """ - if self.length is None: if size is None: remaining = inf @@ -889,6 +903,7 @@ def readlines(self, sizehint=None): return lines def finish(self): + """Handle finish.""" self.done = True if self.has_trailers and hasattr(self.fp, 'read_trailer_lines'): self.trailers = {} @@ -946,6 +961,7 @@ class RequestBody(Entity): """ def __init__(self, fp, headers, params=None, request_params=None): + """Initialize RequestBody.""" Entity.__init__(self, fp, headers, params) # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1 diff --git a/cherrypy/_cprequest.py b/cherrypy/_cprequest.py index a4ad298b0..a9eb28710 100644 --- a/cherrypy/_cprequest.py +++ b/cherrypy/_cprequest.py @@ -42,6 +42,7 @@ class Hook(object): callable on each call.""" def __init__(self, callback, failsafe=None, priority=None, **kwargs): + """Initialize Hook.""" self.callback = callback if failsafe is None: @@ -56,6 +57,14 @@ def __init__(self, callback, failsafe=None, priority=None, **kwargs): def __lt__(self, other): """ + Less-Than Hook Operator. + + :param other: A Hook Object to compare priority with + :type other: Hook + + :return: Other Hook's priority is higher than this one + :rtype: Bool + Hooks sort by priority, ascending, such that hooks of lower priority are run first. """ @@ -66,6 +75,7 @@ def __call__(self): return self.callback(**self.kwargs) def __repr__(self): + """Represent Hook.""" cls = self.__class__ return ('%s.%s(callback=%r, failsafe=%r, priority=%r, %s)' % (cls.__module__, cls.__name__, self.callback, @@ -78,12 +88,14 @@ class HookMap(dict): """A map of call points to lists of callbacks (Hook objects).""" def __new__(cls, points=None): + """Handle New HookMap.""" d = dict.__new__(cls) for p in points or []: d[p] = [] return d def __init__(self, *a, **kw): + """Initialize HookMap.""" pass def attach(self, point, callback, failsafe=None, priority=None, **kwargs): @@ -124,6 +136,7 @@ def run_hooks(cls, hooks): raise def __copy__(self): + """Copy.""" newmap = self.__class__() # We can't just use 'update' because we want copies of the # mutable values (each is a list) as well. @@ -133,6 +146,7 @@ def __copy__(self): copy = __copy__ def __repr__(self): + """Represent HookMap.""" cls = self.__class__ return '%s.%s(points=%r)' % ( cls.__module__, @@ -541,7 +555,7 @@ def close(self): self.stage = 'close' def run(self, method, path, query_string, req_protocol, headers, rfile): - r"""Process the Request. (Core) + r"""Process the Request (Core). method, path, query_string, and req_protocol should be pulled directly from the Request-Line (e.g. "GET /path?key=val HTTP/1.0"). @@ -815,6 +829,7 @@ class ResponseBody(object): 'if you wish to return unicode.') def __get__(self, obj, objclass=None): + """Handle get for ReponseBody.""" if obj is None: # When calling on the class instead of an instance... return self @@ -822,7 +837,7 @@ def __get__(self, obj, objclass=None): return obj._body def __set__(self, obj, value): - # Convert the given value to an iterable object. + """Convert the given value to an iterable object.""" if isinstance(value, str): raise ValueError(self.unicode_err) elif isinstance(value, list): @@ -874,6 +889,7 @@ class Response(object): """If False, buffer the response body.""" def __init__(self): + """Intialize Response.""" self.status = None self.header_list = None self._body = [] @@ -896,8 +912,13 @@ def collapse_body(self): return new_body def _flush_body(self): - """Discard self.body but consume any generator such that any - finalization can occur, such as is required by caching.tee_output().""" + """_flush_body Response. + + :rtype: None + + Discard self.body but consume any generator such that any + finalization can occur, such as is required by caching.tee_output(). + """ consume(iter(self.body)) def finalize(self): @@ -951,6 +972,8 @@ def finalize(self): class LazyUUID4(object): + """LazyUUID4 class.""" + def __str__(self): """Return UUID4 and keep it for future calls.""" return str(self.uuid4) diff --git a/cherrypy/_cptools.py b/cherrypy/_cptools.py index e47c046ea..610ebfa21 100644 --- a/cherrypy/_cptools.py +++ b/cherrypy/_cptools.py @@ -57,6 +57,7 @@ class Tool(object): namespace = 'tools' def __init__(self, point, callable, name=None, priority=50): + """Initialize Tool.""" self._point = point self.callable = callable self._name = name @@ -66,10 +67,12 @@ def __init__(self, point, callable, name=None, priority=50): @property def on(self): + """Property on.""" raise AttributeError(_attr_error) @on.setter def on(self, value): + """Setter for on property.""" raise AttributeError(_attr_error) def _setargs(self): @@ -133,7 +136,7 @@ def tool_decorator(f): return tool_decorator def _setup(self): - """Hook this tool into cherrypy.request. + """Hooking this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -159,6 +162,7 @@ class HandlerTool(Tool): """ def __init__(self, callable, name=None): + """Initialize HandlerTool.""" Tool.__init__(self, 'before_handler', callable, name) def handler(self, *args, **kwargs): @@ -183,7 +187,7 @@ def _wrapper(self, **kwargs): cherrypy.serving.request.handler = None def _setup(self): - """Hook this tool into cherrypy.request. + """Hooking this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -217,12 +221,14 @@ def interpolator(next_handler, *args, **kwargs): def __init__(self, newhandler, point='before_handler', name=None, priority=50): + """Initialize HandlerWrapperTool.""" self.newhandler = newhandler self._point = point self._name = name self._priority = priority def callable(self, *args, **kwargs): + """Make HandlerWrapperTool callable.""" innerfunc = cherrypy.serving.request.handler def wrap(*args, **kwargs): @@ -234,13 +240,14 @@ class ErrorTool(Tool): """Tool which is used to replace the default request.error_response.""" def __init__(self, callable, name=None): + """Initialize ErrorTool.""" Tool.__init__(self, None, callable, name) def _wrapper(self): self.callable(**self._merged_args()) def _setup(self): - """Hook this tool into cherrypy.request. + """Hooking this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -270,6 +277,7 @@ class SessionTool(Tool): """ def __init__(self): + """Initialize SessionTool.""" # _sessions.init must be bound after headers are read Tool.__init__(self, 'before_request_body', _sessions.init) @@ -277,7 +285,7 @@ def _lock_session(self): cherrypy.serving.session.acquire_lock() def _setup(self): - """Hook this tool into cherrypy.request. + """Hooking this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -360,6 +368,7 @@ class XMLRPCController(object): @expose def default(self, *vpath, **params): + """Handle default XMLRPCController.""" rpcparams, rpcmethod = _xmlrpc.process_body() subhandler = self @@ -384,6 +393,8 @@ def default(self, *vpath, **params): class SessionAuthTool(HandlerTool): + """Stub for SessionAuthTool.""" + pass @@ -402,7 +413,7 @@ def _wrapper(self, **kwargs): _wrapper.priority = 90 def _setup(self): - """Hook caching into cherrypy.request.""" + """Hooking caching into cherrypy.request.""" conf = self._merged_args() p = conf.pop('priority', None) @@ -419,9 +430,11 @@ class Toolbox(object): """ def __init__(self, namespace): + """Initialize Toolbox.""" self.namespace = namespace def __setattr__(self, name, value): + """Set attribute for Toolbox.""" # If the Tool._name is None, supply it from the attribute name. if isinstance(value, Tool): if value._name is None: @@ -449,7 +462,8 @@ def __exit__(self, exc_type, exc_val, exc_tb): tool._setup() def register(self, point, **kwargs): - """ + """Register Toolbox. + Return a decorator which registers the function at the given hook point. """ diff --git a/cherrypy/_cpwsgi.py b/cherrypy/_cpwsgi.py index b2a6da52a..f022a469e 100644 --- a/cherrypy/_cpwsgi.py +++ b/cherrypy/_cpwsgi.py @@ -18,8 +18,7 @@ def downgrade_wsgi_ux_to_1x(environ): - """Return a new environ dict for WSGI 1.x from the given WSGI u.x environ. - """ + """Return new environ dict for WSGI 1.x from provided WSGI u.x environ.""" env1x = {} url_encoding = environ[ntou('wsgi.url_encoding')] @@ -54,33 +53,36 @@ class VirtualHost(object): cherrypy.tree.graft(vhost) """ - default = None - """Required. - - The default WSGI application. - """ + default = None use_x_forwarded_host = True - """If True (the default), any "X-Forwarded-Host" - request header will be used instead of the "Host" header. This - is commonly added by HTTP servers (such as Apache) when proxying.""" - domains = {} - """A dict of {host header value: application} pairs. - - The incoming "Host" request header is looked up in this dict, and, - if a match is found, the corresponding WSGI application will be - called instead of the default. Note that you often need separate - entries for "example.com" and "www.example.com". In addition, "Host" - headers may contain the port number. - """ def __init__(self, default, domains=None, use_x_forwarded_host=True): + """ + Initialize VirtualHost. + + :param default: The default WSGI application + :type default: WSGI application + :param use_x_forwarded_host: If True (the default), any + "X-Forwarded-Host" request header will be used instead of the + "Host" header. This is commonly added by HTTP servers (such as + Apache) when proxying. + :type use_x_forwarded_host: Bool, optional + :param domains: A dict of {host header value: application} pairs. + The incoming "Host" request header is looked up in this dict, and, + if a match is found, the corresponding WSGI application will be + called instead of the default. Note that you often need separate + entries for "example.com" and "www.example.com". In addition, + "Host" headers may contain the port number. + :type domains: Dict, optional + """ self.default = default self.domains = domains or {} self.use_x_forwarded_host = use_x_forwarded_host def __call__(self, environ, start_response): + """Call VirtualHost.""" domain = environ.get('HTTP_HOST', '') if self.use_x_forwarded_host: domain = environ.get('HTTP_X_FORWARDED_HOST', domain) @@ -95,10 +97,12 @@ class InternalRedirector(object): """WSGI middleware that handles raised cherrypy.InternalRedirect.""" def __init__(self, nextapp, recursive=False): + """Initialize InternalRedirector.""" self.nextapp = nextapp self.recursive = recursive def __call__(self, environ, start_response): + """Initialize InternalRedirector.""" redirections = [] while True: environ = environ.copy() @@ -142,10 +146,12 @@ class ExceptionTrapper(object): """WSGI middleware that traps exceptions.""" def __init__(self, nextapp, throws=(KeyboardInterrupt, SystemExit)): + """Initialize ExceptionTrapper.""" self.nextapp = nextapp self.throws = throws def __call__(self, environ, start_response): + """Call ExceptionTrapper.""" return _TrappedResponse( self.nextapp, environ, @@ -230,6 +236,7 @@ class AppResponse(object): """WSGI response iterable for CherryPy applications.""" def __init__(self, environ, start_response, cpapp): + """Initialize AppResponse.""" self.cpapp = cpapp try: self.environ = environ @@ -271,9 +278,11 @@ def __init__(self, environ, start_response, cpapp): raise def __iter__(self): + """Handle iteration for AppResponse.""" return self def __next__(self): + """Handle next for AppResponse.""" return next(self.iter_response) def close(self): @@ -346,6 +355,7 @@ def run(self): } def recode_path_qs(self, path, qs): + """Recode path qs AppResponse.""" # This isn't perfect; if the given PATH_INFO is in the # wrong encoding, it may fail to match the appropriate config # section URI. But meh. @@ -416,6 +426,7 @@ class CPWSGIApp(object): """ def __init__(self, cpapp, pipeline=None): + """Initialize CPWSGIApp.""" self.cpapp = cpapp self.pipeline = self.pipeline[:] if pipeline: @@ -431,6 +442,7 @@ def tail(self, environ, start_response): return self.response_class(environ, start_response, self.cpapp) def __call__(self, environ, start_response): + """Handle call to CPWSGIApp.""" head = self.head if head is None: # Create and nest the WSGI apps in our pipeline (in reverse order). diff --git a/cherrypy/lib/auth_basic.py b/cherrypy/lib/auth_basic.py index b938a5600..bf57d77e1 100644 --- a/cherrypy/lib/auth_basic.py +++ b/cherrypy/lib/auth_basic.py @@ -33,7 +33,9 @@ def checkpassword_dict(user_password_dict): - """Returns a checkpassword function which checks credentials + """Check credentials against a dictionary. + + Returns a checkpassword function which checks credentials against a dictionary of the form: {username : password}. If you want a simple dictionary-based authentication scheme, use @@ -48,7 +50,9 @@ def checkpassword(realm, user, password): def basic_auth(realm, checkpassword, debug=False, accept_charset='utf-8'): - """A CherryPy tool which hooks at before_handler to perform + """Perform basic auth. + + A CherryPy tool which hooks at before_handler to perform HTTP Basic Access Authentication, as specified in :rfc:`2617` and :rfc:`7617`. @@ -69,7 +73,6 @@ def basic_auth(realm, checkpassword, debug=False, accept_charset='utf-8'): returns True, else it returns False. """ - fallback_charset = 'ISO-8859-1' if '"' in realm: diff --git a/cherrypy/lib/auth_digest.py b/cherrypy/lib/auth_digest.py index 467492689..f8b5d698a 100644 --- a/cherrypy/lib/auth_digest.py +++ b/cherrypy/lib/auth_digest.py @@ -34,6 +34,7 @@ def md5_hex(s): + """Return hexdigest of md5sum.""" return md5(ntob(s, 'utf-8')).hexdigest() @@ -48,6 +49,7 @@ def md5_hex(s): def TRACE(msg): + """Log message in TOOLS.AUTH_DIGEST context.""" cherrypy.log(msg, context='TOOLS.AUTH_DIGEST') # Three helper functions for users of the tool, providing three variants @@ -55,8 +57,9 @@ def TRACE(msg): def get_ha1_dict_plain(user_password_dict): - """Return a get_ha1 function which obtains a plaintext password from a - dictionary of the form: {username : password}. + """Return a get_ha1 function which obtains a plaintext password. + + user_password_dict is a dictionary of the form: {username : password}. If you want a simple dictionary-based authentication scheme, with plaintext passwords, use get_ha1_dict_plain(my_userpass_dict) as the value for the @@ -72,8 +75,9 @@ def get_ha1(realm, username): def get_ha1_dict(user_ha1_dict): - """Return a get_ha1 function which obtains a HA1 password hash from a - dictionary of the form: {username : HA1}. + """Return a get_ha1 function which obtains a HA1 password hash. + + user_ha1_dict is a dictionary of the form: {username : HA1}. If you want a dictionary-based authentication scheme, but with pre-computed HA1 hashes instead of plain-text passwords, use @@ -87,7 +91,9 @@ def get_ha1(realm, username): def get_ha1_file_htdigest(filename): - """Return a get_ha1 function which obtains a HA1 password hash from a + """Return a get_ha1 function. + + The returned function obtains a HA1 password hash from a flat file with lines of the same format as that produced by the Apache htdigest utility. For example, for realm 'wonderland', username 'alice', and password '4x5istwelve', the htdigest line would be:: @@ -113,7 +119,9 @@ def get_ha1(realm, username): def synthesize_nonce(s, key, timestamp=None): - """Synthesize a nonce value which resists spoofing and can be checked + """Synthesize a nonce value. + + A nonce value resists spoofing and can be checked for staleness. Returns a string suitable as the value for 'nonce' in the www-authenticate header. @@ -135,7 +143,7 @@ def synthesize_nonce(s, key, timestamp=None): def H(s): - """The hash function H.""" + """Return an md5_hex hash.""" return md5_hex(s) @@ -152,18 +160,20 @@ def _try_decode_header(header, charset): class HttpDigestAuthorization(object): - """ - Parses a Digest Authorization header and performs - re-calculation of the digest. + """Parses a Digest Authorization header. + + Parses and performs re-calculation of the digest. """ scheme = 'digest' def errmsg(self, s): + """Error message for HttpDigestAuthorization.""" return 'Digest Authorization header: %s' % s @classmethod def matches(cls, header): + """Compare cls.scheme to header.scheme.""" scheme, _, _ = header.partition(' ') return scheme.lower() == cls.scheme @@ -171,6 +181,7 @@ def __init__( self, auth_header, http_method, debug=False, accept_charset=DEFAULT_CHARSET[:], ): + """Initialize HttpDigestAuthorization.""" self.http_method = http_method self.debug = debug @@ -229,10 +240,12 @@ def __init__( 'neither cnonce nor nc can be present')) def __str__(self): + """Stringify represetation of HttpDigestAuthorization.""" return 'authorization : %s' % self.auth_header def validate_nonce(self, s, key): """Validate the nonce. + Returns True if nonce was generated by synthesize_nonce() and the timestamp is not spoofed, else returns False. @@ -298,7 +311,7 @@ def HA2(self, entity_body=''): return H(a2) def request_digest(self, ha1, entity_body=''): - """Calculates the Request-Digest. See :rfc:`2617` section 3.2.2.1. + """Calculate the Request-Digest. See :rfc:`2617` section 3.2.2.1. ha1 The HA1 string obtained from the credentials store. @@ -351,7 +364,7 @@ def www_authenticate( realm, key, algorithm='MD5', nonce=None, qop=qop_auth, stale=False, accept_charset=DEFAULT_CHARSET[:], ): - """Constructs a WWW-Authenticate header for Digest authentication.""" + """Construct a WWW-Authenticate header for Digest authentication.""" if qop not in valid_qops: raise ValueError("Unsupported value for qop: '%s'" % qop) if algorithm not in valid_algorithms: @@ -374,7 +387,9 @@ def www_authenticate( def digest_auth(realm, get_ha1, key, debug=False, accept_charset='utf-8'): - """A CherryPy tool that hooks at before_handler to perform + """Perform HTTP Digest Access Authentication. + + A CherryPy tool that hooks at before_handler to perform HTTP Digest Access Authentication, as specified in :rfc:`2617`. If the request has an 'authorization' header with a 'Digest' scheme, diff --git a/cherrypy/lib/caching.py b/cherrypy/lib/caching.py index 89cb0442a..ed0b534ff 100644 --- a/cherrypy/lib/caching.py +++ b/cherrypy/lib/caching.py @@ -1,4 +1,6 @@ """ +CherryPy Cache implementation. + CherryPy implements a simple caching system as a pluggable Tool. This tool tries to be an (in-process) HTTP/1.1-compliant cache. It's not quite there yet, but it's probably good enough for most sites. @@ -161,6 +163,7 @@ class MemoryCache(Cache): debug = False def __init__(self): + """Initialize Memory Caching.""" self.clear() # Run self.expire_cache in a separate daemon thread. @@ -442,7 +445,6 @@ def expires(secs=0, force=False, debug=False): If any are already present, none of the above response headers are set. """ - response = cherrypy.serving.response headers = response.headers diff --git a/cherrypy/lib/covercp.py b/cherrypy/lib/covercp.py index f22cce742..4063f9f4d 100644 --- a/cherrypy/lib/covercp.py +++ b/cherrypy/lib/covercp.py @@ -38,6 +38,7 @@ the_coverage = coverage(data_file=localFile) def start(): + """Start coverage.""" the_coverage.start() except ImportError: # Setting the_coverage to None will raise errors @@ -50,6 +51,7 @@ def start(): 'coverage.py could not be imported.') def start(): + """Start coverage.""" pass start.priority = 20 @@ -284,8 +286,10 @@ def get_tree(base, exclude, coverage=the_coverage): class CoverStats(object): + """CoverStats route handler.""" def __init__(self, coverage, root=None): + """Initialize CoverStats.""" self.coverage = coverage if root is None: # Guess initial depth. Files outside this path will not be @@ -295,12 +299,13 @@ def __init__(self, coverage, root=None): @cherrypy.expose def index(self): + """Index of CoverStats.""" return TEMPLATE_FRAMESET % self.root.lower() @cherrypy.expose def menu(self, base='/', pct='50', showpct='', exclude=r'python\d\.\d|test|tut\d|tutorial'): - + """Return menu html content.""" # The coverage module uses all-lower-case names. base = base.lower().rstrip(os.sep) @@ -334,6 +339,7 @@ def menu(self, base='/', pct='50', showpct='', yield '' def annotated_file(self, filename, statements, excluded, missing): + """Return annotated file.""" with open(filename, 'r') as source: lines = source.readlines() buffer = [] @@ -358,6 +364,7 @@ def annotated_file(self, filename, statements, excluded, missing): @cherrypy.expose def report(self, name): + """Report coverage stats.""" filename, statements, excluded, missing, _ = self.coverage.analysis2( name) pc = _percent(statements, missing) @@ -374,6 +381,7 @@ def report(self, name): def serve(path=localFile, port=8080, root=None): + """Serve coverage server.""" if coverage is None: raise ImportError('The coverage module could not be imported.') from coverage import coverage diff --git a/cherrypy/lib/cpstats.py b/cherrypy/lib/cpstats.py index 5dff319b0..dfd1a5e29 100644 --- a/cherrypy/lib/cpstats.py +++ b/cherrypy/lib/cpstats.py @@ -249,6 +249,7 @@ def extrapolate_statistics(scope): def proc_time(s): + """Return proc time.""" return time.time() - s['Start Time'] @@ -256,20 +257,24 @@ class ByteCountWrapper(object): """Wraps a file-like object, counting the number of bytes read.""" def __init__(self, rfile): + """Initialize ByteCountWrapper.""" self.rfile = rfile self.bytes_read = 0 def read(self, size=-1): + """Read method for ByteCountWrapper.""" data = self.rfile.read(size) self.bytes_read += len(data) return data def readline(self, size=-1): + """Readline method for ByteCountWrapper.""" data = self.rfile.readline(size) self.bytes_read += len(data) return data def readlines(self, sizehint=0): + """Readline method for ByteCountWrapper.""" # Shamelessly stolen from StringIO total = 0 lines = [] @@ -283,22 +288,27 @@ def readlines(self, sizehint=0): return lines def close(self): + """Close method for ByteCountWrapper.""" self.rfile.close() def __iter__(self): + """Iterate method for ByteCountWrapper.""" return self def next(self): + """Next method for ByteCountWrapper.""" data = self.rfile.next() self.bytes_read += len(data) return data def average_uriset_time(s): + """Return the average uriset time.""" return s['Count'] and (s['Sum'] / s['Count']) or 0 def _get_threading_ident(): + """Get threading identity.""" if sys.version_info >= (3, 3): return threading.get_ident() return threading._get_ident() @@ -308,10 +318,11 @@ class StatsTool(cherrypy.Tool): """Record various information about the current request.""" def __init__(self): + """Initialize StatsTool.""" cherrypy.Tool.__init__(self, 'on_end_request', self.record_stop) def _setup(self): - """Hook this tool into cherrypy.request. + """Set Hook for this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -404,14 +415,17 @@ def record_stop( def locale_date(v): + """Return date formated for locale.""" return time.strftime('%c', time.gmtime(v)) def iso_format(v): + """Return date formated ISO.""" return time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(v)) def pause_resume(ns): + """Return pause and return forms.""" def _pause_resume(enabled): pause_disabled = '' resume_disabled = '' @@ -433,6 +447,7 @@ def _pause_resume(enabled): class StatsPage(object): + """StatsPage class.""" formatting = { 'CherryPy Applications': { @@ -474,6 +489,7 @@ class StatsPage(object): @cherrypy.expose def index(self): + """Route handler for index.""" # Transform the raw data into pretty output for HTML yield """ @@ -672,12 +688,14 @@ def get_list_collection(self, v, formatting): if json is not None: @cherrypy.expose def data(self): + """Return json data.""" s = extrapolate_statistics(logging.statistics) cherrypy.response.headers['Content-Type'] = 'application/json' return json.dumps(s, sort_keys=True, indent=4).encode('utf-8') @cherrypy.expose def pause(self, namespace): + """Pause.""" logging.statistics.get(namespace, {})['Enabled'] = False raise cherrypy.HTTPRedirect('./') pause.cp_config = {'tools.allow.on': True, @@ -685,6 +703,7 @@ def pause(self, namespace): @cherrypy.expose def resume(self, namespace): + """Resume.""" logging.statistics.get(namespace, {})['Enabled'] = True raise cherrypy.HTTPRedirect('./') resume.cp_config = {'tools.allow.on': True, diff --git a/cherrypy/lib/cptools.py b/cherrypy/lib/cptools.py index 61d4d36b0..17e981717 100644 --- a/cherrypy/lib/cptools.py +++ b/cherrypy/lib/cptools.py @@ -172,7 +172,6 @@ def proxy(base=None, local='X-Forwarded-Host', remote='X-Forwarded-For', default, 'remote' is set to 'X-Forwarded-For'. If you do not want to rewrite remote.ip, set the 'remote' arg to an empty string. """ - request = cherrypy.serving.request if scheme: @@ -288,6 +287,7 @@ class SessionAuth(object): debug = False def check_username_and_password(self, username, password): + """Check username and password stub.""" pass def anonymous(self): @@ -295,16 +295,20 @@ def anonymous(self): pass def on_login(self, username): + """Login event stub.""" pass def on_logout(self, username): + """Logout event stub.""" pass def on_check(self, username): + """Check event stub.""" pass def login_screen(self, from_page='..', username='', error_msg='', **kwargs): + """Login screen.""" return (str(""" Message: %(error_msg)s
@@ -385,6 +389,7 @@ def _debug_message(self, template, context={}): cherrypy.log(template % context, 'TOOLS.SESSAUTH') def run(self): + """Handle run.""" request = cherrypy.serving.request response = cherrypy.serving.response @@ -592,19 +597,21 @@ def accept(media=None, debug=False): class MonitoredHeaderMap(_httputil.HeaderMap): + """MonitoredHeaderMap class.""" def transform_key(self, key): + """Transform key.""" self.accessed_headers.add(key) return super(MonitoredHeaderMap, self).transform_key(key) def __init__(self): + """Initialize MonitoredHeaderMap.""" self.accessed_headers = set() super(MonitoredHeaderMap, self).__init__() def autovary(ignore=None, debug=False): - """Auto-populate the Vary response header based on request.header access. - """ + """Auto-populate Vary response header based on request.header access.""" request = cherrypy.serving.request req_h = request.headers diff --git a/cherrypy/lib/encoding.py b/cherrypy/lib/encoding.py index 068c88d25..ee4c2606d 100644 --- a/cherrypy/lib/encoding.py +++ b/cherrypy/lib/encoding.py @@ -1,3 +1,4 @@ +"""Encoding module.""" import struct import time import io @@ -41,32 +42,41 @@ def decode(encoding=None, default_encoding='utf-8'): class UTF8StreamEncoder: + """UTF8 Stream Encoder.""" + def __init__(self, iterator): + """Initialize UTF8StreamEncoder.""" self._iterator = iterator def __iter__(self): + """Iterate for UTF8StreamEncoder.""" return self def next(self): + """Next for UTF8StreamEncoder.""" return self.__next__() def __next__(self): + """Next for UTF8StreamEncoder.""" res = next(self._iterator) if isinstance(res, str): res = res.encode('utf-8') return res def close(self): + """Close for UTF8StreamEncoder.""" if is_closable_iterator(self._iterator): self._iterator.close() def __getattr__(self, attr): + """Get attr for UTF8StreamEncoder.""" if attr.startswith('__'): raise AttributeError(self, attr) return getattr(self._iterator, attr) class ResponseEncoder: + """Response Encoder.""" default_encoding = 'utf-8' failmsg = 'Response body could not be encoded with %r.' @@ -77,6 +87,7 @@ class ResponseEncoder: debug = False def __init__(self, **kwargs): + """Initialize ResponseEncoder.""" for k, v in kwargs.items(): setattr(self, k, v) @@ -124,6 +135,7 @@ def encode_string(self, encoding): return True def find_acceptable_charset(self): + """Find acceptable charset.""" request = cherrypy.serving.request response = cherrypy.serving.response @@ -219,6 +231,7 @@ def find_acceptable_charset(self): raise cherrypy.HTTPError(406, msg) def __call__(self, *args, **kwargs): + """Call for ResponseEncoder.""" response = cherrypy.serving.response self.body = self.oldhandler(*args, **kwargs) @@ -330,6 +343,7 @@ def compress(body, compress_level): def decompress(body): + """Decompress.""" import gzip zbuf = io.BytesIO() diff --git a/cherrypy/lib/gctools.py b/cherrypy/lib/gctools.py index 14d3ba7e7..5aaab7a6c 100644 --- a/cherrypy/lib/gctools.py +++ b/cherrypy/lib/gctools.py @@ -1,3 +1,4 @@ +"""GCtools.""" import gc import inspect import sys @@ -19,6 +20,7 @@ class ReferrerTree(object): peek_length = 40 def __init__(self, ignore=None, maxdepth=2, maxparents=10): + """Initialize ReferrerTree.""" self.ignore = ignore or [] self.ignore.append(inspect.currentframe().f_back) self.maxdepth = maxdepth @@ -99,18 +101,23 @@ def ascend(branch, depth=1): def get_instances(cls): + """Return GC instances.""" return [x for x in gc.get_objects() if isinstance(x, cls)] class RequestCounter(SimplePlugin): + """RequestCounter class.""" def start(self): + """Start request counter.""" self.count = 0 def before_request(self): + """Run before request.""" self.count += 1 def after_request(self): + """Run after request.""" self.count -= 1 @@ -119,6 +126,7 @@ def after_request(self): def get_context(obj): + """Get context.""" if isinstance(obj, _cprequest.Request): return 'path=%s;stage=%s' % (obj.path_info, obj.stage) elif isinstance(obj, _cprequest.Response): @@ -144,10 +152,12 @@ class GCRoot(object): @cherrypy.expose def index(self): + """Handle index route.""" return 'Hello, world!' @cherrypy.expose def stats(self): + """Handle stats route.""" output = ['Statistics:'] for trial in range(10): diff --git a/cherrypy/lib/httputil.py b/cherrypy/lib/httputil.py index 7f0a24252..64a60f256 100644 --- a/cherrypy/lib/httputil.py +++ b/cherrypy/lib/httputil.py @@ -78,7 +78,6 @@ def get_ranges(headervalue, content_length): If this function returns an empty list, you should return HTTP 416. """ - if not headervalue: return None @@ -130,25 +129,31 @@ class HeaderElement(object): """An element (with parameters) from an HTTP header's element list.""" def __init__(self, value, params=None): + """Initialize HeaderElement.""" self.value = value if params is None: params = {} self.params = params def __cmp__(self, other): + """Compare values.""" return builtins.cmp(self.value, other.value) def __lt__(self, other): + """Less-Than values.""" return self.value < other.value def __str__(self): + """Stringify HeaderElement.""" p = [';%s=%s' % (k, v) for k, v in self.params.items()] return str('%s%s' % (self.value, ''.join(p))) def __bytes__(self): + """Bytesify HeaderElement.""" return ntob(self.__str__()) def __unicode__(self): + """Unicodeify HeaderElement.""" return ntou(self.__str__()) @staticmethod @@ -180,6 +185,7 @@ class AcceptElement(HeaderElement): @classmethod def from_str(cls, elementstr): + """Initialize AcceptElement from string.""" qvalue = None # The first "q" parameter (if any) separates the initial # media-range parameter(s) (if any) from the accept-params. @@ -197,7 +203,7 @@ def from_str(cls, elementstr): @property def qvalue(self): - 'The qvalue, or priority, of this value.' + """The qvalue, or priority, of this value.""" val = self.params.get('q', '1') if isinstance(val, HeaderElement): val = val.value @@ -215,12 +221,14 @@ def qvalue(self): ) from val_err def __cmp__(self, other): + """Compare qvalues.""" diff = builtins.cmp(self.qvalue, other.qvalue) if diff == 0: diff = builtins.cmp(str(self), str(other)) return diff def __lt__(self, other): + """Less-Than qvalues.""" if self.qvalue == other.qvalue: return str(self) < str(other) else: @@ -231,7 +239,9 @@ def __lt__(self, other): def header_elements(fieldname, fieldvalue): - """Return a sorted HeaderElement list from a comma-separated header string. + """Return sorted HeaderElement list. + + Constucted from a comma-separated header string. """ if not fieldvalue: return [] @@ -283,7 +293,6 @@ def valid_status(status): ... ) + BaseHTTPRequestHandler.responses[http.client.ACCEPTED] True """ - if not status: status = 200 @@ -322,7 +331,6 @@ def _parse_qs(qs, keep_blank_values=0, strict_parsing=0, encoding='utf-8'): """Parse a query given as a string argument. Arguments: - qs: URL-encoded query string to be parsed keep_blank_values: flag indicating whether blank values in @@ -391,6 +399,7 @@ class CaseInsensitiveDict(jaraco.collections.KeyTransformingDict): @staticmethod def transform_key(key): + """Transform key to title.""" if key is None: # TODO(#1830): why? return 'None' @@ -444,7 +453,8 @@ def output(self): @classmethod def encode_header_items(cls, header_items): - """ + """Encode Header Items. + Prepare the sequence of name, value tuples into a form suitable for transmitting on the wire for HTTP. """ @@ -456,6 +466,7 @@ def encode_header_items(cls, header_items): @classmethod def encode_header_item(cls, item): + """Encode Header Item.""" if isinstance(item, str): item = cls.encode(item) @@ -501,6 +512,7 @@ class Host(object): name = 'unknown.tld' def __init__(self, ip, port, name=None): + """Initialize Host.""" self.ip = ip self.port = port if name is None: @@ -508,11 +520,13 @@ def __init__(self, ip, port, name=None): self.name = name def __repr__(self): + """Represent Host object.""" return 'httputil.Host(%r, %r, %r)' % (self.ip, self.port, self.name) class SanitizedHost(str): - r""" + r"""Sanitize host header. + Wraps a raw host header received from the network in a sanitized version that elides dangerous characters. @@ -526,9 +540,11 @@ class SanitizedHost(str): >>> isinstance(SanitizedHost('foobar'), SanitizedHost) False """ + dangerous = re.compile(r'[\n\r]') def __new__(cls, raw): + """Create new SanitizedHost.""" sanitized = cls._sanitize(raw) if sanitized == raw: return raw @@ -538,4 +554,5 @@ def __new__(cls, raw): @classmethod def _sanitize(cls, raw): + """Sanitize class data.""" return cls.dangerous.sub('', raw) diff --git a/cherrypy/lib/jsontools.py b/cherrypy/lib/jsontools.py index 9ca75a8f3..5e228e5e1 100644 --- a/cherrypy/lib/jsontools.py +++ b/cherrypy/lib/jsontools.py @@ -1,3 +1,4 @@ +"""Json tools.""" import cherrypy from cherrypy import _json as json from cherrypy._cpcompat import text_or_bytes, ntou @@ -15,7 +16,8 @@ def json_processor(entity): def json_in(content_type=[ntou('application/json'), ntou('text/javascript')], force=True, debug=False, processor=json_processor): - """Add a processor to parse JSON request entities: + """Add a processor to parse JSON request entities. + The default processor places the parsed data into request.json. Incoming request entities which match the given content_type(s) will @@ -56,6 +58,7 @@ def json_in(content_type=[ntou('application/json'), ntou('text/javascript')], def json_handler(*args, **kwargs): + """Handle JSON.""" value = cherrypy.serving.request._json_inner_handler(*args, **kwargs) return json.encode(value) diff --git a/cherrypy/lib/locking.py b/cherrypy/lib/locking.py index ea76450a1..a21ebd5a5 100644 --- a/cherrypy/lib/locking.py +++ b/cherrypy/lib/locking.py @@ -1,15 +1,20 @@ +"""Locking module.""" import datetime class NeverExpires(object): + """NeverExpires class.""" + def expired(self): + """Expired check.""" return False class Timer(object): """A simple timer that will indicate when an expiration time has passed.""" + def __init__(self, expiration): - 'Create a timer that expires at `expiration` (UTC datetime)' + """Create a timer that expires at `expiration` (UTC datetime).""" self.expiration = expiration @classmethod @@ -20,18 +25,21 @@ def after(cls, elapsed): ) def expired(self): + """Expired check.""" return datetime.datetime.now( datetime.timezone.utc, ) >= self.expiration class LockTimeout(Exception): - 'An exception when a lock could not be acquired before a timeout period' + """Exception when a lock could not be acquired before a timeout period.""" class LockChecker(object): """Keep track of the time and detect if a timeout has expired.""" + def __init__(self, session_id, timeout): + """Initialize LockChecker.""" self.session_id = session_id if timeout: self.timer = Timer.after(timeout) @@ -39,6 +47,7 @@ def __init__(self, session_id, timeout): self.timer = NeverExpires() def expired(self): + """Expired check.""" if self.timer.expired(): raise LockTimeout( 'Timeout acquiring lock for %(session_id)s' % vars(self)) diff --git a/cherrypy/lib/profiler.py b/cherrypy/lib/profiler.py index 9cda41d88..2b7964582 100644 --- a/cherrypy/lib/profiler.py +++ b/cherrypy/lib/profiler.py @@ -69,8 +69,10 @@ def new_func_strip_path(func_name): class Profiler(object): + """Profiler class.""" def __init__(self, path=None): + """Initialize Profiler.""" if not path: path = os.path.join(os.path.dirname(__file__), 'profile') self.path = path @@ -88,13 +90,17 @@ def run(self, func, *args, **params): return result def statfiles(self): - """:rtype: list of available profiles. + """Statistics files. + + :rtype: list of available profiles. """ return [f for f in os.listdir(self.path) if f.startswith('cp_') and f.endswith('.prof')] def stats(self, filename, sortby='cumulative'): - """:rtype stats(index): output of print_stats() for the given profile. + """Generate statistics. + + :rtype stats(index): output of print_stats() for the given profile. """ sio = io.StringIO() if sys.version_info >= (2, 5): @@ -120,6 +126,7 @@ def stats(self, filename, sortby='cumulative'): @cherrypy.expose def index(self): + """Index page html content.""" return """ CherryPy profile data @@ -131,6 +138,7 @@ def index(self): @cherrypy.expose def menu(self): + """Menu page html content.""" yield '

Profiling runs

' yield '

Click on one of the runs below to see profiling data.

' runs = self.statfiles() @@ -141,19 +149,23 @@ def menu(self): @cherrypy.expose def report(self, filename): + """Report statistics.""" cherrypy.response.headers['Content-Type'] = 'text/plain' return self.stats(filename) class ProfileAggregator(Profiler): + """ProfileAggregator class.""" def __init__(self, path=None): + """Initialize ProfileAggregator.""" Profiler.__init__(self, path) global _count self.count = _count = _count + 1 self.profiler = profile.Profile() def run(self, func, *args, **params): + """Run ProfileAggregator.""" path = os.path.join(self.path, 'cp_%04d.prof' % self.count) result = self.profiler.runcall(func, *args, **params) self.profiler.dump_stats(path) @@ -161,6 +173,7 @@ def run(self, func, *args, **params): class make_app: + """Make app class.""" def __init__(self, nextapp, path=None, aggregate=False): """Make a WSGI middleware app which wraps 'nextapp' with profiling. @@ -194,6 +207,7 @@ def __init__(self, nextapp, path=None, aggregate=False): self.profiler = Profiler(path) def __call__(self, environ, start_response): + """Call make app.""" def gather(): result = [] for line in self.nextapp(environ, start_response): @@ -203,6 +217,7 @@ def gather(): def serve(path=None, port=8080): + """Serve Profiler.""" if profile is None or pstats is None: msg = ('Your installation of Python does not have a profile module. ' "If you're on Debian, try " diff --git a/cherrypy/lib/reprconf.py b/cherrypy/lib/reprconf.py index 532610949..a050e2e5a 100644 --- a/cherrypy/lib/reprconf.py +++ b/cherrypy/lib/reprconf.py @@ -92,10 +92,12 @@ def __call__(self, config): handler(k, v) def __repr__(self): + """Represent NamespaceSet.""" return '%s.%s(%s)' % (self.__module__, self.__class__.__name__, dict.__repr__(self)) def __copy__(self): + """Handle copy.""" newobj = self.__class__() newobj.update(self) return newobj @@ -113,6 +115,7 @@ class Config(dict): namespaces = NamespaceSet() def __init__(self, file=None, **kwargs): + """Initialize config.""" self.reset() if file is not None: self.update(file) @@ -141,20 +144,24 @@ def _apply(self, config): self.namespaces(config) def __setitem__(self, k, v): + """Handle set item.""" dict.__setitem__(self, k, v) self.namespaces({k: v}) class Parser(configparser.ConfigParser): + """A config parser. - """Sub-class of ConfigParser that keeps the case of options and that + Sub-class of ConfigParser that keeps the case of options and that raises an exception if the file cannot be read. """ def optionxform(self, optionstr): + """Option X form.""" return optionstr def read(self, filenames): + """Handle read.""" if isinstance(filenames, text_or_bytes): filenames = [filenames] for filename in filenames: @@ -186,6 +193,7 @@ def as_dict(self, raw=False, vars=None): return result def dict_from_file(self, file): + """Generate a dict from a file.""" if hasattr(file, 'read'): self.read_file(file) else: @@ -235,8 +243,9 @@ def build_Index(self, o): return self.build(o.value) def _build_call35(self, o): - """ - Workaround for python 3.5 _ast.Call signature, docs found here + """Workaround for python 3.5. + + _ast.Call signature, docs found here https://greentreesnakes.readthedocs.org/en/latest/nodes.html """ import ast @@ -375,7 +384,6 @@ def modules(modulePath): def attributes(full_attribute_name): """Load a module and retrieve an attribute of that module.""" - # Parse out the path, module, and attribute last_dot = full_attribute_name.rfind('.') attr_name = full_attribute_name[last_dot + 1:] diff --git a/cherrypy/lib/sessions.py b/cherrypy/lib/sessions.py index 68badd93b..4a6070d84 100644 --- a/cherrypy/lib/sessions.py +++ b/cherrypy/lib/sessions.py @@ -177,6 +177,7 @@ def id(self, value): # --------------------- Session management methods --------------------- # def __init__(self, id=None, **kwargs): + """Initialize Session.""" self.id_observers = [] self._data = {} @@ -321,16 +322,19 @@ def delete(self): # -------------------- Application accessor methods -------------------- # def __getitem__(self, key): + """Get item from session.""" if not self.loaded: self.load() return self._data[key] def __setitem__(self, key, value): + """Set item in session.""" if not self.loaded: self.load() self._data[key] = value def __delitem__(self, key): + """Delete item from session.""" if not self.loaded: self.load() del self._data[key] @@ -349,13 +353,15 @@ def pop(self, key, default=missing): return self._data.pop(key, default) def __contains__(self, key): + """Test if session contains key.""" if not self.loaded: self.load() return key in self._data def get(self, key, default=None): - """D.get(k[,d]) -> D[k] if k in D, else d. + """Get session key. + D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None. """ if not self.loaded: @@ -363,8 +369,9 @@ def get(self, key, default=None): return self._data.get(key, default) def update(self, d): - """D.update(E) -> None. + """Update session key. + D.update(E) -> None. Update D from E: for k in E: D[k] = E[k]. """ if not self.loaded: @@ -372,14 +379,18 @@ def update(self, d): self._data.update(d) def setdefault(self, key, default=None): - """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D.""" + """Set default session value. + + D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D. + """ if not self.loaded: self.load() return self._data.setdefault(key, default) def clear(self): - """D.clear() -> None. + """Clear session. + D.clear() -> None. Remove all items from D. """ if not self.loaded: @@ -387,25 +398,35 @@ def clear(self): self._data.clear() def keys(self): - """D.keys() -> list of D's keys.""" + """Get list of session keys. + + D.keys() -> list of D's keys. + """ if not self.loaded: self.load() return self._data.keys() def items(self): - """D.items() -> list of D's (key, value) pairs, as 2-tuples.""" + """Get list of items as tuples. + + D.items() -> list of D's (key, value) pairs, as 2-tuples. + """ if not self.loaded: self.load() return self._data.items() def values(self): - """D.values() -> list of D's values.""" + """Get list of session values. + + D.values() -> list of D's values. + """ if not self.loaded: self.load() return self._data.values() class RamSession(Session): + """Handler for session in RAM.""" # Class-level objects. Don't rebind these! cache = {} @@ -413,7 +434,6 @@ class RamSession(Session): def clean_up(self): """Clean up expired sessions.""" - now = self.now() for _id, (data, expiration_time) in self.cache.copy().items(): if expiration_time <= now: @@ -466,8 +486,7 @@ def __len__(self): class FileSession(Session): - - """Implementation of the File backend for sessions + """Implementation of the File backend for sessions. storage_path The folder where session data will be saved. Each session @@ -485,6 +504,7 @@ class FileSession(Session): pickle_protocol = pickle.HIGHEST_PROTOCOL def __init__(self, id=None, **kwargs): + """Initialize FileSession.""" # The 'storage_path' arg is required for file-based sessions. kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) kwargs.setdefault('lock_timeout', None) @@ -614,6 +634,7 @@ def __len__(self): class MemcachedSession(Session): + """Use Memcache as a session backend.""" # The most popular memcached client for Python isn't thread-safe. # Wrap all .get and .set operations in a single lock. @@ -687,7 +708,6 @@ def __len__(self): def save(): """Save any changed session data.""" - if not hasattr(cherrypy.serving, 'session'): return request = cherrypy.serving.request @@ -783,7 +803,6 @@ def init(storage_type=None, path=None, path_header=None, name='session_id', and may be specific to the storage type. See the subclass of Session you're using for more information. """ - # Py27 compat storage_class = kwargs.pop('storage_class', RamSession) @@ -898,7 +917,8 @@ def set_response_cookie(path=None, path_header=None, name='session_id', def _add_MSIE_max_age_workaround(cookie, timeout): - """ + """Add MSIE max age workaround. + We'd like to use the "max-age" param as indicated in http://www.faqs.org/rfcs/rfc2109.html but IE doesn't save it to disk and the session is lost if people close diff --git a/cherrypy/process/plugins.py b/cherrypy/process/plugins.py index 20bf1c665..75b1062a9 100644 --- a/cherrypy/process/plugins.py +++ b/cherrypy/process/plugins.py @@ -38,6 +38,7 @@ class SimplePlugin(object): """ def __init__(self, bus): + """Initialize SimplePlugin.""" self.bus = bus def subscribe(self): @@ -93,6 +94,7 @@ class SignalHandler(object): del k, v def __init__(self, bus): + """Initialize SignalHandler.""" self.bus = bus # Set default handlers self.handlers = {'SIGTERM': self.bus.exit, @@ -117,8 +119,7 @@ def _jython_SIGINT_handler(self, signum=None, frame=None): self.bus.exit() def _is_daemonized(self): - """Return boolean indicating if the current process is - running as a daemon. + """Return boolean indicating if current process is running as a daemon. The criteria to determine the `daemon` condition is to verify if the current pid is not the same as the one that got used on @@ -223,6 +224,7 @@ class DropPrivileges(SimplePlugin): """ def __init__(self, bus, umask=None, uid=None, gid=None): + """Initialize DropPrivileges.""" SimplePlugin.__init__(self, bus) self.finalized = False self.uid = uid @@ -288,6 +290,7 @@ def umask(self, val): self._umask = val def start(self): + """Start DropPrivilages.""" # uid/gid def current_ids(): """Return the current (uid, gid) if available.""" @@ -353,6 +356,7 @@ class Daemonizer(SimplePlugin): def __init__(self, bus, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): + """Initialize Daemonizer.""" SimplePlugin.__init__(self, bus) self.stdin = stdin self.stdout = stdout @@ -360,6 +364,7 @@ def __init__(self, bus, stdin='/dev/null', stdout='/dev/null', self.finalized = False def start(self): + """Start Daemonizer.""" if self.finalized: self.bus.log('Already deamonized.') @@ -382,6 +387,7 @@ def start(self): def daemonize( stdin='/dev/null', stdout='/dev/null', stderr='/dev/null', logger=lambda msg: None): + """Daemonize Daemonizer.""" # See http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 # (or http://www.faqs.org/faqs/unix-faq/programmer/faq/ section 1.7) # and http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012 @@ -428,11 +434,13 @@ class PIDFile(SimplePlugin): """Maintain a PID file via a WSPBus.""" def __init__(self, bus, pidfile): + """Initialize PIDFile.""" SimplePlugin.__init__(self, bus) self.pidfile = pidfile self.finalized = False def start(self): + """Start PIDFile.""" pid = os.getpid() if self.finalized: self.bus.log('PID %r already written to %r.' % (pid, self.pidfile)) @@ -444,6 +452,7 @@ def start(self): start.priority = 70 def exit(self): + """Exit PIDFile.""" try: os.remove(self.pidfile) self.bus.log('PID file removed: %r.' % self.pidfile) @@ -462,11 +471,12 @@ class PerpetualTimer(threading.Timer): """ def __init__(self, *args, **kwargs): - "Override parent constructor to allow 'bus' to be provided." + """Override parent constructor to allow 'bus' to be provided.""" self.bus = kwargs.pop('bus', None) super(PerpetualTimer, self).__init__(*args, **kwargs) def run(self): + """Run PerpetualTimer.""" while True: self.finished.wait(self.interval) if self.finished.isSet(): @@ -494,6 +504,7 @@ class BackgroundTask(threading.Thread): """ def __init__(self, interval, function, args=[], kwargs={}, bus=None): + """Override parent constructor to assign provides properties.""" super(BackgroundTask, self).__init__() self.interval = interval self.function = function @@ -506,9 +517,11 @@ def __init__(self, interval, function, args=[], kwargs={}, bus=None): self.daemon = True def cancel(self): + """Cancel BackgroundTask.""" self.running = False def run(self): + """Run BackgroundTask.""" self.running = True while self.running: time.sleep(self.interval) @@ -539,6 +552,7 @@ class Monitor(SimplePlugin): """ def __init__(self, bus, callback, frequency=60, name=None): + """Initialize Monitor Plugin.""" SimplePlugin.__init__(self, bus) self.callback = callback self.frequency = frequency @@ -611,6 +625,7 @@ class Autoreloader(Monitor): """A regular expression by which to match filenames.""" def __init__(self, bus, frequency=1, match='.*'): + """Initialize Autoreloader Monitor Plugin.""" self.mtimes = {} self.files = set() self.match = match @@ -717,6 +732,7 @@ class ThreadManager(SimplePlugin): """A map of {thread ident: index number} pairs.""" def __init__(self, bus): + """Initialize ThreadManager Plugin.""" self.threads = {} SimplePlugin.__init__(self, bus) self.bus.listeners.setdefault('acquire_thread', set()) diff --git a/cherrypy/process/servers.py b/cherrypy/process/servers.py index fdd4bb681..249ab1ad6 100644 --- a/cherrypy/process/servers.py +++ b/cherrypy/process/servers.py @@ -1,4 +1,6 @@ r""" +Server Objects. + Starting in CherryPy 3.1, cherrypy.server is implemented as an :ref:`Engine Plugin`. It's an instance of :class:`cherrypy._cpserver.Server`, which is a subclass of @@ -127,6 +129,8 @@ def index(self): class Timeouts: + """Timeouts.""" + occupied = 5 free = 1 @@ -146,6 +150,7 @@ class ServerAdapter(object): """ def __init__(self, bus, httpserver=None, bind_addr=None): + """Initialize the HTTP server.""" self.bus = bus self.httpserver = httpserver self.bind_addr = bind_addr @@ -153,10 +158,12 @@ def __init__(self, bus, httpserver=None, bind_addr=None): self.running = False def subscribe(self): + """Subscribe the HTTP server.""" self.bus.subscribe('start', self.start) self.bus.subscribe('stop', self.stop) def unsubscribe(self): + """Unsubcribe the HTTP server.""" self.bus.unsubscribe('start', self.start) self.bus.unsubscribe('stop', self.stop) @@ -212,7 +219,9 @@ def _get_base(self): return '%s://%s' % (scheme, host) def _start_http_thread(self): - """HTTP servers MUST be running in new threads, so that the + """Start Http Thread. + + HTTP servers MUST be running in new threads, so that the main thread persists to receive KeyboardInterrupt's. If an exception is raised in the httpserver's thread then it's trapped here, and the bus (and therefore our httpserver) @@ -258,8 +267,9 @@ def wait(self): @property def bound_addr(self): - """ - The bind address, or if it's an ephemeral port and the + """The bind Address. + + or if it's an ephemeral port and the socket has been bound, return the actual port bound. """ host, port = self.bind_addr @@ -292,6 +302,7 @@ class FlupCGIServer(object): """Adapter for a flup.server.cgi.WSGIServer.""" def __init__(self, *args, **kwargs): + """Initialize Flup CGI Server.""" self.args = args self.kwargs = kwargs self.ready = False @@ -315,6 +326,7 @@ class FlupFCGIServer(object): """Adapter for a flup.server.fcgi.WSGIServer.""" def __init__(self, *args, **kwargs): + """Initialize Flup FCGI Server.""" if kwargs.get('bindAddress', None) is None: import socket if not hasattr(socket, 'fromfd'): @@ -360,6 +372,7 @@ class FlupSCGIServer(object): """Adapter for a flup.server.scgi.WSGIServer.""" def __init__(self, *args, **kwargs): + """Initialize Flup SCGI Server.""" self.args = args self.kwargs = kwargs self.ready = False @@ -395,7 +408,8 @@ def stop(self): @contextlib.contextmanager def _safe_wait(host, port): - """ + """Warn when bind interface is ambiguous. + On systems where a loopback interface is not available and the server is bound to all interfaces, it's difficult to determine whether the server is in fact occupying the port. In this case, diff --git a/cherrypy/process/win32.py b/cherrypy/process/win32.py index 305596bac..cb56c9989 100644 --- a/cherrypy/process/win32.py +++ b/cherrypy/process/win32.py @@ -17,10 +17,12 @@ class ConsoleCtrlHandler(plugins.SimplePlugin): """A WSPBus plugin for handling Win32 console events (like Ctrl-C).""" def __init__(self, bus): + """Initialize ConsoleCtrlHandler.""" self.is_set = False plugins.SimplePlugin.__init__(self, bus) def start(self): + """Handle start.""" if self.is_set: self.bus.log('Handler for console events already set.', level=20) return @@ -34,6 +36,7 @@ def start(self): self.is_set = True def stop(self): + """Handle stop.""" if not self.is_set: self.bus.log('Handler for console events already off.', level=20) return @@ -78,6 +81,7 @@ class Win32Bus(wspbus.Bus): """ def __init__(self): + """Initialize Win32Bus.""" self.events = {} wspbus.Bus.__init__(self) @@ -94,10 +98,12 @@ def _get_state_event(self, state): @property def state(self): + """Handle state.""" return self._state @state.setter def state(self, value): + """Handle set state.""" self._state = value event = self._get_state_event(value) win32event.PulseEvent(event) @@ -144,6 +150,7 @@ def key_for(self, obj): def signal_child(service, command): + """Handle signal child.""" if command == 'stop': win32serviceutil.StopService(service) elif command == 'restart': @@ -165,16 +172,19 @@ class PyWebService(win32serviceutil.ServiceFramework): _svc_description_ = 'Python Web Service' def SvcDoRun(self): + """Handle run.""" from cherrypy import process process.bus.start() process.bus.block() def SvcStop(self): + """Handle stop.""" from cherrypy import process self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) process.bus.exit() def SvcOther(self, control): + """Handle other.""" from cherrypy import process process.bus.publish(control_codes.key_for(control)) diff --git a/cherrypy/test/__init__.py b/cherrypy/test/__init__.py index 72c4c2618..a2ce3d845 100644 --- a/cherrypy/test/__init__.py +++ b/cherrypy/test/__init__.py @@ -5,17 +5,22 @@ def newexit(): + """Handle Exit.""" os._exit(1) def setup(): - # We want to monkey patch sys.exit so that we can get some - # information about where exit is being called. + """Handle Setup. + + We want to monkey patch sys.exit so that we can get some + information about where exit is being called. + """ newexit._old = sys.exit sys.exit = newexit def teardown(): + """Handle Teardown.""" try: sys.exit = sys.exit._old except AttributeError: diff --git a/cherrypy/test/_test_decorators.py b/cherrypy/test/_test_decorators.py index 02effbee4..3e15004df 100644 --- a/cherrypy/test/_test_decorators.py +++ b/cherrypy/test/_test_decorators.py @@ -5,29 +5,36 @@ class ExposeExamples(object): + """Test class ExposeExamples.""" @expose def no_call(self): + """No call function for ExposeExamples.""" return 'Mr E. R. Bradshaw' @expose() def call_empty(self): + """Empty call function for ExposeExamples.""" return 'Mrs. B.J. Smegma' @expose('call_alias') def nesbitt(self): + """Return Mr Nesbitt.""" return 'Mr Nesbitt' @expose(['alias1', 'alias2']) def andrews(self): + """Return Mr Ken Andrews.""" return 'Mr Ken Andrews' @expose(alias='alias3') def watson(self): + """Return Mr. and Mrs. Watson.""" return 'Mr. and Mrs. Watson' class ToolExamples(object): + """Test ToolExamples class.""" @expose # This is here to demonstrate that using the config decorator @@ -36,4 +43,5 @@ class ToolExamples(object): @cherrypy.config(**{'response.stream': True}) @tools.response_headers(headers=[('Content-Type', 'application/data')]) def blah(self): + """Blah.""" yield b'blah' diff --git a/cherrypy/test/_test_states_demo.py b/cherrypy/test/_test_states_demo.py index a49407baf..fb111e1f8 100644 --- a/cherrypy/test/_test_states_demo.py +++ b/cherrypy/test/_test_states_demo.py @@ -8,25 +8,31 @@ class Root: + """Root routes handler.""" @cherrypy.expose def index(self): + """Handle index.""" return 'Hello World' @cherrypy.expose def mtimes(self): + """Handle mtimes.""" return repr(cherrypy.engine.publish('Autoreloader', 'mtimes')) @cherrypy.expose def pid(self): + """Handle pid.""" return str(os.getpid()) @cherrypy.expose def start(self): + """Handle start.""" return repr(starttime) @cherrypy.expose def exit(self): + """Handle exit.""" # This handler might be called before the engine is STARTED if an # HTTP worker thread handles it before the HTTP server returns # control to engine.start. We avoid that race condition here @@ -37,6 +43,7 @@ def exit(self): @cherrypy.engine.subscribe('start', priority=100) def unsub_sig(): + """Handle unsub sig.""" cherrypy.log('unsubsig: %s' % cherrypy.config.get('unsubsig', False)) if cherrypy.config.get('unsubsig', False): cherrypy.log('Unsubscribing the default cherrypy signal handler') @@ -55,12 +62,14 @@ def old_term_handler(signum=None, frame=None): @cherrypy.engine.subscribe('start', priority=6) def starterror(): + """Handle start error.""" if cherrypy.config.get('starterror', False): 1 / 0 @cherrypy.engine.subscribe('start', priority=6) def log_test_case_name(): + """Log test case name.""" if cherrypy.config.get('test_case_name', False): cherrypy.log('STARTED FROM: %s' % cherrypy.config.get('test_case_name')) diff --git a/cherrypy/test/benchmark.py b/cherrypy/test/benchmark.py index 9c65e17b1..92cb2c266 100644 --- a/cherrypy/test/benchmark.py +++ b/cherrypy/test/benchmark.py @@ -47,9 +47,11 @@ class Root: + """Root class.""" @cherrypy.expose def index(self): + """Handle index for Root.""" return """ CherryPy Benchmark @@ -67,10 +69,12 @@ def index(self): @cherrypy.expose def hello(self): + """Handle hello for Root.""" return 'Hello, world\r\n' @cherrypy.expose def sizer(self, size): + """Handle sizer for Root.""" resp = size_cache.get(size, None) if resp is None: size_cache[size] = resp = 'X' * int(size) @@ -78,7 +82,7 @@ def sizer(self, size): def init(): - + """Initialize server.""" cherrypy.config.update({ 'log.error.file': '', 'environment': 'production', @@ -109,12 +113,15 @@ class NullRequest: """A null HTTP request class, returning 200 and an empty body.""" def __init__(self, local, remote, scheme='http'): + """Initialize NullRequest.""" pass def close(self): + """Close NullRequest.""" pass def run(self, method, path, query_string, protocol, headers, rfile): + """Run NullRequest.""" cherrypy.response.status = '200 OK' cherrypy.response.header_list = [('Content-Type', 'text/html'), ('Server', 'Null CherryPy'), @@ -126,6 +133,8 @@ def run(self, method, path, query_string, protocol, headers, rfile): class NullResponse: + """NullResponse class.""" + pass @@ -206,11 +215,13 @@ class ABSession: def __init__(self, path=SCRIPT_NAME + '/hello', requests=1000, concurrency=10): + """Initialize ABSession.""" self.path = path self.requests = requests self.concurrency = concurrency def args(self): + """Get ABSession arguments.""" port = cherrypy.server.socket_port assert self.concurrency > 0 assert self.requests > 0 @@ -221,6 +232,7 @@ def args(self): (self.requests, self.concurrency, port, self.path)) def run(self): + """Run ABSession.""" # Parse output of ab, setting attributes on self try: self.output = _cpmodpy.read_process(AB_PATH or 'ab', self.args()) @@ -244,6 +256,7 @@ def run(self): def thread_report(path=SCRIPT_NAME + '/hello', concurrency=safe_threads): + """Report on threads from ABSession.""" sess = ABSession(path) attrs, names, patterns = list(zip(*sess.parse_patterns)) avg = dict.fromkeys(attrs, 0.0) @@ -271,6 +284,7 @@ def thread_report(path=SCRIPT_NAME + '/hello', concurrency=safe_threads): def size_report(sizes=(10, 100, 1000, 10000, 100000, 100000000), concurrency=50): + """Report sizing from ABSession.""" sess = ABSession(concurrency=concurrency) attrs, names, patterns = list(zip(*sess.parse_patterns)) yield ('bytes',) + names @@ -281,6 +295,7 @@ def size_report(sizes=(10, 100, 1000, 10000, 100000, 100000000), def print_report(rows): + """Print rows to standard out.""" for row in rows: print('') for val in row: @@ -289,6 +304,7 @@ def print_report(rows): def run_standard_benchmarks(): + """Run Standard Benchmarks.""" print('') print('Client Thread Report (1000 requests, 14 byte response body, ' '%s server threads):' % cherrypy.server.thread_pool) @@ -308,8 +324,7 @@ def run_standard_benchmarks(): # modpython and other WSGI # def startup_modpython(req=None): - """Start the CherryPy app server in 'serverless' mode (for modpython/WSGI). - """ + """Start CherryPy app server in 'serverless' mode (for modpython/WSGI).""" if cherrypy.engine.state == cherrypy._cpengine.STOPPED: if req: if 'nullreq' in req.get_options(): diff --git a/cherrypy/test/checkerdemo.py b/cherrypy/test/checkerdemo.py index 02553ab00..fe65bc0fe 100644 --- a/cherrypy/test/checkerdemo.py +++ b/cherrypy/test/checkerdemo.py @@ -11,6 +11,8 @@ class Root: + """Root class.""" + pass diff --git a/cherrypy/test/helper.py b/cherrypy/test/helper.py index 5cf93d0ca..fc56382f8 100644 --- a/cherrypy/test/helper.py +++ b/cherrypy/test/helper.py @@ -31,6 +31,7 @@ class Supervisor(object): """Base class for modeling and controlling servers during testing.""" def __init__(self, **kwargs): + """Initialize Supervisor.""" for k, v in kwargs.items(): if k == 'port': setattr(self, k, int(v)) @@ -38,12 +39,12 @@ def __init__(self, **kwargs): def log_to_stderr(msg, level): + """Log to Standard Error.""" return sys.stderr.write(msg + os.linesep) class LocalSupervisor(Supervisor): - """Base class for modeling/controlling servers which run in the same - process. + """Base for modeling/controlling servers which run in the same process. When the server side runs in a different process, start/stop can dump all state between each test module easily. When the server side @@ -55,6 +56,7 @@ class LocalSupervisor(Supervisor): using_wsgi = False def __init__(self, **kwargs): + """Initialize LocalSupervisor.""" for k, v in kwargs.items(): setattr(self, k, v) @@ -85,6 +87,7 @@ def sync_apps(self): pass def stop(self): + """Stop the HTTP server.""" td = getattr(self, 'teardown', None) if td: td() @@ -104,6 +107,7 @@ class NativeServerSupervisor(LocalSupervisor): using_wsgi = False def __str__(self): + """Represent NativeServerSupervisor as a string.""" return 'Builtin HTTP Server on %s:%s' % (self.host, self.port) @@ -115,10 +119,11 @@ class LocalWSGISupervisor(LocalSupervisor): using_wsgi = True def __str__(self): + """Represent LocalWSGISupervisor as a string.""" return 'Builtin WSGI Server on %s:%s' % (self.host, self.port) def sync_apps(self): - """Hook a new WSGI app into the origin server.""" + """Create Hook into a new WSGI app into the origin server.""" cherrypy.server.httpserver.wsgi_app = self.get_app() def get_app(self, app=None): @@ -140,6 +145,7 @@ def get_app(self, app=None): def get_cpmodpy_supervisor(**options): + """Get CherryPy mod_python supervisor.""" from cherrypy.test import modpy sup = modpy.ModPythonSupervisor(**options) sup.template = modpy.conf_cpmodpy @@ -147,6 +153,7 @@ def get_cpmodpy_supervisor(**options): def get_modpygw_supervisor(**options): + """Get CherryPy mod_python gateway supervisor.""" from cherrypy.test import modpy sup = modpy.ModPythonSupervisor(**options) sup.template = modpy.conf_modpython_gateway @@ -155,26 +162,31 @@ def get_modpygw_supervisor(**options): def get_modwsgi_supervisor(**options): + """Get CherryPy mod_wsgi supervisor.""" from cherrypy.test import modwsgi return modwsgi.ModWSGISupervisor(**options) def get_modfcgid_supervisor(**options): + """Get CherryPy mod_fcgi supervisor.""" from cherrypy.test import modfcgid return modfcgid.ModFCGISupervisor(**options) def get_modfastcgi_supervisor(**options): + """Get CherryPy mod_fastcgi supervisor.""" from cherrypy.test import modfastcgi return modfastcgi.ModFCGISupervisor(**options) def get_wsgi_u_supervisor(**options): + """Get CherryPy wsgi supervisor.""" cherrypy.server.wsgi_version = ('u', 0) return LocalWSGISupervisor(**options) class CPWebCase(webtest.WebCase): + """CherryPy Web Test Case.""" script_name = '' scheme = 'http' @@ -236,8 +248,7 @@ def _setup_server(cls, supervisor, conf): @classmethod def setup_class(cls): - '' - # Creates a server + """Create a server.""" conf = { 'scheme': 'http', 'protocol': 'HTTP/1.1', @@ -274,13 +285,14 @@ def setup_class(cls): @classmethod def teardown_class(cls): - '' + """Teardown a server.""" if hasattr(cls, 'setup_server'): cls.supervisor.stop() do_gc_test = False def test_gc(self): + """Test /gc.""" if not self.do_gc_test: return @@ -291,9 +303,11 @@ def test_gc(self): 'Failures occur intermittently. See #1420' def prefix(self): + """Get prefix.""" return self.script_name.rstrip('/') def base(self): + """Return base.""" if ((self.scheme == 'http' and self.PORT == 80) or (self.scheme == 'https' and self.PORT == 443)): port = '' @@ -304,6 +318,7 @@ def base(self): self.script_name.rstrip('/')) def exit(self): + """Exit.""" sys.exit() def getPage(self, url, *args, **kwargs): @@ -313,6 +328,7 @@ def getPage(self, url, *args, **kwargs): return webtest.WebCase.getPage(self, url, *args, **kwargs) def skip(self, msg='skipped '): + """Skip.""" pytest.skip(msg) def assertErrorPage(self, status, message=None, pattern=''): @@ -321,7 +337,6 @@ def assertErrorPage(self, status, message=None, pattern=''): The function will optionally look for the regexp pattern, within the exception embedded in the error page. """ - # This will never contain a traceback page = cherrypy._cperror.get_error_page(status, message=message) @@ -394,6 +409,7 @@ def setup_client(): class CPProcess(object): + """CherryPy Process Spawning Helper.""" pid_file = os.path.join(thisdir, 'test.pid') config_file = os.path.join(thisdir, 'test.conf') @@ -412,6 +428,7 @@ class CPProcess(object): def __init__(self, wait=False, daemonize=False, ssl=False, socket_host=None, socket_port=None): + """Initialize CPProcess.""" self.wait = wait self.daemonize = daemonize self.ssl = ssl @@ -419,6 +436,7 @@ def __init__(self, wait=False, daemonize=False, ssl=False, self.port = socket_port or cherrypy.server.socket_port def write_conf(self, extra=''): + """Write CPProcess config.""" if self.ssl: serverpem = os.path.join(thisdir, 'test.pem') ssl = """ @@ -498,6 +516,7 @@ def start(self, imports=None): time.sleep(1) def get_pid(self): + """Get PID.""" if self.daemonize: with open(self.pid_file, 'rb') as f: return int(f.read()) diff --git a/cherrypy/test/logtest.py b/cherrypy/test/logtest.py index acdc95876..8ed095dcb 100644 --- a/cherrypy/test/logtest.py +++ b/cherrypy/test/logtest.py @@ -14,6 +14,7 @@ import msvcrt def getchar(): + """Handle windows case for get char.""" return msvcrt.getch() except ImportError: # Unix getchr @@ -21,6 +22,7 @@ def getchar(): import termios def getchar(): + """Handle unix case for get char.""" fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: @@ -92,6 +94,7 @@ def _handleLogError(self, msg, data, marker, pattern): sys.stdout.write(p + ' ') def exit(self): + """Exit.""" sys.exit() def emptyLog(self): diff --git a/cherrypy/test/modfastcgi.py b/cherrypy/test/modfastcgi.py index 16927d3cc..aae515a68 100644 --- a/cherrypy/test/modfastcgi.py +++ b/cherrypy/test/modfastcgi.py @@ -44,6 +44,7 @@ def read_process(cmd, args=''): + """Handle read process.""" pipein, pipeout = os.popen4('%s %s' % (cmd, args)) try: firstline = pipeout.readline() @@ -81,11 +82,13 @@ def read_process(cmd, args=''): def erase_script_name(environ, start_response): + """Erase script name.""" environ['SCRIPT_NAME'] = '' return cherrypy.tree(environ, start_response) class ModFCGISupervisor(helper.LocalWSGISupervisor): + """ModFCGISupervisor class.""" httpserver_class = 'cherrypy.process.servers.FlupFCGIServer' using_apache = True @@ -93,9 +96,11 @@ class ModFCGISupervisor(helper.LocalWSGISupervisor): template = conf_fastcgi def __str__(self): + """Return string representaion of ModFCGISupervisor.""" return 'FCGI Server on %s:%s' % (self.host, self.port) def start(self, modulename): + """Handle start.""" cherrypy.server.httpserver = servers.FlupFCGIServer( application=erase_script_name, bindAddress=('127.0.0.1', 4000)) cherrypy.server.httpserver.bind_addr = ('127.0.0.1', 4000) @@ -107,6 +112,7 @@ def start(self, modulename): self.sync_apps() def start_apache(self): + """Handle start Apache.""" fcgiconf = CONF_PATH if not os.path.isabs(fcgiconf): fcgiconf = os.path.join(curdir, fcgiconf) @@ -129,5 +135,6 @@ def stop(self): helper.LocalWSGISupervisor.stop(self) def sync_apps(self): + """Handle sync apps.""" cherrypy.server.httpserver.fcgiserver.application = self.get_app( erase_script_name) diff --git a/cherrypy/test/modfcgid.py b/cherrypy/test/modfcgid.py index 6dd48a943..5f6867222 100644 --- a/cherrypy/test/modfcgid.py +++ b/cherrypy/test/modfcgid.py @@ -45,6 +45,7 @@ def read_process(cmd, args=''): + """Handle read process.""" pipein, pipeout = os.popen4('%s %s' % (cmd, args)) try: firstline = pipeout.readline() @@ -78,15 +79,18 @@ def read_process(cmd, args=''): class ModFCGISupervisor(helper.LocalSupervisor): + """ModFCGISupervisor class.""" using_apache = True using_wsgi = True template = conf_fcgid def __str__(self): + """Return string representation of ModFCGISupervisor.""" return 'FCGI Server on %s:%s' % (self.host, self.port) def start(self, modulename): + """Handle start.""" cherrypy.server.httpserver = servers.FlupFCGIServer( application=cherrypy.tree, bindAddress=('127.0.0.1', 4000)) cherrypy.server.httpserver.bind_addr = ('127.0.0.1', 4000) @@ -96,6 +100,7 @@ def start(self, modulename): helper.LocalServer.start(self, modulename) def start_apache(self): + """Handle start Apache.""" fcgiconf = CONF_PATH if not os.path.isabs(fcgiconf): fcgiconf = os.path.join(curdir, fcgiconf) @@ -118,4 +123,5 @@ def stop(self): helper.LocalServer.stop(self) def sync_apps(self): + """Handle sync apps.""" cherrypy.server.httpserver.fcgiserver.application = self.get_app() diff --git a/cherrypy/test/modpy.py b/cherrypy/test/modpy.py index f4f685232..50cbc6d00 100644 --- a/cherrypy/test/modpy.py +++ b/cherrypy/test/modpy.py @@ -44,6 +44,7 @@ def read_process(cmd, args=''): + """Handle read process.""" pipein, pipeout = os.popen4('%s %s' % (cmd, args)) try: firstline = pipeout.readline() @@ -94,15 +95,18 @@ def read_process(cmd, args=''): class ModPythonSupervisor(helper.Supervisor): + """ModPythonSupervisor class.""" using_apache = True using_wsgi = False template = None def __str__(self): + """Retusn string representation of ModPythonSupervisor.""" return 'ModPython Server on %s:%s' % (self.host, self.port) def start(self, modulename): + """Handle start.""" mpconf = CONF_PATH if not os.path.isabs(mpconf): mpconf = os.path.join(curdir, mpconf) @@ -125,6 +129,7 @@ def stop(self): def wsgisetup(req): + """Handle WGSI setup.""" global loaded if not loaded: loaded = True @@ -147,6 +152,7 @@ def wsgisetup(req): def cpmodpysetup(req): + """Handle CP Mod Python setup.""" global loaded if not loaded: loaded = True diff --git a/cherrypy/test/modwsgi.py b/cherrypy/test/modwsgi.py index 911d48191..2a8fb1745 100644 --- a/cherrypy/test/modwsgi.py +++ b/cherrypy/test/modwsgi.py @@ -48,6 +48,7 @@ def read_process(cmd, args=''): + """Read Process of supplied command.""" pipein, pipeout = os.popen4('%s %s' % (cmd, args)) try: firstline = pipeout.readline() @@ -101,9 +102,11 @@ class ModWSGISupervisor(helper.Supervisor): template = conf_modwsgi def __str__(self): + """Represent ModWSGISupervisor as a string.""" return 'ModWSGI Server on %s:%s' % (self.host, self.port) def start(self, modulename): + """Start Mod WSGI Supervisor.""" mpconf = CONF_PATH if not os.path.isabs(mpconf): mpconf = os.path.join(curdir, mpconf) @@ -133,6 +136,7 @@ def stop(self): def application(environ, start_response): + """Application to load test mod.""" global loaded if not loaded: loaded = True diff --git a/cherrypy/test/sessiondemo.py b/cherrypy/test/sessiondemo.py index 0eb13cf72..14901e041 100755 --- a/cherrypy/test/sessiondemo.py +++ b/cherrypy/test/sessiondemo.py @@ -98,8 +98,10 @@ class Root(object): + """Root request handler.""" def page(self): + """Handle page route.""" changemsg = [] if cherrypy.session.id != cherrypy.session.originalid: if cherrypy.session.originalid is None: @@ -137,17 +139,20 @@ def page(self): @cherrypy.expose def index(self): + """Handle index route.""" # Must modify data or the session will not be saved. cherrypy.session['color'] = 'green' return self.page() @cherrypy.expose def expire(self): + """Handle expire route.""" sessions.expire() return self.page() @cherrypy.expose def regen(self): + """Handle regen route.""" cherrypy.session.regenerate() # Must modify data or the session will not be saved. cherrypy.session['color'] = 'yellow' diff --git a/cherrypy/test/webtest.py b/cherrypy/test/webtest.py index 9fb6ce62b..cf4d10bdd 100644 --- a/cherrypy/test/webtest.py +++ b/cherrypy/test/webtest.py @@ -1,4 +1,4 @@ -# for compatibility, expose cheroot webtest here +"""For compatibility, expose cheroot webtest here.""" import warnings from cheroot.test.webtest import ( # noqa diff --git a/cherrypy/tutorial/__init__.py b/cherrypy/tutorial/__init__.py index 08c142c5f..5b81780e9 100644 --- a/cherrypy/tutorial/__init__.py +++ b/cherrypy/tutorial/__init__.py @@ -1,3 +1,3 @@ - +"""Initialization file for tutorial module.""" # This is used in test_config to test unrepr of "from A import B" thing2 = object() diff --git a/cherrypy/tutorial/tut01_helloworld.py b/cherrypy/tutorial/tut01_helloworld.py index e575a9e29..4e33968db 100644 --- a/cherrypy/tutorial/tut01_helloworld.py +++ b/cherrypy/tutorial/tut01_helloworld.py @@ -1,5 +1,5 @@ """ -Tutorial - Hello World +Tutorial - Hello World. The most basic (working) CherryPy application possible. """ @@ -17,6 +17,7 @@ class HelloWorld: # publish methods that don't have the exposed attribute set to True. @cherrypy.expose def index(self): + """Handle index.""" # CherryPy will call this method for the root URI ("/") and send # its return value to the client. Because this is tutorial # lesson number 01, we'll just send something really simple. diff --git a/cherrypy/tutorial/tut02_expose_methods.py b/cherrypy/tutorial/tut02_expose_methods.py index 8afbf7d8b..14a7107a8 100644 --- a/cherrypy/tutorial/tut02_expose_methods.py +++ b/cherrypy/tutorial/tut02_expose_methods.py @@ -1,5 +1,5 @@ """ -Tutorial - Multiple methods +Tutorial - Multiple methods. This tutorial shows you how to link to other methods of your request handler. @@ -11,15 +11,24 @@ class HelloWorld: + """HelloWorld class for tutorial.""" @cherrypy.expose def index(self): - # Let's link to another method here. + """ + Index HelloWorld. + + Let's link to another method here. + """ return 'We have an important message for you!' @cherrypy.expose def show_msg(self): - # Here's the important message! + """ + Show_msg HelloWorld. + + Here's the important message! + """ return 'Hello world!' diff --git a/cherrypy/tutorial/tut03_get_and_post.py b/cherrypy/tutorial/tut03_get_and_post.py index 0b3d46131..4c38312b5 100644 --- a/cherrypy/tutorial/tut03_get_and_post.py +++ b/cherrypy/tutorial/tut03_get_and_post.py @@ -1,5 +1,5 @@ """ -Tutorial - Passing variables +Tutorial - Passing variables. This tutorial shows you how to pass GET/POST variables to methods. """ @@ -10,10 +10,15 @@ class WelcomePage: + """WelcomePage Class for Tutorial 03.""" @cherrypy.expose def index(self): - # Ask for the user's name. + """ + Index WelcomePage. + + Ask for the user's name. + """ return ''' What is your name? @@ -23,14 +28,17 @@ def index(self): @cherrypy.expose def greetUser(self, name=None): - # CherryPy passes all GET and POST variables as method parameters. - # It doesn't make a difference where the variables come from, how - # large their contents are, and so on. - # - # You can define default parameter values as usual. In this - # example, the "name" parameter defaults to None so we can check - # if a name was actually specified. + """ + Greet User WelcomePage. + + CherryPy passes all GET and POST variables as method parameters. + It doesn't make a difference where the variables come from, how + large their contents are, and so on. + You can define default parameter values as usual. In this + example, the "name" parameter defaults to None so we can check + if a name was actually specified. + """ if name: # Greet the user! return "Hey %s, what's up?" % name diff --git a/cherrypy/tutorial/tut04_complex_site.py b/cherrypy/tutorial/tut04_complex_site.py index fe04054f1..51cf2ce79 100644 --- a/cherrypy/tutorial/tut04_complex_site.py +++ b/cherrypy/tutorial/tut04_complex_site.py @@ -1,5 +1,5 @@ """ -Tutorial - Multiple objects +Tutorial - Multiple objects. This tutorial shows you how to create a site structure through multiple possibly nested request handler objects. @@ -11,9 +11,11 @@ class HomePage: + """HomePage class.""" @cherrypy.expose def index(self): + """Handle index for HomePage.""" return '''

Hi, this is the home page! Check out the other fun stuff on this site:

@@ -25,9 +27,11 @@ def index(self): class JokePage: + """JokePage class.""" @cherrypy.expose def index(self): + """Handle index for JokePage.""" return '''

"In Python, how do you create a string of random characters?" -- "Read a Perl file!"

@@ -35,8 +39,10 @@ def index(self): class LinksPage: + """LinksPage class.""" def __init__(self): + """Initialize LinksPage.""" # Request handler objects can create their own nested request # handler objects. Simply create them inside their __init__ # methods! @@ -44,6 +50,7 @@ def __init__(self): @cherrypy.expose def index(self): + """Handle index for LinksPage.""" # Note the way we link to the extra links page (and back). # As you can see, this object doesn't really care about its # absolute position in the site tree, since we use relative @@ -68,9 +75,11 @@ def index(self): class ExtraLinksPage: + """ExtraLinksPage class.""" @cherrypy.expose def index(self): + """Handle index for ExtraLinksPage.""" # Note the relative link back to the Links page! return '''

Here are some extra useful links:

diff --git a/cherrypy/tutorial/tut05_derived_objects.py b/cherrypy/tutorial/tut05_derived_objects.py index f626e03f0..aafaa6d7d 100644 --- a/cherrypy/tutorial/tut05_derived_objects.py +++ b/cherrypy/tutorial/tut05_derived_objects.py @@ -1,5 +1,5 @@ """ -Tutorial - Object inheritance +Tutorial - Object inheritance. You are free to derive your request handler classes from any base class you wish. In most real-world applications, you will probably @@ -13,10 +13,13 @@ class you wish. In most real-world applications, you will probably class Page: + """Page base route handler.""" + # Store the page title in a class attribute title = 'Untitled Page' def header(self): + """Header html content.""" return ''' @@ -27,6 +30,7 @@ def header(self): ''' % (self.title, self.title) def footer(self): + """Footer html content.""" return ''' @@ -40,15 +44,19 @@ def footer(self): class HomePage(Page): + """HomePage route handler.""" + # Different title for this page title = 'Tutorial 5' def __init__(self): + """Initialize HomePage.""" # create a subpage self.another = AnotherPage() @cherrypy.expose def index(self): + """Handle index.""" # Note that we call the header and footer methods inherited # from the Page class! return self.header() + ''' @@ -60,10 +68,13 @@ def index(self): class AnotherPage(Page): + """AnotherPage route handler.""" + title = 'Another Page' @cherrypy.expose def index(self): + """Handle index.""" return self.header() + '''

And this is the amazing second page! diff --git a/cherrypy/tutorial/tut06_default_method.py b/cherrypy/tutorial/tut06_default_method.py index 0ce4cabe8..bd12e4356 100644 --- a/cherrypy/tutorial/tut06_default_method.py +++ b/cherrypy/tutorial/tut06_default_method.py @@ -1,5 +1,5 @@ """ -Tutorial - The default method +Tutorial - The default method. Request handler objects can implement a method called "default" that is called when no other suitable method/object could be found. @@ -22,12 +22,16 @@ class UsersPage: + """The UsersPage Class for Tutorial 06.""" @cherrypy.expose def index(self): - # Since this is just a stupid little example, we'll simply - # display a list of links to random, made-up users. In a real - # application, this could be generated from a database result set. + """Index for UsersPage. + + Since this is just a stupid little example, we'll simply + display a list of links to random, made-up users. In a real + application, this could be generated from a database result set. + """ return ''' Remi Delon
Hendrik Mans
@@ -36,10 +40,13 @@ def index(self): @cherrypy.expose def default(self, user): - # Here we react depending on the virtualPath -- the part of the - # path that could not be mapped to an object method. In a real - # application, we would probably do some database lookups here - # instead of the silly if/elif/else construct. + """Handle Default for UsersPage. + + Here we react depending on the virtualPath -- the part of the + path that could not be mapped to an object method. In a real + application, we would probably do some database lookups here + instead of the silly if/elif/else construct. + """ if user == 'remi': out = 'Remi Delon, CherryPy lead developer' elif user == 'hendrik': diff --git a/cherrypy/tutorial/tut07_sessions.py b/cherrypy/tutorial/tut07_sessions.py index 204322b58..6dfd0b493 100644 --- a/cherrypy/tutorial/tut07_sessions.py +++ b/cherrypy/tutorial/tut07_sessions.py @@ -1,5 +1,5 @@ """ -Tutorial - Sessions +Tutorial - Sessions. Storing session data in CherryPy applications is very easy: cherrypy provides a dictionary called "session" that represents the session @@ -14,11 +14,13 @@ class HitCounter: + """HitCounter Class.""" _cp_config = {'tools.sessions.on': True} @cherrypy.expose def index(self): + """Index route hander.""" # Increase the silly hit counter count = cherrypy.session.get('count', 0) + 1 diff --git a/cherrypy/tutorial/tut08_generators_and_yield.py b/cherrypy/tutorial/tut08_generators_and_yield.py index 18f42f934..81a6dae14 100644 --- a/cherrypy/tutorial/tut08_generators_and_yield.py +++ b/cherrypy/tutorial/tut08_generators_and_yield.py @@ -1,5 +1,5 @@ """ -Bonus Tutorial: Using generators to return result bodies +Bonus Tutorial: Using generators to return result bodies. Instead of returning a complete result string, you can use the yield statement to return one result part after another. This may be convenient @@ -13,15 +13,19 @@ class GeneratorDemo: + """GeneratorDemo class.""" def header(self): + """Header html content.""" return '

Generators rule!

' def footer(self): + """Footer html content.""" return '' @cherrypy.expose def index(self): + """Return index html content.""" # Let's make up a list of users for presentation purposes users = ['Remi', 'Carlos', 'Hendrik', 'Lorenzo Lamas'] diff --git a/cherrypy/tutorial/tut09_files.py b/cherrypy/tutorial/tut09_files.py index 48585cbe1..740f9f3ae 100644 --- a/cherrypy/tutorial/tut09_files.py +++ b/cherrypy/tutorial/tut09_files.py @@ -1,6 +1,5 @@ """ - -Tutorial: File upload and download +Tutorial: File upload and download. Uploads ------- @@ -51,9 +50,11 @@ class FileDemo(object): + """FileDemo request handler.""" @cherrypy.expose def index(self): + """Handle index route.""" return """

Upload a file

@@ -68,6 +69,7 @@ def index(self): @cherrypy.expose def upload(self, myFile): + """Handle upload route.""" out = """ myFile length: %s
@@ -91,6 +93,7 @@ def upload(self, myFile): @cherrypy.expose def download(self): + """Handle download route.""" path = os.path.join(absDir, 'pdf_file.pdf') return static.serve_file(path, 'application/x-download', 'attachment', os.path.basename(path)) diff --git a/cherrypy/tutorial/tut10_http_errors.py b/cherrypy/tutorial/tut10_http_errors.py index 18f02fd0e..982b24307 100644 --- a/cherrypy/tutorial/tut10_http_errors.py +++ b/cherrypy/tutorial/tut10_http_errors.py @@ -1,11 +1,9 @@ """ - -Tutorial: HTTP errors +Tutorial: HTTP errors. HTTPError is used to return an error response to the client. CherryPy has lots of options regarding how such errors are logged, displayed, and formatted. - """ import os @@ -18,6 +16,7 @@ class HTTPErrorDemo(object): + """HTTPErrorDemo request handler.""" # Set a custom response for 403 errors. _cp_config = {'error_page.403': @@ -25,6 +24,7 @@ class HTTPErrorDemo(object): @cherrypy.expose def index(self): + """Handle index route.""" # display some links that will result in errors tracebacks = cherrypy.request.show_tracebacks if tracebacks: @@ -55,6 +55,7 @@ def index(self): @cherrypy.expose def toggleTracebacks(self): + """Handle toggleTracebacks route.""" # simple function to toggle tracebacks on and off tracebacks = cherrypy.request.show_tracebacks cherrypy.config.update({'request.show_tracebacks': not tracebacks}) @@ -64,11 +65,13 @@ def toggleTracebacks(self): @cherrypy.expose def error(self, code): + """Handle error route.""" # raise an error based on the get query raise cherrypy.HTTPError(status=code) @cherrypy.expose def messageArg(self): + """Handle messageArg route.""" message = ("If you construct an HTTPError with a 'message' " 'argument, it wil be placed on the error page ' '(underneath the status line by default).') From ba131378d1ae30b38caca7e6bcfdf564413c5390 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 21 May 2024 23:00:08 +0200 Subject: [PATCH 02/69] =?UTF-8?q?=F0=9F=A7=AA=F0=9F=94=A5=20Drop=20separat?= =?UTF-8?q?e=20pep257=20linting=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 5 ++--- .pre-commit-config-pep257.yaml | 9 --------- .pre-commit-config.yaml | 17 ----------------- tox.ini | 5 ----- 4 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 .pre-commit-config-pep257.yaml diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 54304e921..b73a13376 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -552,7 +552,6 @@ jobs: # - linkcheck-docs # - metadata-validation - pre-commit - - pre-commit-pep257 - setup-check # - spellcheck-docs fail-fast: false @@ -574,7 +573,7 @@ jobs: - name: Grab the source from Git if: >- contains( - fromJSON('["pre-commit", "pre-commit-pep257", "spellcheck-docs"]'), + fromJSON('["pre-commit", "spellcheck-docs"]'), matrix.toxenv ) uses: actions/checkout@v3 @@ -583,7 +582,7 @@ jobs: - name: Retrieve the project source from an sdist inside the GHA artifact if: >- !contains( - fromJSON('["pre-commit", "pre-commit-pep257", "spellcheck-docs"]'), + fromJSON('["pre-commit", "spellcheck-docs"]'), matrix.toxenv ) uses: re-actors/checkout-python-sdist@release/v1 diff --git a/.pre-commit-config-pep257.yaml b/.pre-commit-config-pep257.yaml deleted file mode 100644 index 84eab227f..000000000 --- a/.pre-commit-config-pep257.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- - -repos: -- repo: https://github.com/PyCQA/pydocstyle.git - rev: 6.2.2 - hooks: - - id: pydocstyle - -... diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dc20b02e9..26ab04826 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,23 +39,6 @@ repos: rev: 6.3.0 hooks: - id: pydocstyle - exclude: | - (?x) - tests/dist| - cherrypy/( - _cp( - compat|modpy|logging|error|wsgi|dispatch|tools|reqbody|request - )| - ( - lib/( - auth|auth_basic|auth_digest|caching|covercp| - cpstats|cptools|encoding|gctools|httpauth|httputil| - jsontools|lockfile|locking|profiler|reprconf|sessions - )| - process/(plugins|servers|win32) - ).py| - test|tutorial - ) - repo: https://github.com/Lucas-C/pre-commit-hooks.git rev: v1.5.4 diff --git a/tox.ini b/tox.ini index 487448a5c..f1765a2c6 100644 --- a/tox.ini +++ b/tox.ini @@ -50,11 +50,6 @@ commands = 'cmd = "{envpython} -m pre_commit install"; scr_width = len(cmd) + 10; sep = "=" * scr_width; cmd_str = " $ " + cmd; '\ 'print("\n" + sep + "\nTo install pre-commit hooks into the Git repo, run:\n\n" + cmd_str + "\n\n" + sep + "\n")' -[testenv:pre-commit-pep257] -deps = pre-commit -commands = - pre-commit run --config .pre-commit-config-pep257.yaml --all-files {posargs} - [testenv:dist-check] # ensure that package artifacts are installed as expected usedevelop = False From f076a71551d0103d38156dce0a1be662a4d3f4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 17:34:34 +0200 Subject: [PATCH 03/69] Rewrite compat dopcstrings --- cherrypy/_cpcompat.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cherrypy/_cpcompat.py b/cherrypy/_cpcompat.py index c955478b9..6e8053fc4 100644 --- a/cherrypy/_cpcompat.py +++ b/cherrypy/_cpcompat.py @@ -22,14 +22,20 @@ def ntob(n, encoding='ISO-8859-1'): - """Return given native string as a byte str in the given encoding.""" + """Convert a native :class:`str` to a :class:`bytes` instance. + + The encoding can be changed to non-ASCII optionally. + """ assert_native(n) # In Python 3, the native string type is unicode return n.encode(encoding) def ntou(n, encoding='ISO-8859-1'): - """Return given native string as a unicode str in the given encoding.""" + """Convert a native :class:`str` to a :class:`str` instance. + + This doesn't actually do anything. + """ assert_native(n) # In Python 3, the native string type is unicode return n @@ -44,7 +50,7 @@ def tonative(n, encoding='ISO-8859-1'): def assert_native(n): - """Assert if native string.""" + """Ensure that input is a native :class:`str`.""" if not isinstance(n, str): raise TypeError('n must be a native str (got %s)' % type(n).__name__) From e30d3ee30284a1324b5c6c0e2a978c9d281761e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 21:30:54 +0200 Subject: [PATCH 04/69] Make dispatch module docstrings more accurate --- cherrypy/_cpdispatch.py | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/cherrypy/_cpdispatch.py b/cherrypy/_cpdispatch.py index 9373cccfd..3fb19fe9b 100644 --- a/cherrypy/_cpdispatch.py +++ b/cherrypy/_cpdispatch.py @@ -25,7 +25,7 @@ class PageHandler(object): """Callable which sets response.body.""" def __init__(self, callable, *args, **kwargs): - """Initialize PageHandler.""" + """Initialize the page handler.""" self.callable = callable self.args = args self.kwargs = kwargs @@ -37,7 +37,7 @@ def args(self): @args.setter def args(self, args): - """Setter for ordered args.""" + """Set the request arguments in order.""" cherrypy.serving.request.args = args return cherrypy.serving.request.args @@ -48,12 +48,12 @@ def kwargs(self): @kwargs.setter def kwargs(self, kwargs): - """Setter for named kwargs.""" + """Set the named request keyword arguments as :class:`dict`.""" cherrypy.serving.request.kwargs = kwargs return cherrypy.serving.request.kwargs def __call__(self): - """Call handler for PageHandler.""" + """Invoke an HTTP handler callable for :class:`PageHandler`.""" try: return self.callable(*self.args, **self.kwargs) except TypeError: @@ -207,18 +207,18 @@ def test_callable_spec(callable, callable_args, callable_kwargs): import inspect except ImportError: def test_callable_spec(callable, args, kwargs): # noqa: F811 - """Test callable spec.""" + """Do nothing as a no-op.""" return None else: def getargspec(callable): - """Get arg spec.""" + """Get argument specification using :mod:`inspect`.""" return inspect.getfullargspec(callable)[:4] class LateParamPageHandler(PageHandler): - """LateParamPageHandler PageHandler class. + """Page handler callable with delayed request parameters binding. - When passing cherrypy.request.params to the page handler, we do not + When passing ``cherrypy.request.params`` to the page handler, we do not want to capture that dict too early; we want to give tools like the decoding tool a chance to modify the params dict in-between the lookup of the handler and the actual calling of the handler. This subclass @@ -228,7 +228,10 @@ class LateParamPageHandler(PageHandler): @property def kwargs(self): - """Page handler kwargs with cherrypy.request.params copied in.""" + """Page handler keyword arguments. + + The returned value contains data merged in + from ``cherrypy.request.params``.""" kwargs = cherrypy.serving.request.params.copy() if self._kwargs: kwargs.update(self._kwargs) @@ -236,7 +239,7 @@ def kwargs(self): @kwargs.setter def kwargs(self, kwargs): - """Setter for kwargs.""" + """Set the named request keyword arguments as :class:`dict`.""" cherrypy.serving.request.kwargs = kwargs self._kwargs = kwargs @@ -246,7 +249,7 @@ def kwargs(self, kwargs): string.punctuation, '_' * len(string.punctuation)) def validate_translator(t): - """Validate translator.""" + """Ensure the translator is of the correct length and size.""" if not isinstance(t, str) or len(t) != 256: raise ValueError( 'The translate argument must be a str of len 256.') @@ -255,7 +258,7 @@ def validate_translator(t): string.punctuation, '_' * len(string.punctuation)) def validate_translator(t): - """Validate translator.""" + """Ensure the translator is of the correct length and size.""" if not isinstance(t, dict): raise ValueError('The translate argument must be a dict.') @@ -283,7 +286,7 @@ class Dispatcher(object): def __init__(self, dispatch_method_name=None, translate=punctuation_to_underscores): - """Initialize Dispatcher.""" + """Initialize the HTTP request dispatcher.""" validate_translator(translate) self.translate = translate if dispatch_method_name: @@ -400,7 +403,9 @@ def find_handler(self, path): object_trail.append([name, node, nodeconf, segleft]) def set_conf(): - """Collapse all object_trail conf into cherrypy.request.config.""" + """Collapse all ``object_trail`` conf into config. + + The config being ``cherrypy.request.config``.""" base = cherrypy.config.copy() # Note that we merge the config from each node # even if that node was None. @@ -515,12 +520,12 @@ def __init__(self, full_result=False, **mapper_options): self.mapper.controller_scan = self.controllers.keys def connect(self, name, route, controller, **kwargs): - """Connect.""" + """Mount an HTTP handler into the router.""" self.controllers[name] = controller self.mapper.connect(name, route, controller=name, **kwargs) def redirect(self, url): - """Redirect.""" + """Perform an HTTP redirect to the given URL.""" raise cherrypy.HTTPRedirect(url) def __call__(self, path_info): @@ -614,7 +619,7 @@ def merge(nodeconf): def XMLRPCDispatcher(next_dispatcher=Dispatcher()): - """Xml RPC Dispatcher class.""" + """An HTTP dispatcher variant implementing XML-RPC.""" from cherrypy.lib import xmlrpcutil def xmlrpc_dispatch(path_info): From 0295e06497c6efe48e850abf417b51a4e82908a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 21:31:35 +0200 Subject: [PATCH 05/69] Drop a redundand `pass` node from the error module --- cherrypy/_cperror.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cherrypy/_cperror.py b/cherrypy/_cperror.py index 009123136..816b3a167 100644 --- a/cherrypy/_cperror.py +++ b/cherrypy/_cperror.py @@ -138,8 +138,6 @@ class Root: class CherryPyException(Exception): """A base class for CherryPy exceptions.""" - pass - class InternalRedirect(CherryPyException): """Exception raised to switch to the handler for a different URL. From 208880d001fea2f0f0acc519863f1b6388028fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 21:45:20 +0200 Subject: [PATCH 06/69] Format the closing jdocstring quotes in dispatch mod --- cherrypy/_cpdispatch.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cherrypy/_cpdispatch.py b/cherrypy/_cpdispatch.py index 3fb19fe9b..a396283b9 100644 --- a/cherrypy/_cpdispatch.py +++ b/cherrypy/_cpdispatch.py @@ -231,7 +231,8 @@ def kwargs(self): """Page handler keyword arguments. The returned value contains data merged in - from ``cherrypy.request.params``.""" + from ``cherrypy.request.params``. + """ kwargs = cherrypy.serving.request.params.copy() if self._kwargs: kwargs.update(self._kwargs) @@ -405,7 +406,8 @@ def find_handler(self, path): def set_conf(): """Collapse all ``object_trail`` conf into config. - The config being ``cherrypy.request.config``.""" + The config being ``cherrypy.request.config``. + """ base = cherrypy.config.copy() # Note that we merge the config from each node # even if that node was None. From c8ade1864780e9879b6c0955f4ec11b3abbf891d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 21:46:22 +0200 Subject: [PATCH 07/69] Rephrase a function docstring in dispatch --- cherrypy/_cpdispatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/_cpdispatch.py b/cherrypy/_cpdispatch.py index a396283b9..782bb22c1 100644 --- a/cherrypy/_cpdispatch.py +++ b/cherrypy/_cpdispatch.py @@ -621,7 +621,7 @@ def merge(nodeconf): def XMLRPCDispatcher(next_dispatcher=Dispatcher()): - """An HTTP dispatcher variant implementing XML-RPC.""" + """Chain an HTTP dispatcher variant implementing XML-RPC.""" from cherrypy.lib import xmlrpcutil def xmlrpc_dispatch(path_info): From 980af9b3b318feff4e56ea6361b1ac35c69477ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 21:52:42 +0200 Subject: [PATCH 08/69] Fix the spelling of CherryPy in logging mod --- cherrypy/_cplogging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/_cplogging.py b/cherrypy/_cplogging.py index ac9c6a571..ec183a12f 100644 --- a/cherrypy/_cplogging.py +++ b/cherrypy/_cplogging.py @@ -1,5 +1,5 @@ """ -Cherrpy Logging module. +CherryPy logging module. Simple config ============= From 8373831aad0e40280e84bd8d9db0c2a49f3daaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 21:54:07 +0200 Subject: [PATCH 09/69] Normalize the http error mod docstrings --- cherrypy/_cperror.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/cherrypy/_cperror.py b/cherrypy/_cperror.py index 816b3a167..34061a445 100644 --- a/cherrypy/_cperror.py +++ b/cherrypy/_cperror.py @@ -149,7 +149,7 @@ class InternalRedirect(CherryPyException): """ def __init__(self, path, query_string=''): - """Initialize InternalRedirect.""" + """Initialize the internal redirect exception.""" self.request = cherrypy.serving.request self.query_string = query_string @@ -202,7 +202,7 @@ class HTTPRedirect(CherryPyException): """The encoding when passed urls are not native strings.""" def __init__(self, urls, status=None, encoding=None): - """Initialize HTTPRedirect.""" + """Initialize the HTTP redirect exception.""" self.urls = abs_urls = [ # Note that urljoin will "do the right thing" whether url is: # 1. a complete URL with host (e.g. "http://www.example.com/test") @@ -228,7 +228,9 @@ def __init__(self, urls, status=None, encoding=None): @classproperty def default_status(cls): - """Redirect status for the request, this is the default handler. + """Redirect status for the request. + + This is the default handler. RFC 2616 indicates a 301 response code fits our goal; however, browser support for 301 is quite messy. Use 302/303 instead. See @@ -243,7 +245,7 @@ def status(self): return status def set_response(self): - """Modify cherrypy.response to represent self. + """Modify ``cherrypy.response`` to represent ``self``. Modifies status, headers, and body. @@ -368,7 +370,7 @@ class HTTPError(CherryPyException): """The HTTP Reason-Phrase string.""" def __init__(self, status=500, message=None): - """Initialize HTTPError.""" + """Initialize an HTTP error.""" self.status = status try: self.code, self.reason, defaultmsg = _httputil.valid_status(status) @@ -384,7 +386,7 @@ def __init__(self, status=500, message=None): CherryPyException.__init__(self, status, message) def set_response(self): - """Modify cherrypy.response to represent self. + """Modify ``cherrypy.response`` to represent ``self``. Modifies status, headers, and body. @@ -412,7 +414,7 @@ def set_response(self): _be_ie_unfriendly(self.code) def get_error_page(self, *args, **kwargs): - """Get error page.""" + """Compose an HTML page with error information.""" return get_error_page(*args, **kwargs) def __call__(self): @@ -437,7 +439,7 @@ class NotFound(HTTPError): """ def __init__(self, path=None): - """Initialize NotFound HTTPError.""" + """Initialize an HTTP Not Found error.""" if path is None: request = cherrypy.serving.request path = request.script_name + request.path_info From fe8867d9e8fed2f292895db730e3b256ab159e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 22:03:48 +0200 Subject: [PATCH 10/69] Improve the look of the logging module docstrings --- cherrypy/_cplogging.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/cherrypy/_cplogging.py b/cherrypy/_cplogging.py index ec183a12f..dae72692b 100644 --- a/cherrypy/_cplogging.py +++ b/cherrypy/_cplogging.py @@ -128,15 +128,15 @@ class NullHandler(logging.Handler): """A no-op logging handler to silence the logging.lastResort handler.""" def handle(self, record): - """Handle stub.""" + """Handle a log record doing no-op.""" pass def emit(self, record): - """Emit stub.""" + """Emit a log record doing no-op.""" pass def createLock(self): - """Create Lock stub.""" + """Lock log write with no-op.""" self.lock = None @@ -172,7 +172,7 @@ class LogManager(object): """ def __init__(self, appid=None, logger_root='cherrypy'): - """Initialize LogManager.""" + """Initialize a CherryPy log manager.""" self.logger_root = logger_root self.appid = appid if appid is None: @@ -223,7 +223,7 @@ def error(self, msg='', context='', severity=logging.INFO, ) def __call__(self, *args, **kwargs): - """Call handler, An alias for ``error``.""" + """Record an error log entry.""" return self.error(*args, **kwargs) def access(self): @@ -420,7 +420,10 @@ def wsgi(self, newvalue): class WSGIErrorHandler(logging.Handler): - """Handler class that writes logging records to environ['wsgi.errors'].""" + """A handler class writing logs to WSGI env. + + Specifically, the target is ``environ['wsgi.errors']``. + """ def flush(self): """Flushes the stream.""" @@ -456,7 +459,7 @@ def emit(self, record): class LazyRfc3339UtcTime(object): - """LazyRfc3339UtcTime class.""" + """A postponed timestamp string retrieval class.""" def __str__(self): """Return datetime in RFC3339 UTC Format.""" From 368a91342fe5ba2fc1526f2b7e3cc0ada353a275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 22:13:57 +0200 Subject: [PATCH 11/69] Improcve the `mod_python` integration docstrings --- cherrypy/_cpmodpy.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cherrypy/_cpmodpy.py b/cherrypy/_cpmodpy.py index 9fd2490cf..9029b43d8 100644 --- a/cherrypy/_cpmodpy.py +++ b/cherrypy/_cpmodpy.py @@ -72,7 +72,7 @@ def setup_server(): def setup(req): - """Handle setup.""" + """Execute pre-initialization functions.""" from mod_python import apache # Run any setup functions defined by a "PythonOption cherrypy.setup" @@ -141,7 +141,7 @@ def __init__(self, req): def handler(req): - """Run handler.""" + """Invoke the HTTP handler.""" from mod_python import apache try: global _isSetUp @@ -253,7 +253,7 @@ def handler(req): def send_response(req, status, headers, body, stream=False): - """Handle sending response.""" + """Send the HTTP response to the client.""" # Set response status req.status = int(status[:3]) @@ -279,20 +279,20 @@ def send_response(req, status, headers, body, stream=False): import subprocess def popen(fullcmd): - """Open process.""" + """Invoke a subprocess via :mod:`subprocess`.""" p = subprocess.Popen(fullcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) return p.stdout except ImportError: def popen(fullcmd): - """Open process.""" + """Invoke a subprocess via :mod:`os`.""" pipein, pipeout = os.popen4(fullcmd) return pipeout def read_process(cmd, args=''): - """Handle read process.""" + """Return a subprocess standard output.""" fullcmd = '%s %s' % (cmd, args) pipeout = popen(fullcmd) try: @@ -311,7 +311,7 @@ def read_process(cmd, args=''): class ModPythonServer(object): - """Mod Python Server class.""" + """A server wrapper for ``mod_python``.""" template = """ # Apache2 server configuration file for running CherryPy with mod_python. @@ -330,7 +330,7 @@ class ModPythonServer(object): def __init__(self, loc='/', port=80, opts=None, apache_path='apache', handler='cherrypy._cpmodpy::handler'): - """Initialize ModPythonServer.""" + """Initialize a ``mod_python`` server.""" self.loc = loc self.port = port self.opts = opts @@ -338,7 +338,7 @@ def __init__(self, loc='/', port=80, opts=None, apache_path='apache', self.handler = handler def start(self): - """Handle start.""" + """Start an Apache2/httpd server.""" opts = ''.join([' PythonOption %s %s\n' % (k, v) for k, v in self.opts]) conf_data = self.template % {'port': self.port, @@ -356,6 +356,6 @@ def start(self): return response def stop(self): - """Handle stop.""" + """Stop an Apache2/httpd server.""" os.popen('apache -k stop') self.ready = False From e04421ec0c9663d3a1394e2f704cbc4e38a439fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 22:32:28 +0200 Subject: [PATCH 12/69] Improve docstrings for request body handler --- cherrypy/_cpreqbody.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/cherrypy/_cpreqbody.py b/cherrypy/_cpreqbody.py index 672bb7e40..ffa6289f2 100644 --- a/cherrypy/_cpreqbody.py +++ b/cherrypy/_cpreqbody.py @@ -220,7 +220,10 @@ def process_multipart(entity): def process_multipart_form_data(entity): - """Read multipart/form-data parts into entity.parts or entity.params.""" + """Read ``multipart/form-data`` parts. + + This function saves them into ``entity.parts`` or ``entity.params``. + """ process_multipart(entity) kept_parts = [] @@ -410,7 +413,7 @@ class Entity(object): """ def __init__(self, fp, headers, params=None, parts=None): - """Initialize Entity.""" + """Initialize an HTTP entity.""" # Make an instance-specific copy of the class processors # so Tools, etc. can replace them per-request. self.processors = self.processors.copy() @@ -479,30 +482,30 @@ def __init__(self, fp, headers, params=None, parts=None): self.filename = unquote(str(filename), encoding) def read(self, size=None, fp_out=None): - """Handle read.""" + """Read bytes from the connection.""" return self.fp.read(size, fp_out) def readline(self, size=None): - """Handle readline.""" + """Read a line of bytes from the connection.""" return self.fp.readline(size) def readlines(self, sizehint=None): - """Handle readlines.""" + """Read some byte lines from the connection.""" return self.fp.readlines(sizehint) def __iter__(self): - """Handle iterations.""" + """Set up the iterator.""" return self def __next__(self): - """Handle next.""" + """Return the next line of bytes.""" line = self.readline() if not line: raise StopIteration return line def next(self): - """Handle next.""" + """Return the next line of bytes.""" # FIXME: python 2? return self.__next__() def read_into_file(self, fp_out=None): @@ -570,10 +573,10 @@ def process(self): proc(self) def default_proc(self): - """Handle default proc. + """Process unknown data as a fallback. Called if a more-specific processor is not found for the - ``Content-Type`` + ``Content-Type``. """ # Leave the fp alone for someone else to read. This works fine # for request.body, but the Part subclasses need to override this @@ -622,7 +625,7 @@ class Part(Entity): """ def __init__(self, fp, headers, boundary): - """Initialize Part.""" + """Initialize an entity part.""" Entity.__init__(self, fp, headers) self.boundary = boundary self.file = None @@ -630,13 +633,13 @@ def __init__(self, fp, headers, boundary): @classmethod def from_fp(cls, fp, boundary): - """Load from fp.""" + """Initialize an entity part from a file handle.""" headers = cls.read_headers(fp) return cls(fp, headers, boundary) @classmethod def read_headers(cls, fp): - """Read headers.""" + """Read HTTP headers from a file handle.""" headers = httputil.HeaderMap() while True: line = fp.readline() @@ -724,7 +727,7 @@ def read_lines_to_boundary(self, fp_out=None): return fp_out def default_proc(self): - """Handle default proc. + """Process unknown data as a fallback. Called if a more-specific processor is not found for the ``Content-Type``. @@ -756,11 +759,11 @@ def read_into_file(self, fp_out=None): class SizedReader: - """SizedReader class.""" + """A buffered/sized reader.""" def __init__(self, fp, length, maxbytes, bufsize=DEFAULT_BUFFER_SIZE, has_trailers=False): - """Initialize SizedReader.""" + """Initialize buffered file handle reader.""" # Wrap our fp in a buffer so peek() works self.fp = fp self.length = length @@ -903,7 +906,7 @@ def readlines(self, sizehint=None): return lines def finish(self): - """Handle finish.""" + """Finalize reading the HTTP trailer headers.""" self.done = True if self.has_trailers and hasattr(self.fp, 'read_trailer_lines'): self.trailers = {} @@ -961,7 +964,7 @@ class RequestBody(Entity): """ def __init__(self, fp, headers, params=None, request_params=None): - """Initialize RequestBody.""" + """Initialize a request body entity.""" Entity.__init__(self, fp, headers, params) # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1 From dc9271d187380f6e2cec8df7ceb6af05232b54c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 23:07:27 +0200 Subject: [PATCH 13/69] Improve the docstrings in the request module --- cherrypy/_cprequest.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/cherrypy/_cprequest.py b/cherrypy/_cprequest.py index a9eb28710..89356a0fc 100644 --- a/cherrypy/_cprequest.py +++ b/cherrypy/_cprequest.py @@ -42,7 +42,7 @@ class Hook(object): callable on each call.""" def __init__(self, callback, failsafe=None, priority=None, **kwargs): - """Initialize Hook.""" + """Initialize the hook instance.""" self.callback = callback if failsafe is None: @@ -75,7 +75,7 @@ def __call__(self): return self.callback(**self.kwargs) def __repr__(self): - """Represent Hook.""" + """Render a string representation of :class:`Hook` instance.""" cls = self.__class__ return ('%s.%s(callback=%r, failsafe=%r, priority=%r, %s)' % (cls.__module__, cls.__name__, self.callback, @@ -88,14 +88,14 @@ class HookMap(dict): """A map of call points to lists of callbacks (Hook objects).""" def __new__(cls, points=None): - """Handle New HookMap.""" + """Construct a fresh hook map instance.""" d = dict.__new__(cls) for p in points or []: d[p] = [] return d def __init__(self, *a, **kw): - """Initialize HookMap.""" + """Initialize a hook map instance post-construction.""" pass def attach(self, point, callback, failsafe=None, priority=None, **kwargs): @@ -136,7 +136,7 @@ def run_hooks(cls, hooks): raise def __copy__(self): - """Copy.""" + """Duplicate object per the copy protocol.""" newmap = self.__class__() # We can't just use 'update' because we want copies of the # mutable values (each is a list) as well. @@ -146,7 +146,7 @@ def __copy__(self): copy = __copy__ def __repr__(self): - """Represent HookMap.""" + """Render a string representation of :class:`HookMap`.""" cls = self.__class__ return '%s.%s(points=%r)' % ( cls.__module__, @@ -555,7 +555,9 @@ def close(self): self.stage = 'close' def run(self, method, path, query_string, req_protocol, headers, rfile): - r"""Process the Request (Core). + r"""Process the request. + + *(core)* method, path, query_string, and req_protocol should be pulled directly from the Request-Line (e.g. "GET /path?key=val HTTP/1.0"). @@ -829,7 +831,7 @@ class ResponseBody(object): 'if you wish to return unicode.') def __get__(self, obj, objclass=None): - """Handle get for ReponseBody.""" + """Return a response body through the descriptor protocol.""" if obj is None: # When calling on the class instead of an instance... return self @@ -837,7 +839,10 @@ def __get__(self, obj, objclass=None): return obj._body def __set__(self, obj, value): - """Convert the given value to an iterable object.""" + """Set a response body through the descriptor protocol. + + Convert the given value to an iterable object. + """ if isinstance(value, str): raise ValueError(self.unicode_err) elif isinstance(value, list): @@ -889,7 +894,7 @@ class Response(object): """If False, buffer the response body.""" def __init__(self): - """Intialize Response.""" + """Intialize the HTTP response instance.""" self.status = None self.header_list = None self._body = [] @@ -912,12 +917,12 @@ def collapse_body(self): return new_body def _flush_body(self): - """_flush_body Response. + """Exhaust the body iterator. :rtype: None - Discard self.body but consume any generator such that any - finalization can occur, such as is required by caching.tee_output(). + Discard ``self.body`` but consume any generator such that any + finalization can occur, such as is required by ``caching.tee_output()``. """ consume(iter(self.body)) @@ -972,7 +977,7 @@ def finalize(self): class LazyUUID4(object): - """LazyUUID4 class.""" + """A delayed UUID4 string maker.""" def __str__(self): """Return UUID4 and keep it for future calls.""" From 73619fad9319a184268172fe1ea5f13197f18c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 23:30:33 +0200 Subject: [PATCH 14/69] Split the long line in a docstring in request mod --- cherrypy/_cprequest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cherrypy/_cprequest.py b/cherrypy/_cprequest.py index 89356a0fc..f4a2c7efd 100644 --- a/cherrypy/_cprequest.py +++ b/cherrypy/_cprequest.py @@ -922,7 +922,8 @@ def _flush_body(self): :rtype: None Discard ``self.body`` but consume any generator such that any - finalization can occur, such as is required by ``caching.tee_output()``. + finalization can occur, such as is required by + ``caching.tee_output()``. """ consume(iter(self.body)) From b6813685bd23ac85ce22fa2474ad504d180927b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 22 May 2024 23:47:00 +0200 Subject: [PATCH 15/69] Improve docstrings in the tools module --- cherrypy/_cptools.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/cherrypy/_cptools.py b/cherrypy/_cptools.py index 610ebfa21..883ba785c 100644 --- a/cherrypy/_cptools.py +++ b/cherrypy/_cptools.py @@ -57,7 +57,7 @@ class Tool(object): namespace = 'tools' def __init__(self, point, callable, name=None, priority=50): - """Initialize Tool.""" + """Initialize a CherryPy tool instance.""" self._point = point self.callable = callable self._name = name @@ -67,12 +67,12 @@ def __init__(self, point, callable, name=None, priority=50): @property def on(self): - """Property on.""" + """Flag whether the tool is enabled.""" raise AttributeError(_attr_error) @on.setter def on(self, value): - """Setter for on property.""" + """Set a flag for whether the tool is enabled.""" raise AttributeError(_attr_error) def _setargs(self): @@ -136,7 +136,7 @@ def tool_decorator(f): return tool_decorator def _setup(self): - """Hooking this tool into cherrypy.request. + """Wire this tool into ``cherrypy.request``. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -162,7 +162,7 @@ class HandlerTool(Tool): """ def __init__(self, callable, name=None): - """Initialize HandlerTool.""" + """Initialize a handler tool.""" Tool.__init__(self, 'before_handler', callable, name) def handler(self, *args, **kwargs): @@ -187,7 +187,7 @@ def _wrapper(self, **kwargs): cherrypy.serving.request.handler = None def _setup(self): - """Hooking this tool into cherrypy.request. + """Wire this tool into ``cherrypy.request``. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -221,14 +221,14 @@ def interpolator(next_handler, *args, **kwargs): def __init__(self, newhandler, point='before_handler', name=None, priority=50): - """Initialize HandlerWrapperTool.""" + """Initialize a handler wrapper tool.""" self.newhandler = newhandler self._point = point self._name = name self._priority = priority def callable(self, *args, **kwargs): - """Make HandlerWrapperTool callable.""" + """Decorate a request handler with a handler tool callable.""" innerfunc = cherrypy.serving.request.handler def wrap(*args, **kwargs): @@ -240,14 +240,14 @@ class ErrorTool(Tool): """Tool which is used to replace the default request.error_response.""" def __init__(self, callable, name=None): - """Initialize ErrorTool.""" + """Initialize an error tool.""" Tool.__init__(self, None, callable, name) def _wrapper(self): self.callable(**self._merged_args()) def _setup(self): - """Hooking this tool into cherrypy.request. + """Wire this tool into ``cherrypy.request``. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -277,7 +277,7 @@ class SessionTool(Tool): """ def __init__(self): - """Initialize SessionTool.""" + """Initialize a session tool.""" # _sessions.init must be bound after headers are read Tool.__init__(self, 'before_request_body', _sessions.init) @@ -285,7 +285,7 @@ def _lock_session(self): cherrypy.serving.session.acquire_lock() def _setup(self): - """Hooking this tool into cherrypy.request. + """Wire this tool into ``cherrypy.request``. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -368,7 +368,7 @@ class XMLRPCController(object): @expose def default(self, *vpath, **params): - """Handle default XMLRPCController.""" + """Process the unhandled XML-RPC methods.""" rpcparams, rpcmethod = _xmlrpc.process_body() subhandler = self @@ -393,9 +393,7 @@ def default(self, *vpath, **params): class SessionAuthTool(HandlerTool): - """Stub for SessionAuthTool.""" - - pass + """An HTTP session authentication tool.""" class CachingTool(Tool): @@ -413,7 +411,7 @@ def _wrapper(self, **kwargs): _wrapper.priority = 90 def _setup(self): - """Hooking caching into cherrypy.request.""" + """Wire caching into ``cherrypy.request``.""" conf = self._merged_args() p = conf.pop('priority', None) @@ -430,11 +428,11 @@ class Toolbox(object): """ def __init__(self, namespace): - """Initialize Toolbox.""" + """Initialize a toolbox instance.""" self.namespace = namespace def __setattr__(self, name, value): - """Set attribute for Toolbox.""" + """Set an attribute on this :class:`Toolbox` instance.""" # If the Tool._name is None, supply it from the attribute name. if isinstance(value, Tool): if value._name is None: @@ -462,7 +460,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): tool._setup() def register(self, point, **kwargs): - """Register Toolbox. + """Register a hook point handler in the toolbox. Return a decorator which registers the function at the given hook point. From 4418bb941f425dddc953f25498f4f5ad6d9dc132 Mon Sep 17 00:00:00 2001 From: Dan Radez Date: Thu, 23 May 2024 10:10:21 -0400 Subject: [PATCH 16/69] Update cherrypy/lib/auth_digest.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- cherrypy/lib/auth_digest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/lib/auth_digest.py b/cherrypy/lib/auth_digest.py index f8b5d698a..d9679a25a 100644 --- a/cherrypy/lib/auth_digest.py +++ b/cherrypy/lib/auth_digest.py @@ -143,7 +143,7 @@ def synthesize_nonce(s, key, timestamp=None): def H(s): - """Return an md5_hex hash.""" + """Return an ``md5`` HEX hash.""" return md5_hex(s) From c3421b4321dcd39ee1cc2f180961908652b478f4 Mon Sep 17 00:00:00 2001 From: Dan Radez Date: Thu, 23 May 2024 10:10:30 -0400 Subject: [PATCH 17/69] Update cherrypy/lib/auth_digest.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- cherrypy/lib/auth_digest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/lib/auth_digest.py b/cherrypy/lib/auth_digest.py index d9679a25a..2651e99b5 100644 --- a/cherrypy/lib/auth_digest.py +++ b/cherrypy/lib/auth_digest.py @@ -168,7 +168,7 @@ class HttpDigestAuthorization(object): scheme = 'digest' def errmsg(self, s): - """Error message for HttpDigestAuthorization.""" + """Make an error message for HTTP Digest Authorization.""" return 'Digest Authorization header: %s' % s @classmethod From 3d83e7233de275e535b2fa21338d13635a3f9f55 Mon Sep 17 00:00:00 2001 From: Dan Radez Date: Thu, 23 May 2024 10:10:40 -0400 Subject: [PATCH 18/69] Update cherrypy/lib/auth_digest.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- cherrypy/lib/auth_digest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/lib/auth_digest.py b/cherrypy/lib/auth_digest.py index 2651e99b5..fc99d2b29 100644 --- a/cherrypy/lib/auth_digest.py +++ b/cherrypy/lib/auth_digest.py @@ -181,7 +181,7 @@ def __init__( self, auth_header, http_method, debug=False, accept_charset=DEFAULT_CHARSET[:], ): - """Initialize HttpDigestAuthorization.""" + """Initialize an HTTP Digest Authorization parser.""" self.http_method = http_method self.debug = debug From f04daa01e0e3083ba68d3428933f14b4120e9650 Mon Sep 17 00:00:00 2001 From: Dan Radez Date: Thu, 23 May 2024 10:10:48 -0400 Subject: [PATCH 19/69] Update cherrypy/lib/auth_digest.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- cherrypy/lib/auth_digest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/lib/auth_digest.py b/cherrypy/lib/auth_digest.py index fc99d2b29..c1c9546d1 100644 --- a/cherrypy/lib/auth_digest.py +++ b/cherrypy/lib/auth_digest.py @@ -173,7 +173,7 @@ def errmsg(self, s): @classmethod def matches(cls, header): - """Compare cls.scheme to header.scheme.""" + """Check if header scheme matches auth implementation.""" scheme, _, _ = header.partition(' ') return scheme.lower() == cls.scheme From 9eb06d7978c152a54af77997711f57063ee45c8d Mon Sep 17 00:00:00 2001 From: Dan Radez Date: Thu, 23 May 2024 10:10:56 -0400 Subject: [PATCH 20/69] Update cherrypy/lib/auth_digest.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- cherrypy/lib/auth_digest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/lib/auth_digest.py b/cherrypy/lib/auth_digest.py index c1c9546d1..697633fa7 100644 --- a/cherrypy/lib/auth_digest.py +++ b/cherrypy/lib/auth_digest.py @@ -240,7 +240,7 @@ def __init__( 'neither cnonce nor nc can be present')) def __str__(self): - """Stringify represetation of HttpDigestAuthorization.""" + """Render an HTTP Digest Auth header as a string.""" return 'authorization : %s' % self.auth_header def validate_nonce(self, s, key): From 2c0688d439a15549771d66c34fedfe0ff03e8ac6 Mon Sep 17 00:00:00 2001 From: Dan Radez Date: Thu, 23 May 2024 10:11:03 -0400 Subject: [PATCH 21/69] Update cherrypy/lib/auth_digest.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- cherrypy/lib/auth_digest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/lib/auth_digest.py b/cherrypy/lib/auth_digest.py index 697633fa7..abf19b45c 100644 --- a/cherrypy/lib/auth_digest.py +++ b/cherrypy/lib/auth_digest.py @@ -389,7 +389,7 @@ def www_authenticate( def digest_auth(realm, get_ha1, key, debug=False, accept_charset='utf-8'): """Perform HTTP Digest Access Authentication. - A CherryPy tool that hooks at before_handler to perform + A CherryPy tool that hooks at ``before_handler`` to perform HTTP Digest Access Authentication, as specified in :rfc:`2617`. If the request has an 'authorization' header with a 'Digest' scheme, From 6962e42588db0ef42a2940cbc422c3d6ac31fc19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 17:31:34 +0200 Subject: [PATCH 22/69] Clarify `MemoryCache` initializer docstring --- cherrypy/lib/caching.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/lib/caching.py b/cherrypy/lib/caching.py index ed0b534ff..4728ee7db 100644 --- a/cherrypy/lib/caching.py +++ b/cherrypy/lib/caching.py @@ -163,7 +163,7 @@ class MemoryCache(Cache): debug = False def __init__(self): - """Initialize Memory Caching.""" + """Initialize in-memory cache store.""" self.clear() # Run self.expire_cache in a separate daemon thread. From 818284090bcc4adc8338673db1172a0d316e388d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 17:48:54 +0200 Subject: [PATCH 23/69] Clarify `cherrypy.lib.caching` docstring --- cherrypy/lib/caching.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/lib/caching.py b/cherrypy/lib/caching.py index 4728ee7db..a2522f337 100644 --- a/cherrypy/lib/caching.py +++ b/cherrypy/lib/caching.py @@ -1,5 +1,5 @@ """ -CherryPy Cache implementation. +CherryPy cache tooling. CherryPy implements a simple caching system as a pluggable Tool. This tool tries to be an (in-process) HTTP/1.1-compliant cache. It's not quite there From ea6e6c934b1598bd241b77e09dc72a72e829c95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 18:28:19 +0200 Subject: [PATCH 24/69] Clarify docstrings in `cherrypy.lib.covercp` module --- cherrypy/lib/covercp.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cherrypy/lib/covercp.py b/cherrypy/lib/covercp.py index 4063f9f4d..a2621a2d4 100644 --- a/cherrypy/lib/covercp.py +++ b/cherrypy/lib/covercp.py @@ -38,7 +38,7 @@ the_coverage = coverage(data_file=localFile) def start(): - """Start coverage.""" + """Start collecting coverage.""" the_coverage.start() except ImportError: # Setting the_coverage to None will raise errors @@ -51,7 +51,7 @@ def start(): 'coverage.py could not be imported.') def start(): - """Start coverage.""" + """Start collecting coverage.""" pass start.priority = 20 @@ -286,10 +286,10 @@ def get_tree(base, exclude, coverage=the_coverage): class CoverStats(object): - """CoverStats route handler.""" + """HTTP handler for the coverage stats.""" def __init__(self, coverage, root=None): - """Initialize CoverStats.""" + """Initialize the coverage stats application.""" self.coverage = coverage if root is None: # Guess initial depth. Files outside this path will not be @@ -299,13 +299,13 @@ def __init__(self, coverage, root=None): @cherrypy.expose def index(self): - """Index of CoverStats.""" + """Render the coverage stats index page.""" return TEMPLATE_FRAMESET % self.root.lower() @cherrypy.expose def menu(self, base='/', pct='50', showpct='', exclude=r'python\d\.\d|test|tut\d|tutorial'): - """Return menu html content.""" + """Render HTML menu web page.""" # The coverage module uses all-lower-case names. base = base.lower().rstrip(os.sep) @@ -339,7 +339,7 @@ def menu(self, base='/', pct='50', showpct='', yield '' def annotated_file(self, filename, statements, excluded, missing): - """Return annotated file.""" + """Annotate given file with coverage information.""" with open(filename, 'r') as source: lines = source.readlines() buffer = [] @@ -364,7 +364,7 @@ def annotated_file(self, filename, statements, excluded, missing): @cherrypy.expose def report(self, name): - """Report coverage stats.""" + """Render coverage stats as HTML.""" filename, statements, excluded, missing, _ = self.coverage.analysis2( name) pc = _percent(statements, missing) @@ -381,7 +381,7 @@ def report(self, name): def serve(path=localFile, port=8080, root=None): - """Serve coverage server.""" + """Serve the coverage app over HTTP.""" if coverage is None: raise ImportError('The coverage module could not be imported.') from coverage import coverage From 83f273500d5ccc7f7187f744e56bd5a330b7e3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 19:25:23 +0200 Subject: [PATCH 25/69] Clarify docstrings in `cherrypy.lib.cpstats` module --- cherrypy/lib/cpstats.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/cherrypy/lib/cpstats.py b/cherrypy/lib/cpstats.py index dfd1a5e29..5b9c85e47 100644 --- a/cherrypy/lib/cpstats.py +++ b/cherrypy/lib/cpstats.py @@ -249,7 +249,7 @@ def extrapolate_statistics(scope): def proc_time(s): - """Return proc time.""" + """Compute current HTTP request processing time.""" return time.time() - s['Start Time'] @@ -257,24 +257,24 @@ class ByteCountWrapper(object): """Wraps a file-like object, counting the number of bytes read.""" def __init__(self, rfile): - """Initialize ByteCountWrapper.""" + """Initialize a read byte counter.""" self.rfile = rfile self.bytes_read = 0 def read(self, size=-1): - """Read method for ByteCountWrapper.""" + """Read from file, counting bytes.""" data = self.rfile.read(size) self.bytes_read += len(data) return data def readline(self, size=-1): - """Readline method for ByteCountWrapper.""" + """Read a line from file, counting bytes.""" data = self.rfile.readline(size) self.bytes_read += len(data) return data def readlines(self, sizehint=0): - """Readline method for ByteCountWrapper.""" + """Read a list of lines from file, counting bytes.""" # Shamelessly stolen from StringIO total = 0 lines = [] @@ -288,27 +288,27 @@ def readlines(self, sizehint=0): return lines def close(self): - """Close method for ByteCountWrapper.""" + """Close the underlying file object.""" self.rfile.close() def __iter__(self): - """Iterate method for ByteCountWrapper.""" + """Make a file reader iterator.""" return self def next(self): - """Next method for ByteCountWrapper.""" + """Return next portion of bytes from the iterated file.""" data = self.rfile.next() self.bytes_read += len(data) return data def average_uriset_time(s): - """Return the average uriset time.""" + """Compute average request processing time within a URI set.""" return s['Count'] and (s['Sum'] / s['Count']) or 0 def _get_threading_ident(): - """Get threading identity.""" + """Discover the current thread identifier.""" if sys.version_info >= (3, 3): return threading.get_ident() return threading._get_ident() @@ -318,11 +318,11 @@ class StatsTool(cherrypy.Tool): """Record various information about the current request.""" def __init__(self): - """Initialize StatsTool.""" + """Initialize the statistics gathering tool.""" cherrypy.Tool.__init__(self, 'on_end_request', self.record_stop) def _setup(self): - """Set Hook for this tool into cherrypy.request. + """Plug this tool into ``cherrypy.request``. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. @@ -415,17 +415,17 @@ def record_stop( def locale_date(v): - """Return date formated for locale.""" + """Format given date per current locale.""" return time.strftime('%c', time.gmtime(v)) def iso_format(v): - """Return date formated ISO.""" + """Format given date as ISO string.""" return time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(v)) def pause_resume(ns): - """Return pause and return forms.""" + """Produce pause or resume HTML form maker.""" def _pause_resume(enabled): pause_disabled = '' resume_disabled = '' @@ -447,7 +447,7 @@ def _pause_resume(enabled): class StatsPage(object): - """StatsPage class.""" + """An app rendering the gathered statistics.""" formatting = { 'CherryPy Applications': { @@ -489,7 +489,7 @@ class StatsPage(object): @cherrypy.expose def index(self): - """Route handler for index.""" + """Render the app stats index page.""" # Transform the raw data into pretty output for HTML yield """ @@ -688,14 +688,14 @@ def get_list_collection(self, v, formatting): if json is not None: @cherrypy.expose def data(self): - """Return json data.""" + """Render statistics as JSON.""" s = extrapolate_statistics(logging.statistics) cherrypy.response.headers['Content-Type'] = 'application/json' return json.dumps(s, sort_keys=True, indent=4).encode('utf-8') @cherrypy.expose def pause(self, namespace): - """Pause.""" + """Pause gathering the statistics.""" logging.statistics.get(namespace, {})['Enabled'] = False raise cherrypy.HTTPRedirect('./') pause.cp_config = {'tools.allow.on': True, @@ -703,7 +703,7 @@ def pause(self, namespace): @cherrypy.expose def resume(self, namespace): - """Resume.""" + """Resume gathering the statistics.""" logging.statistics.get(namespace, {})['Enabled'] = True raise cherrypy.HTTPRedirect('./') resume.cp_config = {'tools.allow.on': True, From d8ece8bc2080e5a48dfca3f638f4ff58fd9a7d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 19:55:58 +0200 Subject: [PATCH 26/69] Clarify docstrings in `cherrypy.lib.cptools` module --- cherrypy/lib/cptools.py | 45 ++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/cherrypy/lib/cptools.py b/cherrypy/lib/cptools.py index 17e981717..2fc8ea878 100644 --- a/cherrypy/lib/cptools.py +++ b/cherrypy/lib/cptools.py @@ -287,28 +287,45 @@ class SessionAuth(object): debug = False def check_username_and_password(self, username, password): - """Check username and password stub.""" - pass + """Assert the login credentials. + + :param username: A user name sent from the login form. + :type username: str + :param password: A pass word sent from the login form. + :type password: str + + :returns: A non-empty error string if the authentication fails. + :rtype: str + """ def anonymous(self): """Provide a temporary user name for anonymous users.""" pass def on_login(self, username): - """Login event stub.""" - pass + """Process a successful login event. + + :param username: The logged in user name. + :type username: str + """ def on_logout(self, username): - """Logout event stub.""" - pass + """Process a successful logout event. + + :param username: The logged out user name. + :type username: str + """ def on_check(self, username): - """Check event stub.""" - pass + """Process a successful check event. + + :param username: The checked user name. + :type username: str + """ def login_screen(self, from_page='..', username='', error_msg='', **kwargs): - """Login screen.""" + """Render the login HTML page.""" return (str(""" Message: %(error_msg)s @@ -389,7 +406,7 @@ def _debug_message(self, template, context={}): cherrypy.log(template % context, 'TOOLS.SESSAUTH') def run(self): - """Handle run.""" + """Perform session authentication.""" request = cherrypy.serving.request response = cherrypy.serving.response @@ -597,21 +614,21 @@ def accept(media=None, debug=False): class MonitoredHeaderMap(_httputil.HeaderMap): - """MonitoredHeaderMap class.""" + """An access-tracked HTTP header mapping.""" def transform_key(self, key): - """Transform key.""" + """Normalize and track an HTTP header name.""" self.accessed_headers.add(key) return super(MonitoredHeaderMap, self).transform_key(key) def __init__(self): - """Initialize MonitoredHeaderMap.""" + """Initialize a monitored HTTP header mapping.""" self.accessed_headers = set() super(MonitoredHeaderMap, self).__init__() def autovary(ignore=None, debug=False): - """Auto-populate Vary response header based on request.header access.""" + """Populate ``Vary`` response header based on ``request.header`` access.""" request = cherrypy.serving.request req_h = request.headers From 8e184c9bce722cae23590205a8fe616b1216268d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 20:23:16 +0200 Subject: [PATCH 27/69] Clarify docstrings in `cherrypy.lib.encoding` module --- cherrypy/lib/encoding.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cherrypy/lib/encoding.py b/cherrypy/lib/encoding.py index ee4c2606d..42419bacd 100644 --- a/cherrypy/lib/encoding.py +++ b/cherrypy/lib/encoding.py @@ -45,38 +45,38 @@ class UTF8StreamEncoder: """UTF8 Stream Encoder.""" def __init__(self, iterator): - """Initialize UTF8StreamEncoder.""" + """Initialize a UTF-8 stream encoder instance.""" self._iterator = iterator def __iter__(self): - """Iterate for UTF8StreamEncoder.""" + """Make a UTF-8-encoded stream iterator.""" return self def next(self): - """Next for UTF8StreamEncoder.""" + """UTF-8-encode the next chunk of the stream.""" return self.__next__() def __next__(self): - """Next for UTF8StreamEncoder.""" + """UTF-8-encode the next chunk of the stream.""" res = next(self._iterator) if isinstance(res, str): res = res.encode('utf-8') return res def close(self): - """Close for UTF8StreamEncoder.""" + """Close the underlying byte stream.""" if is_closable_iterator(self._iterator): self._iterator.close() def __getattr__(self, attr): - """Get attr for UTF8StreamEncoder.""" + """Return the underlying byte stream attribute value.""" if attr.startswith('__'): raise AttributeError(self, attr) return getattr(self._iterator, attr) class ResponseEncoder: - """Response Encoder.""" + """An HTTP response payload encoder.""" default_encoding = 'utf-8' failmsg = 'Response body could not be encoded with %r.' @@ -87,7 +87,7 @@ class ResponseEncoder: debug = False def __init__(self, **kwargs): - """Initialize ResponseEncoder.""" + """Initialize HTTP response payload encoder.""" for k, v in kwargs.items(): setattr(self, k, v) @@ -135,7 +135,7 @@ def encode_string(self, encoding): return True def find_acceptable_charset(self): - """Find acceptable charset.""" + """Deduce acceptable charset for HTTP response.""" request = cherrypy.serving.request response = cherrypy.serving.response @@ -231,7 +231,7 @@ def find_acceptable_charset(self): raise cherrypy.HTTPError(406, msg) def __call__(self, *args, **kwargs): - """Call for ResponseEncoder.""" + """Set up encoding for the HTTP response.""" response = cherrypy.serving.response self.body = self.oldhandler(*args, **kwargs) @@ -343,7 +343,7 @@ def compress(body, compress_level): def decompress(body): - """Decompress.""" + """Decompress a blob of bytes.""" import gzip zbuf = io.BytesIO() From 342b01a74d31876855e8dcdbbdcfa3062e38c549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 21:27:17 +0200 Subject: [PATCH 28/69] Clarify docstrings in `cherrypy.lib.gctools` module --- cherrypy/lib/gctools.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cherrypy/lib/gctools.py b/cherrypy/lib/gctools.py index 5aaab7a6c..0e0149ebd 100644 --- a/cherrypy/lib/gctools.py +++ b/cherrypy/lib/gctools.py @@ -1,4 +1,4 @@ -"""GCtools.""" +"""Garbage collection inspection tooling.""" import gc import inspect import sys @@ -20,7 +20,7 @@ class ReferrerTree(object): peek_length = 40 def __init__(self, ignore=None, maxdepth=2, maxparents=10): - """Initialize ReferrerTree.""" + """Initialize a referrer tree structure.""" self.ignore = ignore or [] self.ignore.append(inspect.currentframe().f_back) self.maxdepth = maxdepth @@ -106,18 +106,18 @@ def get_instances(cls): class RequestCounter(SimplePlugin): - """RequestCounter class.""" + """An HTTP request counter plugin.""" def start(self): - """Start request counter.""" + """Initialize the internal counter.""" self.count = 0 def before_request(self): - """Run before request.""" + """Increment the counter before HTTP request.""" self.count += 1 def after_request(self): - """Run after request.""" + """Decrement the counter after HTTP request.""" self.count -= 1 @@ -126,7 +126,7 @@ def after_request(self): def get_context(obj): - """Get context.""" + """Compute object's runtime context information.""" if isinstance(obj, _cprequest.Request): return 'path=%s;stage=%s' % (obj.path_info, obj.stage) elif isinstance(obj, _cprequest.Response): @@ -152,12 +152,12 @@ class GCRoot(object): @cherrypy.expose def index(self): - """Handle index route.""" + """Render the index page HTML content.""" return 'Hello, world!' @cherrypy.expose def stats(self): - """Handle stats route.""" + """Render garbage collection statistics page HTML content.""" output = ['Statistics:'] for trial in range(10): From 25a1bef1348d4acc8f377b5a8a6c360e3f5889a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 23:11:54 +0200 Subject: [PATCH 29/69] Clarify docstrings in `cherrypy.lib.httputil` module --- cherrypy/lib/httputil.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/cherrypy/lib/httputil.py b/cherrypy/lib/httputil.py index 64a60f256..204eb488e 100644 --- a/cherrypy/lib/httputil.py +++ b/cherrypy/lib/httputil.py @@ -129,31 +129,31 @@ class HeaderElement(object): """An element (with parameters) from an HTTP header's element list.""" def __init__(self, value, params=None): - """Initialize HeaderElement.""" + """Initialize an HTTP header value representation.""" self.value = value if params is None: params = {} self.params = params def __cmp__(self, other): - """Compare values.""" + """Compare current HTTP header to another by value only.""" return builtins.cmp(self.value, other.value) def __lt__(self, other): - """Less-Than values.""" + """Check if this header value is less than the other.""" return self.value < other.value def __str__(self): - """Stringify HeaderElement.""" + """Render the HTTP header value as a string.""" p = [';%s=%s' % (k, v) for k, v in self.params.items()] return str('%s%s' % (self.value, ''.join(p))) def __bytes__(self): - """Bytesify HeaderElement.""" + """Turn the HTTP header value string representation to bytes.""" return ntob(self.__str__()) def __unicode__(self): - """Unicodeify HeaderElement.""" + """Render the HTTP header value as a string.""" return ntou(self.__str__()) @staticmethod @@ -185,7 +185,7 @@ class AcceptElement(HeaderElement): @classmethod def from_str(cls, elementstr): - """Initialize AcceptElement from string.""" + """Make an :class:`AcceptElement` instance from a string.""" qvalue = None # The first "q" parameter (if any) separates the initial # media-range parameter(s) (if any) from the accept-params. @@ -221,14 +221,17 @@ def qvalue(self): ) from val_err def __cmp__(self, other): - """Compare qvalues.""" + """Compare current header to another by qvalues then strings.""" diff = builtins.cmp(self.qvalue, other.qvalue) if diff == 0: diff = builtins.cmp(str(self), str(other)) return diff def __lt__(self, other): - """Less-Than qvalues.""" + """Check if this header qvalue is less than the other. + + This method uses string comparison as the second factor. + """ if self.qvalue == other.qvalue: return str(self) < str(other) else: @@ -239,7 +242,7 @@ def __lt__(self, other): def header_elements(fieldname, fieldvalue): - """Return sorted HeaderElement list. + """Return a sorted :class:`HeaderElement` list. Constucted from a comma-separated header string. """ @@ -399,7 +402,7 @@ class CaseInsensitiveDict(jaraco.collections.KeyTransformingDict): @staticmethod def transform_key(key): - """Transform key to title.""" + """Title-case an HTTP header name.""" if key is None: # TODO(#1830): why? return 'None' @@ -453,7 +456,7 @@ def output(self): @classmethod def encode_header_items(cls, header_items): - """Encode Header Items. + """Emit tuples of wire-ready HTTP headers. Prepare the sequence of name, value tuples into a form suitable for transmitting on the wire for HTTP. @@ -466,7 +469,7 @@ def encode_header_items(cls, header_items): @classmethod def encode_header_item(cls, item): - """Encode Header Item.""" + """Encode an HTTP header for sending over the wire.""" if isinstance(item, str): item = cls.encode(item) @@ -512,7 +515,7 @@ class Host(object): name = 'unknown.tld' def __init__(self, ip, port, name=None): - """Initialize Host.""" + """Initialize a TCP service representation.""" self.ip = ip self.port = port if name is None: @@ -520,12 +523,12 @@ def __init__(self, ip, port, name=None): self.name = name def __repr__(self): - """Represent Host object.""" + """Render a :class:`Host` instance representation.""" return 'httputil.Host(%r, %r, %r)' % (self.ip, self.port, self.name) class SanitizedHost(str): - r"""Sanitize host header. + r"""A normalized host header value. Wraps a raw host header received from the network in a sanitized version that elides dangerous characters. @@ -544,7 +547,7 @@ class SanitizedHost(str): dangerous = re.compile(r'[\n\r]') def __new__(cls, raw): - """Create new SanitizedHost.""" + """Construct a new :class:`SanitizedHost` instance.""" sanitized = cls._sanitize(raw) if sanitized == raw: return raw @@ -554,5 +557,5 @@ def __new__(cls, raw): @classmethod def _sanitize(cls, raw): - """Sanitize class data.""" + """Clean up the CR LF chars from input.""" return cls.dangerous.sub('', raw) From ae3e9df4ddd5c3288cb048a360c23c85e845725c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 23:20:14 +0200 Subject: [PATCH 30/69] Clarify docstrings in `cherrypy.lib.jsontools` module --- cherrypy/lib/jsontools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cherrypy/lib/jsontools.py b/cherrypy/lib/jsontools.py index 5e228e5e1..13685a9dc 100644 --- a/cherrypy/lib/jsontools.py +++ b/cherrypy/lib/jsontools.py @@ -1,4 +1,4 @@ -"""Json tools.""" +"""JSON tools.""" import cherrypy from cherrypy import _json as json from cherrypy._cpcompat import text_or_bytes, ntou @@ -58,7 +58,7 @@ def json_in(content_type=[ntou('application/json'), ntou('text/javascript')], def json_handler(*args, **kwargs): - """Handle JSON.""" + """Convert decorated HTTP handler-returned object to JSON string.""" value = cherrypy.serving.request._json_inner_handler(*args, **kwargs) return json.encode(value) From dde7887a3f6c71c1e1e308e1a19581d79f25dbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 30 Jun 2024 23:26:32 +0200 Subject: [PATCH 31/69] Clarify docstrings in `cherrypy.lib.locking` module --- cherrypy/lib/locking.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cherrypy/lib/locking.py b/cherrypy/lib/locking.py index a21ebd5a5..fb282f65d 100644 --- a/cherrypy/lib/locking.py +++ b/cherrypy/lib/locking.py @@ -1,12 +1,12 @@ -"""Locking module.""" +"""Lock acquisition helpers.""" import datetime class NeverExpires(object): - """NeverExpires class.""" + """A representation of a never expiring object.""" def expired(self): - """Expired check.""" + """Communicate that the object hasn't expired.""" return False @@ -25,7 +25,7 @@ def after(cls, elapsed): ) def expired(self): - """Expired check.""" + """Check whether the timer has expired.""" return datetime.datetime.now( datetime.timezone.utc, ) >= self.expiration @@ -39,7 +39,7 @@ class LockChecker(object): """Keep track of the time and detect if a timeout has expired.""" def __init__(self, session_id, timeout): - """Initialize LockChecker.""" + """Initialize a lock acquisition tracker.""" self.session_id = session_id if timeout: self.timer = Timer.after(timeout) @@ -47,7 +47,7 @@ def __init__(self, session_id, timeout): self.timer = NeverExpires() def expired(self): - """Expired check.""" + """Check whether the lock checker has expired.""" if self.timer.expired(): raise LockTimeout( 'Timeout acquiring lock for %(session_id)s' % vars(self)) From 4dabb1bdfedd17b09feb18a88a9d4b2e0a3e0169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 00:51:18 +0200 Subject: [PATCH 32/69] Clarify docstrings in `cherrypy._cprequest` module --- cherrypy/_cprequest.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cherrypy/_cprequest.py b/cherrypy/_cprequest.py index f4a2c7efd..14ad69311 100644 --- a/cherrypy/_cprequest.py +++ b/cherrypy/_cprequest.py @@ -56,14 +56,13 @@ def __init__(self, callback, failsafe=None, priority=None, **kwargs): self.kwargs = kwargs def __lt__(self, other): - """ - Less-Than Hook Operator. + """Check if this hook's priority is lower than the other's. - :param other: A Hook Object to compare priority with + :param other: Another object to compare priority with. :type other: Hook - :return: Other Hook's priority is higher than this one - :rtype: Bool + :returns: Whether the other Hook's priority is higher than this one's. + :rtype: bool Hooks sort by priority, ascending, such that hooks of lower priority are run first. From b616cc11ef4480ed1b3e2b23712b1730889e638e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 01:57:18 +0200 Subject: [PATCH 33/69] Clarify docstrings in `cherrypy.lib.profiler` module --- cherrypy/lib/profiler.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/cherrypy/lib/profiler.py b/cherrypy/lib/profiler.py index 2b7964582..86383ed45 100644 --- a/cherrypy/lib/profiler.py +++ b/cherrypy/lib/profiler.py @@ -69,10 +69,10 @@ def new_func_strip_path(func_name): class Profiler(object): - """Profiler class.""" + """A profiling app.""" def __init__(self, path=None): - """Initialize Profiler.""" + """Prepare the profiling app resources.""" if not path: path = os.path.join(os.path.dirname(__file__), 'profile') self.path = path @@ -90,17 +90,19 @@ def run(self, func, *args, **params): return result def statfiles(self): - """Statistics files. + """Compose a list of statistics file names. - :rtype: list of available profiles. + :returns: A list of available profiles. + :rtype: list[str] """ return [f for f in os.listdir(self.path) if f.startswith('cp_') and f.endswith('.prof')] def stats(self, filename, sortby='cumulative'): - """Generate statistics. + """Generate statistics from given profile. - :rtype stats(index): output of print_stats() for the given profile. + :returns: The sorted stats index printout. + :rtype: str """ sio = io.StringIO() if sys.version_info >= (2, 5): @@ -126,7 +128,7 @@ def stats(self, filename, sortby='cumulative'): @cherrypy.expose def index(self): - """Index page html content.""" + """Render the profiling viewer index page.""" return """ CherryPy profile data @@ -138,7 +140,7 @@ def index(self): @cherrypy.expose def menu(self): - """Menu page html content.""" + """Render the profiler menu page html layout.""" yield '

Profiling runs

' yield '

Click on one of the runs below to see profiling data.

' runs = self.statfiles() @@ -149,23 +151,23 @@ def menu(self): @cherrypy.expose def report(self, filename): - """Report statistics.""" + """Render a statistics report.""" cherrypy.response.headers['Content-Type'] = 'text/plain' return self.stats(filename) class ProfileAggregator(Profiler): - """ProfileAggregator class.""" + """A profiling aggregator app.""" def __init__(self, path=None): - """Initialize ProfileAggregator.""" + """Prepare the profiling aggregator app resources.""" Profiler.__init__(self, path) global _count self.count = _count = _count + 1 self.profiler = profile.Profile() def run(self, func, *args, **params): - """Run ProfileAggregator.""" + """Dump aggeregated profile data into ``self.path``.""" path = os.path.join(self.path, 'cp_%04d.prof' % self.count) result = self.profiler.runcall(func, *args, **params) self.profiler.dump_stats(path) @@ -173,7 +175,7 @@ def run(self, func, *args, **params): class make_app: - """Make app class.""" + """Profiling WSGI middleware wrapper.""" def __init__(self, nextapp, path=None, aggregate=False): """Make a WSGI middleware app which wraps 'nextapp' with profiling. @@ -207,7 +209,7 @@ def __init__(self, nextapp, path=None, aggregate=False): self.profiler = Profiler(path) def __call__(self, environ, start_response): - """Call make app.""" + """Process a WSGI request.""" def gather(): result = [] for line in self.nextapp(environ, start_response): @@ -217,7 +219,7 @@ def gather(): def serve(path=None, port=8080): - """Serve Profiler.""" + """Serve the web app with profiler activated.""" if profile is None or pstats is None: msg = ('Your installation of Python does not have a profile module. ' "If you're on Debian, try " From af4f8a52670f53496085a3be129e527785509821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 02:38:13 +0200 Subject: [PATCH 34/69] Clarify docstrings in `cherrypy.lib.reprconf` module --- cherrypy/lib/reprconf.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/cherrypy/lib/reprconf.py b/cherrypy/lib/reprconf.py index a050e2e5a..2f9b8e488 100644 --- a/cherrypy/lib/reprconf.py +++ b/cherrypy/lib/reprconf.py @@ -92,12 +92,12 @@ def __call__(self, config): handler(k, v) def __repr__(self): - """Represent NamespaceSet.""" + """Render representation of a :class:`NamespaceSet` instance.""" return '%s.%s(%s)' % (self.__module__, self.__class__.__name__, dict.__repr__(self)) def __copy__(self): - """Handle copy.""" + """Make a copy of this instance.""" newobj = self.__class__() newobj.update(self) return newobj @@ -115,7 +115,7 @@ class Config(dict): namespaces = NamespaceSet() def __init__(self, file=None, **kwargs): - """Initialize config.""" + """Initialize a CherryPy :class:`Config`.""" self.reset() if file is not None: self.update(file) @@ -144,24 +144,24 @@ def _apply(self, config): self.namespaces(config) def __setitem__(self, k, v): - """Handle set item.""" + """Assign a config setting.""" dict.__setitem__(self, k, v) self.namespaces({k: v}) class Parser(configparser.ConfigParser): - """A config parser. + """A parser for the INI-style config file. Sub-class of ConfigParser that keeps the case of options and that raises an exception if the file cannot be read. """ def optionxform(self, optionstr): - """Option X form.""" + """Keep the option names unedited.""" return optionstr def read(self, filenames): - """Handle read.""" + """Read the config from files on disk.""" if isinstance(filenames, text_or_bytes): filenames = [filenames] for filename in filenames: @@ -243,11 +243,9 @@ def build_Index(self, o): return self.build(o.value) def _build_call35(self, o): - """Workaround for python 3.5. - - _ast.Call signature, docs found here - https://greentreesnakes.readthedocs.org/en/latest/nodes.html - """ + """Emulate ``build_Call`` under Python 3.5.""" + # Workaround for python 3.5. _ast.Call signature, docs found at + # https://greentreesnakes.readthedocs.org/en/latest/nodes.html import ast callee = self.build(o.func) args = [] From b588aa5baece89b5c20a7450c65b37986eae01ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 03:09:39 +0200 Subject: [PATCH 35/69] Clarify docstrings in `cherrypy.lib.sessions` module --- cherrypy/lib/sessions.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/cherrypy/lib/sessions.py b/cherrypy/lib/sessions.py index 4a6070d84..feefc73a7 100644 --- a/cherrypy/lib/sessions.py +++ b/cherrypy/lib/sessions.py @@ -177,7 +177,7 @@ def id(self, value): # --------------------- Session management methods --------------------- # def __init__(self, id=None, **kwargs): - """Initialize Session.""" + """Initialize the session tool.""" self.id_observers = [] self._data = {} @@ -322,19 +322,19 @@ def delete(self): # -------------------- Application accessor methods -------------------- # def __getitem__(self, key): - """Get item from session.""" + """Retrieve a session-stored object.""" if not self.loaded: self.load() return self._data[key] def __setitem__(self, key, value): - """Set item in session.""" + """Store an object in the session.""" if not self.loaded: self.load() self._data[key] = value def __delitem__(self, key): - """Delete item from session.""" + """Delete object stored in the session.""" if not self.loaded: self.load() del self._data[key] @@ -353,13 +353,14 @@ def pop(self, key, default=missing): return self._data.pop(key, default) def __contains__(self, key): - """Test if session contains key.""" + """Check if the session has an object by key.""" if not self.loaded: self.load() return key in self._data def get(self, key, default=None): - """Get session key. + """Retrieve a session-stored object. + D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None. @@ -369,7 +370,7 @@ def get(self, key, default=None): return self._data.get(key, default) def update(self, d): - """Update session key. + """Update multiple session-stored objects in one go. D.update(E) -> None. Update D from E: for k in E: D[k] = E[k]. @@ -379,7 +380,7 @@ def update(self, d): self._data.update(d) def setdefault(self, key, default=None): - """Set default session value. + """Set a default session key value. D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D. """ @@ -388,7 +389,7 @@ def setdefault(self, key, default=None): return self._data.setdefault(key, default) def clear(self): - """Clear session. + """Clean up the session-stored data. D.clear() -> None. Remove all items from D. @@ -398,7 +399,7 @@ def clear(self): self._data.clear() def keys(self): - """Get list of session keys. + """Return an iterable of session keys. D.keys() -> list of D's keys. """ @@ -407,7 +408,7 @@ def keys(self): return self._data.keys() def items(self): - """Get list of items as tuples. + """Return an iterable of items as tuples. D.items() -> list of D's (key, value) pairs, as 2-tuples. """ @@ -416,7 +417,7 @@ def items(self): return self._data.items() def values(self): - """Get list of session values. + """Return an iterable of session objects. D.values() -> list of D's values. """ @@ -426,7 +427,7 @@ def values(self): class RamSession(Session): - """Handler for session in RAM.""" + """A memory-baked session store implementation.""" # Class-level objects. Don't rebind these! cache = {} @@ -486,7 +487,7 @@ def __len__(self): class FileSession(Session): - """Implementation of the File backend for sessions. + """Implementation of the file backend for sessions. storage_path The folder where session data will be saved. Each session @@ -504,7 +505,7 @@ class FileSession(Session): pickle_protocol = pickle.HIGHEST_PROTOCOL def __init__(self, id=None, **kwargs): - """Initialize FileSession.""" + """Prepare the file session store.""" # The 'storage_path' arg is required for file-based sessions. kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) kwargs.setdefault('lock_timeout', None) @@ -634,7 +635,7 @@ def __len__(self): class MemcachedSession(Session): - """Use Memcache as a session backend.""" + """A Memcached-baked session store.""" # The most popular memcached client for Python isn't thread-safe. # Wrap all .get and .set operations in a single lock. @@ -917,7 +918,7 @@ def set_response_cookie(path=None, path_header=None, name='session_id', def _add_MSIE_max_age_workaround(cookie, timeout): - """Add MSIE max age workaround. + """Inject a Microsoft Internet Explorer ``max-age`` workaround. We'd like to use the "max-age" param as indicated in http://www.faqs.org/rfcs/rfc2109.html but IE doesn't From c262c0e1ff0665dedca66a2ed4961ec2ccb7e3eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 04:14:50 +0200 Subject: [PATCH 36/69] Clarify docstrings in `cherrypy.process.plugins` module --- cherrypy/process/plugins.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/cherrypy/process/plugins.py b/cherrypy/process/plugins.py index 75b1062a9..53be2faa6 100644 --- a/cherrypy/process/plugins.py +++ b/cherrypy/process/plugins.py @@ -38,7 +38,7 @@ class SimplePlugin(object): """ def __init__(self, bus): - """Initialize SimplePlugin.""" + """Initialize a simple plugin.""" self.bus = bus def subscribe(self): @@ -94,7 +94,7 @@ class SignalHandler(object): del k, v def __init__(self, bus): - """Initialize SignalHandler.""" + """Initialize a signal handler plugin.""" self.bus = bus # Set default handlers self.handlers = {'SIGTERM': self.bus.exit, @@ -119,7 +119,7 @@ def _jython_SIGINT_handler(self, signum=None, frame=None): self.bus.exit() def _is_daemonized(self): - """Return boolean indicating if current process is running as a daemon. + """Check if current process is running as a daemon. The criteria to determine the `daemon` condition is to verify if the current pid is not the same as the one that got used on @@ -224,7 +224,7 @@ class DropPrivileges(SimplePlugin): """ def __init__(self, bus, umask=None, uid=None, gid=None): - """Initialize DropPrivileges.""" + """Initialize the privilege dropping plugin.""" SimplePlugin.__init__(self, bus) self.finalized = False self.uid = uid @@ -290,7 +290,7 @@ def umask(self, val): self._umask = val def start(self): - """Start DropPrivilages.""" + """Drop the process privileges.""" # uid/gid def current_ids(): """Return the current (uid, gid) if available.""" @@ -356,7 +356,7 @@ class Daemonizer(SimplePlugin): def __init__(self, bus, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): - """Initialize Daemonizer.""" + """Initialize the daemonizer plugin.""" SimplePlugin.__init__(self, bus) self.stdin = stdin self.stdout = stdout @@ -364,7 +364,7 @@ def __init__(self, bus, stdin='/dev/null', stdout='/dev/null', self.finalized = False def start(self): - """Start Daemonizer.""" + """Attempt to daemonize the process.""" if self.finalized: self.bus.log('Already deamonized.') @@ -387,7 +387,7 @@ def start(self): def daemonize( stdin='/dev/null', stdout='/dev/null', stderr='/dev/null', logger=lambda msg: None): - """Daemonize Daemonizer.""" + """Daemonize the process.""" # See http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 # (or http://www.faqs.org/faqs/unix-faq/programmer/faq/ section 1.7) # and http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012 @@ -434,13 +434,13 @@ class PIDFile(SimplePlugin): """Maintain a PID file via a WSPBus.""" def __init__(self, bus, pidfile): - """Initialize PIDFile.""" + """Initialize the PID file plugin.""" SimplePlugin.__init__(self, bus) self.pidfile = pidfile self.finalized = False def start(self): - """Start PIDFile.""" + """Write a PID file to disk.""" pid = os.getpid() if self.finalized: self.bus.log('PID %r already written to %r.' % (pid, self.pidfile)) @@ -452,7 +452,7 @@ def start(self): start.priority = 70 def exit(self): - """Exit PIDFile.""" + """Delete the PID file from disk.""" try: os.remove(self.pidfile) self.bus.log('PID file removed: %r.' % self.pidfile) @@ -476,7 +476,7 @@ def __init__(self, *args, **kwargs): super(PerpetualTimer, self).__init__(*args, **kwargs) def run(self): - """Run PerpetualTimer.""" + """Run an infinitely repeated callable.""" while True: self.finished.wait(self.interval) if self.finished.isSet(): @@ -504,7 +504,7 @@ class BackgroundTask(threading.Thread): """ def __init__(self, interval, function, args=[], kwargs={}, bus=None): - """Override parent constructor to assign provides properties.""" + """Initialize a background task parameters.""" super(BackgroundTask, self).__init__() self.interval = interval self.function = function @@ -517,11 +517,11 @@ def __init__(self, interval, function, args=[], kwargs={}, bus=None): self.daemon = True def cancel(self): - """Cancel BackgroundTask.""" + """Set a task cancellation flag.""" self.running = False def run(self): - """Run BackgroundTask.""" + """Start running the repeated background task in the loop.""" self.running = True while self.running: time.sleep(self.interval) @@ -552,7 +552,7 @@ class Monitor(SimplePlugin): """ def __init__(self, bus, callback, frequency=60, name=None): - """Initialize Monitor Plugin.""" + """Initialize the monitor plugin.""" SimplePlugin.__init__(self, bus) self.callback = callback self.frequency = frequency @@ -625,7 +625,7 @@ class Autoreloader(Monitor): """A regular expression by which to match filenames.""" def __init__(self, bus, frequency=1, match='.*'): - """Initialize Autoreloader Monitor Plugin.""" + """Initialize the auto-reloader monitor plugin.""" self.mtimes = {} self.files = set() self.match = match @@ -732,7 +732,7 @@ class ThreadManager(SimplePlugin): """A map of {thread ident: index number} pairs.""" def __init__(self, bus): - """Initialize ThreadManager Plugin.""" + """Initialize the thread manager plugin.""" self.threads = {} SimplePlugin.__init__(self, bus) self.bus.listeners.setdefault('acquire_thread', set()) From 18d8f713f0be0c03b87f9b51666bfa9f676bbb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 04:32:16 +0200 Subject: [PATCH 37/69] Clarify docstrings in `cherrypy.process.servers` module --- cherrypy/process/servers.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cherrypy/process/servers.py b/cherrypy/process/servers.py index 249ab1ad6..66444c46b 100644 --- a/cherrypy/process/servers.py +++ b/cherrypy/process/servers.py @@ -1,5 +1,5 @@ r""" -Server Objects. +Server interfaces. Starting in CherryPy 3.1, cherrypy.server is implemented as an :ref:`Engine Plugin`. It's an instance of @@ -129,7 +129,7 @@ def index(self): class Timeouts: - """Timeouts.""" + """Timeout constants.""" occupied = 5 free = 1 @@ -150,7 +150,7 @@ class ServerAdapter(object): """ def __init__(self, bus, httpserver=None, bind_addr=None): - """Initialize the HTTP server.""" + """Initialize the HTTP server plugin.""" self.bus = bus self.httpserver = httpserver self.bind_addr = bind_addr @@ -158,12 +158,12 @@ def __init__(self, bus, httpserver=None, bind_addr=None): self.running = False def subscribe(self): - """Subscribe the HTTP server.""" + """Subscribe control methods to the bus lifecycle events.""" self.bus.subscribe('start', self.start) self.bus.subscribe('stop', self.stop) def unsubscribe(self): - """Unsubcribe the HTTP server.""" + """Unsubcribe control methods to the bus lifecycle events.""" self.bus.unsubscribe('start', self.start) self.bus.unsubscribe('stop', self.stop) @@ -219,7 +219,7 @@ def _get_base(self): return '%s://%s' % (scheme, host) def _start_http_thread(self): - """Start Http Thread. + """Start the HTTP server thread. HTTP servers MUST be running in new threads, so that the main thread persists to receive KeyboardInterrupt's. If an @@ -267,10 +267,10 @@ def wait(self): @property def bound_addr(self): - """The bind Address. + """The bind address. - or if it's an ephemeral port and the - socket has been bound, return the actual port bound. + If it's an ephemeral port and the socket has been bound, + return the actual port bound. """ host, port = self.bind_addr if port == 0 and self.httpserver.socket: @@ -302,7 +302,7 @@ class FlupCGIServer(object): """Adapter for a flup.server.cgi.WSGIServer.""" def __init__(self, *args, **kwargs): - """Initialize Flup CGI Server.""" + """Initialize the flup CGI Server plugin.""" self.args = args self.kwargs = kwargs self.ready = False @@ -326,7 +326,7 @@ class FlupFCGIServer(object): """Adapter for a flup.server.fcgi.WSGIServer.""" def __init__(self, *args, **kwargs): - """Initialize Flup FCGI Server.""" + """Initialize the FCGI server parameters.""" if kwargs.get('bindAddress', None) is None: import socket if not hasattr(socket, 'fromfd'): @@ -372,7 +372,7 @@ class FlupSCGIServer(object): """Adapter for a flup.server.scgi.WSGIServer.""" def __init__(self, *args, **kwargs): - """Initialize Flup SCGI Server.""" + """Initialize the SCGI server parameters.""" self.args = args self.kwargs = kwargs self.ready = False From 9a9c74336f75d2a0695f1579520c99daa04ef1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 04:59:53 +0200 Subject: [PATCH 38/69] Clarify docstrings in `cherrypy.process.win32` module --- cherrypy/process/win32.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cherrypy/process/win32.py b/cherrypy/process/win32.py index cb56c9989..c089bbaa0 100644 --- a/cherrypy/process/win32.py +++ b/cherrypy/process/win32.py @@ -17,12 +17,12 @@ class ConsoleCtrlHandler(plugins.SimplePlugin): """A WSPBus plugin for handling Win32 console events (like Ctrl-C).""" def __init__(self, bus): - """Initialize ConsoleCtrlHandler.""" + """Initialize the console control handler.""" self.is_set = False plugins.SimplePlugin.__init__(self, bus) def start(self): - """Handle start.""" + """Register handling of the console control events.""" if self.is_set: self.bus.log('Handler for console events already set.', level=20) return @@ -36,7 +36,7 @@ def start(self): self.is_set = True def stop(self): - """Handle stop.""" + """Unregister the console control handlers.""" if not self.is_set: self.bus.log('Handler for console events already off.', level=20) return @@ -81,7 +81,7 @@ class Win32Bus(wspbus.Bus): """ def __init__(self): - """Initialize Win32Bus.""" + """Initialize a Win32 bus implementation.""" self.events = {} wspbus.Bus.__init__(self) @@ -98,12 +98,12 @@ def _get_state_event(self, state): @property def state(self): - """Handle state.""" + """The bus state.""" return self._state @state.setter def state(self, value): - """Handle set state.""" + """Set the bus state.""" self._state = value event = self._get_state_event(value) win32event.PulseEvent(event) @@ -150,7 +150,7 @@ def key_for(self, obj): def signal_child(service, command): - """Handle signal child.""" + """Send a control command to a service.""" if command == 'stop': win32serviceutil.StopService(service) elif command == 'restart': @@ -172,19 +172,19 @@ class PyWebService(win32serviceutil.ServiceFramework): _svc_description_ = 'Python Web Service' def SvcDoRun(self): - """Handle run.""" + """Start the service.""" from cherrypy import process process.bus.start() process.bus.block() def SvcStop(self): - """Handle stop.""" + """Stop the service.""" from cherrypy import process self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) process.bus.exit() def SvcOther(self, control): - """Handle other.""" + """Send a command to the service.""" from cherrypy import process process.bus.publish(control_codes.key_for(control)) From 7ec3fd777d87a438adf6bbef89f254e11c62e8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 05:07:48 +0200 Subject: [PATCH 39/69] Clarify docstrings in `cherrypy.test` package --- cherrypy/test/__init__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cherrypy/test/__init__.py b/cherrypy/test/__init__.py index a2ce3d845..4da7a7d8a 100644 --- a/cherrypy/test/__init__.py +++ b/cherrypy/test/__init__.py @@ -5,22 +5,20 @@ def newexit(): - """Handle Exit.""" + """Exit the process with return code of 1.""" os._exit(1) def setup(): - """Handle Setup. - - We want to monkey patch sys.exit so that we can get some - information about where exit is being called. - """ + """Monkey-patch ``sys.exit()``. + # We want to monkey patch sys.exit so that we can get some + # information about where exit is being called. newexit._old = sys.exit sys.exit = newexit def teardown(): - """Handle Teardown.""" + """Recover the original ``sys.exit()``.""" try: sys.exit = sys.exit._old except AttributeError: From c0d3e287aea23af1f30d4386531cb94fbe9141b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 05:08:59 +0200 Subject: [PATCH 40/69] fixup! cherrypy/test/__init__.py --- cherrypy/test/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/test/__init__.py b/cherrypy/test/__init__.py index 4da7a7d8a..05bb17ad7 100644 --- a/cherrypy/test/__init__.py +++ b/cherrypy/test/__init__.py @@ -10,7 +10,7 @@ def newexit(): def setup(): - """Monkey-patch ``sys.exit()``. + """Monkey-patch ``sys.exit()``.""" # We want to monkey patch sys.exit so that we can get some # information about where exit is being called. newexit._old = sys.exit From b68ca43da2a28a6a7587c3887ea99e006f15d818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 05:12:32 +0200 Subject: [PATCH 41/69] fixup! cherrypy/lib/sessions.py --- cherrypy/lib/sessions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cherrypy/lib/sessions.py b/cherrypy/lib/sessions.py index feefc73a7..f0d2678b4 100644 --- a/cherrypy/lib/sessions.py +++ b/cherrypy/lib/sessions.py @@ -361,7 +361,6 @@ def __contains__(self, key): def get(self, key, default=None): """Retrieve a session-stored object. - D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None. """ From 1285fa430ed8d39a3f3fcf7d54ab100311ab3d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 14:34:59 +0200 Subject: [PATCH 42/69] Clarify docstrings in `cherrypy.tutorial` package --- cherrypy/tutorial/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/tutorial/__init__.py b/cherrypy/tutorial/__init__.py index 5b81780e9..d6b560567 100644 --- a/cherrypy/tutorial/__init__.py +++ b/cherrypy/tutorial/__init__.py @@ -1,3 +1,3 @@ -"""Initialization file for tutorial module.""" +"""A package with standalone tutorial modules.""" # This is used in test_config to test unrepr of "from A import B" thing2 = object() From 5a128619c3d4be0b19d42ac75cd1fc97bcd009e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 20:03:46 +0200 Subject: [PATCH 43/69] Clarify docstrings in `cherrypy.test.webtest` module --- cherrypy/test/webtest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cherrypy/test/webtest.py b/cherrypy/test/webtest.py index cf4d10bdd..dba74a489 100644 --- a/cherrypy/test/webtest.py +++ b/cherrypy/test/webtest.py @@ -1,4 +1,5 @@ -"""For compatibility, expose cheroot webtest here.""" +"""A deprecated web app testing helper interface.""" +# for compatibility, expose cheroot webtest import warnings from cheroot.test.webtest import ( # noqa From bab89741dce8d9a65f8969688df4f6560011b636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 20:04:22 +0200 Subject: [PATCH 44/69] fixup! cherrypy/test/webtest.py --- cherrypy/test/webtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/test/webtest.py b/cherrypy/test/webtest.py index dba74a489..f579bc4cd 100644 --- a/cherrypy/test/webtest.py +++ b/cherrypy/test/webtest.py @@ -1,5 +1,5 @@ """A deprecated web app testing helper interface.""" -# for compatibility, expose cheroot webtest +# for compatibility, expose cheroot webtest here import warnings from cheroot.test.webtest import ( # noqa From d0c0d6d5eef63735b03ffd05ba92357de3e09209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 20:05:21 +0200 Subject: [PATCH 45/69] Clarify docstrings in `cherrypy.tutorial.tut01_helloworld` module --- cherrypy/tutorial/tut01_helloworld.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherrypy/tutorial/tut01_helloworld.py b/cherrypy/tutorial/tut01_helloworld.py index 4e33968db..5cdde927c 100644 --- a/cherrypy/tutorial/tut01_helloworld.py +++ b/cherrypy/tutorial/tut01_helloworld.py @@ -17,7 +17,7 @@ class HelloWorld: # publish methods that don't have the exposed attribute set to True. @cherrypy.expose def index(self): - """Handle index.""" + """Produce HTTP response body of hello world app index URI.""" # CherryPy will call this method for the root URI ("/") and send # its return value to the client. Because this is tutorial # lesson number 01, we'll just send something really simple. From cca041021b66e2659aad41fdb0fe5daf3cb5cf22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 23:15:04 +0200 Subject: [PATCH 46/69] Clarify docstrings in `cherrypy.tutorial.tut03_get_and_post` module --- cherrypy/tutorial/tut03_get_and_post.py | 28 ++++++++++--------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/cherrypy/tutorial/tut03_get_and_post.py b/cherrypy/tutorial/tut03_get_and_post.py index 4c38312b5..3a50a5847 100644 --- a/cherrypy/tutorial/tut03_get_and_post.py +++ b/cherrypy/tutorial/tut03_get_and_post.py @@ -10,15 +10,12 @@ class WelcomePage: - """WelcomePage Class for Tutorial 03.""" + """Welcome page app.""" @cherrypy.expose def index(self): - """ - Index WelcomePage. - - Ask for the user's name. - """ + """Produce HTTP response body of welcome app index URI.""" + # Ask for the user's name. return ''' What is your name? @@ -28,17 +25,14 @@ def index(self): @cherrypy.expose def greetUser(self, name=None): - """ - Greet User WelcomePage. - - CherryPy passes all GET and POST variables as method parameters. - It doesn't make a difference where the variables come from, how - large their contents are, and so on. - - You can define default parameter values as usual. In this - example, the "name" parameter defaults to None so we can check - if a name was actually specified. - """ + """Render a greeting or form on ``/greetUser`` URI.""" + # CherryPy passes all GET and POST variables as method parameters. + # It doesn't make a difference where the variables come from, how + # large their contents are, and so on. + # + # You can define default parameter values as usual. In this + # example, the "name" parameter defaults to None so we can check + # if a name was actually specified. if name: # Greet the user! return "Hey %s, what's up?" % name From c0cff1773cfe062ab9ef2dc47a64656fe967ccfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 23:17:50 +0200 Subject: [PATCH 47/69] Clarify docstrings in `cherrypy.tutorial.tut02_expose_methods` module --- cherrypy/tutorial/tut02_expose_methods.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/cherrypy/tutorial/tut02_expose_methods.py b/cherrypy/tutorial/tut02_expose_methods.py index 14a7107a8..52823dfb5 100644 --- a/cherrypy/tutorial/tut02_expose_methods.py +++ b/cherrypy/tutorial/tut02_expose_methods.py @@ -11,24 +11,17 @@ class HelloWorld: - """HelloWorld class for tutorial.""" + """Hello world app.""" @cherrypy.expose def index(self): - """ - Index HelloWorld. - - Let's link to another method here. - """ + """Produce HTTP response body of hello world app index URI.""" + # Let's link to another method here. return 'We have an important message for you!' @cherrypy.expose def show_msg(self): - """ - Show_msg HelloWorld. - - Here's the important message! - """ + """Render a "Hello world!" message on ``/show_msg`` URI.""" return 'Hello world!' From 4244c617459b2421d4f159a7c2902ffcfe7650a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 23:34:34 +0200 Subject: [PATCH 48/69] Clarify docstrings in `cherrypy.tutorial.tut04_complex_site` module --- cherrypy/tutorial/tut04_complex_site.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cherrypy/tutorial/tut04_complex_site.py b/cherrypy/tutorial/tut04_complex_site.py index 51cf2ce79..ddba6d9ad 100644 --- a/cherrypy/tutorial/tut04_complex_site.py +++ b/cherrypy/tutorial/tut04_complex_site.py @@ -11,11 +11,11 @@ class HomePage: - """HomePage class.""" + """Home page app.""" @cherrypy.expose def index(self): - """Handle index for HomePage.""" + """Produce HTTP response body of home page app index URI.""" return '''

Hi, this is the home page! Check out the other fun stuff on this site:

@@ -27,11 +27,11 @@ def index(self): class JokePage: - """JokePage class.""" + """Joke app.""" @cherrypy.expose def index(self): - """Handle index for JokePage.""" + """Produce HTTP response body of joke page app index URI.""" return '''

"In Python, how do you create a string of random characters?" -- "Read a Perl file!"

@@ -39,10 +39,10 @@ def index(self): class LinksPage: - """LinksPage class.""" + """Links page app.""" def __init__(self): - """Initialize LinksPage.""" + """Mount extra links page into the links page app.""" # Request handler objects can create their own nested request # handler objects. Simply create them inside their __init__ # methods! @@ -50,7 +50,7 @@ def __init__(self): @cherrypy.expose def index(self): - """Handle index for LinksPage.""" + """Produce HTTP response body of links page app index URI.""" # Note the way we link to the extra links page (and back). # As you can see, this object doesn't really care about its # absolute position in the site tree, since we use relative @@ -75,11 +75,11 @@ def index(self): class ExtraLinksPage: - """ExtraLinksPage class.""" + """Extra links app.""" @cherrypy.expose def index(self): - """Handle index for ExtraLinksPage.""" + """Render extra useful links.""" # Note the relative link back to the Links page! return '''

Here are some extra useful links:

From 4dfd6f9387dc5be0423da5bd215b030cf5e088a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 1 Jul 2024 23:47:43 +0200 Subject: [PATCH 49/69] Clarify docstrings in `cherrypy.tutorial.tut05_derived_objects` module --- cherrypy/tutorial/tut05_derived_objects.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cherrypy/tutorial/tut05_derived_objects.py b/cherrypy/tutorial/tut05_derived_objects.py index aafaa6d7d..7c9e8d288 100644 --- a/cherrypy/tutorial/tut05_derived_objects.py +++ b/cherrypy/tutorial/tut05_derived_objects.py @@ -13,13 +13,13 @@ class you wish. In most real-world applications, you will probably class Page: - """Page base route handler.""" + """Web page base class.""" # Store the page title in a class attribute title = 'Untitled Page' def header(self): - """Header html content.""" + """Render HTML layout header.""" return ''' @@ -30,7 +30,7 @@ def header(self): ''' % (self.title, self.title) def footer(self): - """Footer html content.""" + """Render HTML layout footer.""" return ''' @@ -44,19 +44,19 @@ def footer(self): class HomePage(Page): - """HomePage route handler.""" + """Home page app.""" # Different title for this page title = 'Tutorial 5' def __init__(self): - """Initialize HomePage.""" + """Mount another page into the home page app.""" # create a subpage self.another = AnotherPage() @cherrypy.expose def index(self): - """Handle index.""" + """Produce HTTP response body of home page app index URI.""" # Note that we call the header and footer methods inherited # from the Page class! return self.header() + ''' @@ -68,13 +68,13 @@ def index(self): class AnotherPage(Page): - """AnotherPage route handler.""" + """Another page app.""" title = 'Another Page' @cherrypy.expose def index(self): - """Handle index.""" + """Produce HTTP response body of another page app index URI.""" return self.header() + '''

And this is the amazing second page! From 7deb828eda09ead6c932003faf26cd18687120c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 00:00:32 +0200 Subject: [PATCH 50/69] Clarify docstrings in `cherrypy.tutorial.tut06_default_method` module --- cherrypy/tutorial/tut06_default_method.py | 24 ++++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/cherrypy/tutorial/tut06_default_method.py b/cherrypy/tutorial/tut06_default_method.py index bd12e4356..8a07a90e8 100644 --- a/cherrypy/tutorial/tut06_default_method.py +++ b/cherrypy/tutorial/tut06_default_method.py @@ -22,16 +22,14 @@ class UsersPage: - """The UsersPage Class for Tutorial 06.""" + """The users app.""" @cherrypy.expose def index(self): - """Index for UsersPage. - - Since this is just a stupid little example, we'll simply - display a list of links to random, made-up users. In a real - application, this could be generated from a database result set. - """ + """Produce HTTP response body of the users app index URI.""" + # Since this is just a stupid little example, we'll simply + # display a list of links to random, made-up users. In a real + # application, this could be generated from a database result set. return ''' Remi Delon
Hendrik Mans
@@ -40,13 +38,11 @@ def index(self): @cherrypy.expose def default(self, user): - """Handle Default for UsersPage. - - Here we react depending on the virtualPath -- the part of the - path that could not be mapped to an object method. In a real - application, we would probably do some database lookups here - instead of the silly if/elif/else construct. - """ + """Produce HTTP response body of the users app fallback URI.""" + # Here we react depending on the virtualPath -- the part of the + # path that could not be mapped to an object method. In a real + # application, we would probably do some database lookups here + # instead of the silly if/elif/else construct. if user == 'remi': out = 'Remi Delon, CherryPy lead developer' elif user == 'hendrik': From 3a20d167b98231fe36e1a945188cfe85785f10a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 00:02:56 +0200 Subject: [PATCH 51/69] Clarify docstrings in `cherrypy.tutorial.tut07_sessions` module --- cherrypy/tutorial/tut07_sessions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cherrypy/tutorial/tut07_sessions.py b/cherrypy/tutorial/tut07_sessions.py index 6dfd0b493..210439904 100644 --- a/cherrypy/tutorial/tut07_sessions.py +++ b/cherrypy/tutorial/tut07_sessions.py @@ -14,13 +14,13 @@ class HitCounter: - """HitCounter Class.""" + """Hit counter app.""" _cp_config = {'tools.sessions.on': True} @cherrypy.expose def index(self): - """Index route hander.""" + """Produce HTTP response body of hit counter app index URI.""" # Increase the silly hit counter count = cherrypy.session.get('count', 0) + 1 From e1bf5b898dbf4187e9a4807385982971272367cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 01:06:44 +0200 Subject: [PATCH 52/69] Clarify docstrings in `cherrypy.tutorial.tut08_generators_and_yield` module --- cherrypy/tutorial/tut08_generators_and_yield.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cherrypy/tutorial/tut08_generators_and_yield.py b/cherrypy/tutorial/tut08_generators_and_yield.py index 81a6dae14..4e5500916 100644 --- a/cherrypy/tutorial/tut08_generators_and_yield.py +++ b/cherrypy/tutorial/tut08_generators_and_yield.py @@ -13,19 +13,19 @@ class GeneratorDemo: - """GeneratorDemo class.""" + """HTTP response streaming app.""" def header(self): - """Header html content.""" + """Render HTML layout header.""" return '

Generators rule!

' def footer(self): - """Footer html content.""" + """Render HTML layout footer.""" return '' @cherrypy.expose def index(self): - """Return index html content.""" + """Stream HTTP response body of generator app index URI.""" # Let's make up a list of users for presentation purposes users = ['Remi', 'Carlos', 'Hendrik', 'Lorenzo Lamas'] From 9305612ad49b42d8d603c71785bbb56b646dbb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 01:09:13 +0200 Subject: [PATCH 53/69] Clarify docstrings in `cherrypy.tutorial.tut09_files` module --- cherrypy/tutorial/tut09_files.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cherrypy/tutorial/tut09_files.py b/cherrypy/tutorial/tut09_files.py index 740f9f3ae..23bca6a59 100644 --- a/cherrypy/tutorial/tut09_files.py +++ b/cherrypy/tutorial/tut09_files.py @@ -50,11 +50,11 @@ class FileDemo(object): - """FileDemo request handler.""" + """File upload app.""" @cherrypy.expose def index(self): - """Handle index route.""" + """Produce HTTP response body of file upload app index URI.""" return """

Upload a file

@@ -69,7 +69,7 @@ def index(self): @cherrypy.expose def upload(self, myFile): - """Handle upload route.""" + """Receive a file upload at ``/upload`` URI.""" out = """ myFile length: %s
@@ -93,7 +93,7 @@ def upload(self, myFile): @cherrypy.expose def download(self): - """Handle download route.""" + """Send file to the HTTP client accessing ``/download`` URI.""" path = os.path.join(absDir, 'pdf_file.pdf') return static.serve_file(path, 'application/x-download', 'attachment', os.path.basename(path)) From 6f9436db9c2dfc6c0357d7c9b89368cca219194d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 01:32:56 +0200 Subject: [PATCH 54/69] Clarify docstrings in `cherrypy.tutorial.tut10_http_errors` module --- cherrypy/tutorial/tut10_http_errors.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cherrypy/tutorial/tut10_http_errors.py b/cherrypy/tutorial/tut10_http_errors.py index 982b24307..f982df627 100644 --- a/cherrypy/tutorial/tut10_http_errors.py +++ b/cherrypy/tutorial/tut10_http_errors.py @@ -16,7 +16,7 @@ class HTTPErrorDemo(object): - """HTTPErrorDemo request handler.""" + """HTTP error representation app.""" # Set a custom response for 403 errors. _cp_config = {'error_page.403': @@ -24,7 +24,7 @@ class HTTPErrorDemo(object): @cherrypy.expose def index(self): - """Handle index route.""" + """Produce HTTP response body of error display app index URI.""" # display some links that will result in errors tracebacks = cherrypy.request.show_tracebacks if tracebacks: @@ -55,7 +55,7 @@ def index(self): @cherrypy.expose def toggleTracebacks(self): - """Handle toggleTracebacks route.""" + """Switch tracebacks setting on ``/toggleTracebacks`` URI.""" # simple function to toggle tracebacks on and off tracebacks = cherrypy.request.show_tracebacks cherrypy.config.update({'request.show_tracebacks': not tracebacks}) @@ -65,13 +65,13 @@ def toggleTracebacks(self): @cherrypy.expose def error(self, code): - """Handle error route.""" + """Respond with a given HTTP error.""" # raise an error based on the get query raise cherrypy.HTTPError(status=code) @cherrypy.expose def messageArg(self): - """Handle messageArg route.""" + """Respond with an HTTP 500 and a custom message.""" message = ("If you construct an HTTPError with a 'message' " 'argument, it wil be placed on the error page ' '(underneath the status line by default).') From 2da3f53dc7f1f1b39aa0db33f200e1143a496bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 01:39:08 +0200 Subject: [PATCH 55/69] Clarify docstrings in `cherrypy.test.modwsgi` module --- cherrypy/test/modwsgi.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cherrypy/test/modwsgi.py b/cherrypy/test/modwsgi.py index 2a8fb1745..1e074e63b 100644 --- a/cherrypy/test/modwsgi.py +++ b/cherrypy/test/modwsgi.py @@ -48,7 +48,7 @@ def read_process(cmd, args=''): - """Read Process of supplied command.""" + """Return subprocess' console output.""" pipein, pipeout = os.popen4('%s %s' % (cmd, args)) try: firstline = pipeout.readline() @@ -102,11 +102,11 @@ class ModWSGISupervisor(helper.Supervisor): template = conf_modwsgi def __str__(self): - """Represent ModWSGISupervisor as a string.""" + """Render a :class:`ModWSGISupervisor` instance as a string.""" return 'ModWSGI Server on %s:%s' % (self.host, self.port) def start(self, modulename): - """Start Mod WSGI Supervisor.""" + """Spawn an Apache ``mod_wsgi`` supervisor process.""" mpconf = CONF_PATH if not os.path.isabs(mpconf): mpconf = os.path.join(curdir, mpconf) @@ -136,7 +136,7 @@ def stop(self): def application(environ, start_response): - """Application to load test mod.""" + """Respond to a WSGI-interfaced HTTP request via test module.""" global loaded if not loaded: loaded = True From 0242ec400f845a95c41db3bdc91fc8146f0493ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 01:43:27 +0200 Subject: [PATCH 56/69] Clarify docstrings in `cherrypy.test.sessiondemo` module --- cherrypy/test/sessiondemo.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cherrypy/test/sessiondemo.py b/cherrypy/test/sessiondemo.py index 14901e041..989e23a56 100755 --- a/cherrypy/test/sessiondemo.py +++ b/cherrypy/test/sessiondemo.py @@ -98,10 +98,10 @@ class Root(object): - """Root request handler.""" + """Session demo app.""" def page(self): - """Handle page route.""" + """Render HTTP request-related details.""" changemsg = [] if cherrypy.session.id != cherrypy.session.originalid: if cherrypy.session.originalid is None: @@ -139,20 +139,20 @@ def page(self): @cherrypy.expose def index(self): - """Handle index route.""" + """Save green color in session at app index URI.""" # Must modify data or the session will not be saved. cherrypy.session['color'] = 'green' return self.page() @cherrypy.expose def expire(self): - """Handle expire route.""" + """Expire the existing session.""" sessions.expire() return self.page() @cherrypy.expose def regen(self): - """Handle regen route.""" + """Regenerate the session, storing yellow color in it.""" cherrypy.session.regenerate() # Must modify data or the session will not be saved. cherrypy.session['color'] = 'yellow' From c4f39060e3ea4876418433cb3d5a6e4bee01d5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 02:19:14 +0200 Subject: [PATCH 57/69] Clarify docstrings in `cherrypy.test.modpy` module --- cherrypy/test/modpy.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cherrypy/test/modpy.py b/cherrypy/test/modpy.py index 50cbc6d00..c9b3062b0 100644 --- a/cherrypy/test/modpy.py +++ b/cherrypy/test/modpy.py @@ -44,7 +44,7 @@ def read_process(cmd, args=''): - """Handle read process.""" + """Return subprocess' console output.""" pipein, pipeout = os.popen4('%s %s' % (cmd, args)) try: firstline = pipeout.readline() @@ -95,18 +95,18 @@ def read_process(cmd, args=''): class ModPythonSupervisor(helper.Supervisor): - """ModPythonSupervisor class.""" + """Server Controller for ModPython and CherryPy.""" using_apache = True using_wsgi = False template = None def __str__(self): - """Retusn string representation of ModPythonSupervisor.""" + """Render a :class:`ModPythonSupervisor` instance as a string.""" return 'ModPython Server on %s:%s' % (self.host, self.port) def start(self, modulename): - """Handle start.""" + """Spawn an Apache ``mod_python`` supervisor process.""" mpconf = CONF_PATH if not os.path.isabs(mpconf): mpconf = os.path.join(curdir, mpconf) @@ -129,7 +129,7 @@ def stop(self): def wsgisetup(req): - """Handle WGSI setup.""" + """Start a WGSI server.""" global loaded if not loaded: loaded = True @@ -152,7 +152,7 @@ def wsgisetup(req): def cpmodpysetup(req): - """Handle CP Mod Python setup.""" + """Start a CherryPy server with ``mod_python``.""" global loaded if not loaded: loaded = True From 8a7d37d61d5da5a370daf9ae4239bbaecdd62ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 02:29:33 +0200 Subject: [PATCH 58/69] Clarify docstrings in `cherrypy.test.modfcgid` module --- cherrypy/test/modfcgid.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cherrypy/test/modfcgid.py b/cherrypy/test/modfcgid.py index 5f6867222..5a4a3a8f1 100644 --- a/cherrypy/test/modfcgid.py +++ b/cherrypy/test/modfcgid.py @@ -45,7 +45,7 @@ def read_process(cmd, args=''): - """Handle read process.""" + """Return subprocess' console output.""" pipein, pipeout = os.popen4('%s %s' % (cmd, args)) try: firstline = pipeout.readline() @@ -79,18 +79,18 @@ def read_process(cmd, args=''): class ModFCGISupervisor(helper.LocalSupervisor): - """ModFCGISupervisor class.""" + """Server Controller for ModFCGI and CherryPy.""" using_apache = True using_wsgi = True template = conf_fcgid def __str__(self): - """Return string representation of ModFCGISupervisor.""" + """Render a :class:`ModFCGISupervisor` instance as a string.""" return 'FCGI Server on %s:%s' % (self.host, self.port) def start(self, modulename): - """Handle start.""" + """Spawn an Apache ``mod_fcgid`` supervisor process.""" cherrypy.server.httpserver = servers.FlupFCGIServer( application=cherrypy.tree, bindAddress=('127.0.0.1', 4000)) cherrypy.server.httpserver.bind_addr = ('127.0.0.1', 4000) @@ -100,7 +100,7 @@ def start(self, modulename): helper.LocalServer.start(self, modulename) def start_apache(self): - """Handle start Apache.""" + """Start Apache instance.""" fcgiconf = CONF_PATH if not os.path.isabs(fcgiconf): fcgiconf = os.path.join(curdir, fcgiconf) @@ -123,5 +123,5 @@ def stop(self): helper.LocalServer.stop(self) def sync_apps(self): - """Handle sync apps.""" + """Set up the FCGID request handler.""" cherrypy.server.httpserver.fcgiserver.application = self.get_app() From d90ca1d13947224c0c6595039db088831e9e9661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 02:38:16 +0200 Subject: [PATCH 59/69] Clarify docstrings in `cherrypy.test.modfastcgi` module --- cherrypy/test/modfastcgi.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cherrypy/test/modfastcgi.py b/cherrypy/test/modfastcgi.py index aae515a68..8c20605fb 100644 --- a/cherrypy/test/modfastcgi.py +++ b/cherrypy/test/modfastcgi.py @@ -44,7 +44,7 @@ def read_process(cmd, args=''): - """Handle read process.""" + """Return subprocess' console output.""" pipein, pipeout = os.popen4('%s %s' % (cmd, args)) try: firstline = pipeout.readline() @@ -82,13 +82,13 @@ def read_process(cmd, args=''): def erase_script_name(environ, start_response): - """Erase script name.""" + """Erase script name from the WSGI environment.""" environ['SCRIPT_NAME'] = '' return cherrypy.tree(environ, start_response) class ModFCGISupervisor(helper.LocalWSGISupervisor): - """ModFCGISupervisor class.""" + """Server Controller for ModFastCGI and CherryPy.""" httpserver_class = 'cherrypy.process.servers.FlupFCGIServer' using_apache = True @@ -96,11 +96,11 @@ class ModFCGISupervisor(helper.LocalWSGISupervisor): template = conf_fastcgi def __str__(self): - """Return string representaion of ModFCGISupervisor.""" + """Render a :class:`ModFastCGISupervisor` instance as a string.""" return 'FCGI Server on %s:%s' % (self.host, self.port) def start(self, modulename): - """Handle start.""" + """Spawn an Apache ``mod_fastcgi`` supervisor process.""" cherrypy.server.httpserver = servers.FlupFCGIServer( application=erase_script_name, bindAddress=('127.0.0.1', 4000)) cherrypy.server.httpserver.bind_addr = ('127.0.0.1', 4000) @@ -112,7 +112,7 @@ def start(self, modulename): self.sync_apps() def start_apache(self): - """Handle start Apache.""" + """Start Apache instance.""" fcgiconf = CONF_PATH if not os.path.isabs(fcgiconf): fcgiconf = os.path.join(curdir, fcgiconf) @@ -135,6 +135,6 @@ def stop(self): helper.LocalWSGISupervisor.stop(self) def sync_apps(self): - """Handle sync apps.""" + """Set up the FastCGI request handler.""" cherrypy.server.httpserver.fcgiserver.application = self.get_app( erase_script_name) From 43b172ce34184514aa2b72f0ac0dd0d2709f59c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 02:41:52 +0200 Subject: [PATCH 60/69] Clarify docstrings in `cherrypy.test.logtest` module --- cherrypy/test/logtest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cherrypy/test/logtest.py b/cherrypy/test/logtest.py index 8ed095dcb..433d4e5c9 100644 --- a/cherrypy/test/logtest.py +++ b/cherrypy/test/logtest.py @@ -14,7 +14,7 @@ import msvcrt def getchar(): - """Handle windows case for get char.""" + """Get a key press from the Windows terminal.""" return msvcrt.getch() except ImportError: # Unix getchr @@ -22,7 +22,7 @@ def getchar(): import termios def getchar(): - """Handle unix case for get char.""" + """Get a key press from the UNIX terminal.""" fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: @@ -94,7 +94,7 @@ def _handleLogError(self, msg, data, marker, pattern): sys.stdout.write(p + ' ') def exit(self): - """Exit.""" + """Terminate the program.""" sys.exit() def emptyLog(self): From 4a82cbb63a780fb08977aa92f8ffa25750189dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 02:51:29 +0200 Subject: [PATCH 61/69] Clarify docstrings in `cherrypy.test.checkerdemo` module --- cherrypy/test/checkerdemo.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cherrypy/test/checkerdemo.py b/cherrypy/test/checkerdemo.py index fe65bc0fe..327a75b66 100644 --- a/cherrypy/test/checkerdemo.py +++ b/cherrypy/test/checkerdemo.py @@ -11,9 +11,7 @@ class Root: - """Root class.""" - - pass + """Demo web app.""" if __name__ == '__main__': From 19528b142daa22905c13299f2d71f0bfafc4c970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 03:20:14 +0200 Subject: [PATCH 62/69] Clarify docstrings in `cherrypy.test.helper` module --- cherrypy/test/helper.py | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/cherrypy/test/helper.py b/cherrypy/test/helper.py index fc56382f8..25b25668d 100644 --- a/cherrypy/test/helper.py +++ b/cherrypy/test/helper.py @@ -31,7 +31,7 @@ class Supervisor(object): """Base class for modeling and controlling servers during testing.""" def __init__(self, **kwargs): - """Initialize Supervisor.""" + """Initialize a supervisor.""" for k, v in kwargs.items(): if k == 'port': setattr(self, k, int(v)) @@ -56,7 +56,7 @@ class LocalSupervisor(Supervisor): using_wsgi = False def __init__(self, **kwargs): - """Initialize LocalSupervisor.""" + """Initialize the local supervisor.""" for k, v in kwargs.items(): setattr(self, k, v) @@ -107,7 +107,7 @@ class NativeServerSupervisor(LocalSupervisor): using_wsgi = False def __str__(self): - """Represent NativeServerSupervisor as a string.""" + """Render a :class:`NativeServerSupervisor` instance as a string.""" return 'Builtin HTTP Server on %s:%s' % (self.host, self.port) @@ -119,11 +119,11 @@ class LocalWSGISupervisor(LocalSupervisor): using_wsgi = True def __str__(self): - """Represent LocalWSGISupervisor as a string.""" + """Render a :class:`LocalWSGISupervisor` instance as a string.""" return 'Builtin WSGI Server on %s:%s' % (self.host, self.port) def sync_apps(self): - """Create Hook into a new WSGI app into the origin server.""" + """Connect a new WSGI app into the origin server.""" cherrypy.server.httpserver.wsgi_app = self.get_app() def get_app(self, app=None): @@ -145,7 +145,7 @@ def get_app(self, app=None): def get_cpmodpy_supervisor(**options): - """Get CherryPy mod_python supervisor.""" + """Load a CherryPy ``mod_python`` supervisor.""" from cherrypy.test import modpy sup = modpy.ModPythonSupervisor(**options) sup.template = modpy.conf_cpmodpy @@ -153,7 +153,7 @@ def get_cpmodpy_supervisor(**options): def get_modpygw_supervisor(**options): - """Get CherryPy mod_python gateway supervisor.""" + """Load a CherryPy ``mod_python`` gateway supervisor.""" from cherrypy.test import modpy sup = modpy.ModPythonSupervisor(**options) sup.template = modpy.conf_modpython_gateway @@ -162,31 +162,31 @@ def get_modpygw_supervisor(**options): def get_modwsgi_supervisor(**options): - """Get CherryPy mod_wsgi supervisor.""" + """Load a CherryPy ``mod_wsgi`` supervisor.""" from cherrypy.test import modwsgi return modwsgi.ModWSGISupervisor(**options) def get_modfcgid_supervisor(**options): - """Get CherryPy mod_fcgi supervisor.""" + """Load a CherryPy ``mod_fcgi`` supervisor.""" from cherrypy.test import modfcgid return modfcgid.ModFCGISupervisor(**options) def get_modfastcgi_supervisor(**options): - """Get CherryPy mod_fastcgi supervisor.""" + """Load a CherryPy ``mod_fastcgi`` supervisor.""" from cherrypy.test import modfastcgi return modfastcgi.ModFCGISupervisor(**options) def get_wsgi_u_supervisor(**options): - """Get CherryPy wsgi supervisor.""" + """Load a CherryPy WSGI supervisor.""" cherrypy.server.wsgi_version = ('u', 0) return LocalWSGISupervisor(**options) class CPWebCase(webtest.WebCase): - """CherryPy Web Test Case.""" + """CherryPy web test case base.""" script_name = '' scheme = 'http' @@ -248,7 +248,7 @@ def _setup_server(cls, supervisor, conf): @classmethod def setup_class(cls): - """Create a server.""" + """Invoke a test server.""" conf = { 'scheme': 'http', 'protocol': 'HTTP/1.1', @@ -285,14 +285,14 @@ def setup_class(cls): @classmethod def teardown_class(cls): - """Teardown a server.""" + """Tear down the test server.""" if hasattr(cls, 'setup_server'): cls.supervisor.stop() do_gc_test = False def test_gc(self): - """Test /gc.""" + """Perform the garbage collection testing.""" if not self.do_gc_test: return @@ -303,11 +303,11 @@ def test_gc(self): 'Failures occur intermittently. See #1420' def prefix(self): - """Get prefix.""" + """Get an HTTP handler prefix.""" return self.script_name.rstrip('/') def base(self): - """Return base.""" + """Construct the base server URL.""" if ((self.scheme == 'http' and self.PORT == 80) or (self.scheme == 'https' and self.PORT == 443)): port = '' @@ -318,7 +318,7 @@ def base(self): self.script_name.rstrip('/')) def exit(self): - """Exit.""" + """Terminate the program.""" sys.exit() def getPage(self, url, *args, **kwargs): @@ -328,7 +328,7 @@ def getPage(self, url, *args, **kwargs): return webtest.WebCase.getPage(self, url, *args, **kwargs) def skip(self, msg='skipped '): - """Skip.""" + """Skip the currently running test.""" pytest.skip(msg) def assertErrorPage(self, status, message=None, pattern=''): @@ -428,7 +428,7 @@ class CPProcess(object): def __init__(self, wait=False, daemonize=False, ssl=False, socket_host=None, socket_port=None): - """Initialize CPProcess.""" + """Initialize a server process runner.""" self.wait = wait self.daemonize = daemonize self.ssl = ssl @@ -436,7 +436,7 @@ def __init__(self, wait=False, daemonize=False, ssl=False, self.port = socket_port or cherrypy.server.socket_port def write_conf(self, extra=''): - """Write CPProcess config.""" + """Write the server config to disk.""" if self.ssl: serverpem = os.path.join(thisdir, 'test.pem') ssl = """ @@ -516,7 +516,7 @@ def start(self, imports=None): time.sleep(1) def get_pid(self): - """Get PID.""" + """Get the server process ID.""" if self.daemonize: with open(self.pid_file, 'rb') as f: return int(f.read()) From 2b1280ace761be8176a4b6c0b7124db4eafc32a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 04:10:52 +0200 Subject: [PATCH 63/69] Clarify docstrings in `cherrypy.test.benchmark` module --- cherrypy/test/benchmark.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/cherrypy/test/benchmark.py b/cherrypy/test/benchmark.py index 92cb2c266..2de46457c 100644 --- a/cherrypy/test/benchmark.py +++ b/cherrypy/test/benchmark.py @@ -47,11 +47,11 @@ class Root: - """Root class.""" + """Test web app.""" @cherrypy.expose def index(self): - """Handle index for Root.""" + """Produce HTTP response body of test app index URI.""" return """ CherryPy Benchmark @@ -69,12 +69,12 @@ def index(self): @cherrypy.expose def hello(self): - """Handle hello for Root.""" + """Render a "Hello world!" message on ``/hello`` URI.""" return 'Hello, world\r\n' @cherrypy.expose def sizer(self, size): - """Handle sizer for Root.""" + """Send a cached sized response.""" resp = size_cache.get(size, None) if resp is None: size_cache[size] = resp = 'X' * int(size) @@ -82,7 +82,7 @@ def sizer(self, size): def init(): - """Initialize server.""" + """Configure the test server.""" cherrypy.config.update({ 'log.error.file': '', 'environment': 'production', @@ -113,15 +113,13 @@ class NullRequest: """A null HTTP request class, returning 200 and an empty body.""" def __init__(self, local, remote, scheme='http'): - """Initialize NullRequest.""" - pass + """Initialize a null request instance.""" def close(self): - """Close NullRequest.""" - pass + """Close the null request.""" def run(self, method, path, query_string, protocol, headers, rfile): - """Run NullRequest.""" + """Construct an HTTP response.""" cherrypy.response.status = '200 OK' cherrypy.response.header_list = [('Content-Type', 'text/html'), ('Server', 'Null CherryPy'), @@ -133,9 +131,7 @@ def run(self, method, path, query_string, protocol, headers, rfile): class NullResponse: - """NullResponse class.""" - - pass + """A null HTTP response.""" class ABSession: @@ -215,13 +211,13 @@ class ABSession: def __init__(self, path=SCRIPT_NAME + '/hello', requests=1000, concurrency=10): - """Initialize ABSession.""" + """Initialize an Apache Benchmark session.""" self.path = path self.requests = requests self.concurrency = concurrency def args(self): - """Get ABSession arguments.""" + """Compute the Apache Benchmark CLI arguments.""" port = cherrypy.server.socket_port assert self.concurrency > 0 assert self.requests > 0 @@ -232,7 +228,7 @@ def args(self): (self.requests, self.concurrency, port, self.path)) def run(self): - """Run ABSession.""" + """Run an Apache Benchmark test.""" # Parse output of ab, setting attributes on self try: self.output = _cpmodpy.read_process(AB_PATH or 'ab', self.args()) @@ -256,7 +252,7 @@ def run(self): def thread_report(path=SCRIPT_NAME + '/hello', concurrency=safe_threads): - """Report on threads from ABSession.""" + """Report Apache Benchmark against a multi-threaded server.""" sess = ABSession(path) attrs, names, patterns = list(zip(*sess.parse_patterns)) avg = dict.fromkeys(attrs, 0.0) @@ -284,7 +280,7 @@ def thread_report(path=SCRIPT_NAME + '/hello', concurrency=safe_threads): def size_report(sizes=(10, 100, 1000, 10000, 100000, 100000000), concurrency=50): - """Report sizing from ABSession.""" + """Report Apache Benchmark against different payload sizes.""" sess = ABSession(concurrency=concurrency) attrs, names, patterns = list(zip(*sess.parse_patterns)) yield ('bytes',) + names From 5ea0c97f10bd6ed3e1ded774da39d11a6a74009d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 04:20:31 +0200 Subject: [PATCH 64/69] Clarify docstrings in `cherrypy.test._test_decorators` module --- cherrypy/test/_test_decorators.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cherrypy/test/_test_decorators.py b/cherrypy/test/_test_decorators.py index 3e15004df..9e261d383 100644 --- a/cherrypy/test/_test_decorators.py +++ b/cherrypy/test/_test_decorators.py @@ -5,36 +5,36 @@ class ExposeExamples(object): - """Test class ExposeExamples.""" + """Exposed routes test app.""" @expose def no_call(self): - """No call function for ExposeExamples.""" + """Return a string on ``/no_call``.""" return 'Mr E. R. Bradshaw' @expose() def call_empty(self): - """Empty call function for ExposeExamples.""" + """Return a string on ``/call_empty``.""" return 'Mrs. B.J. Smegma' @expose('call_alias') def nesbitt(self): - """Return Mr Nesbitt.""" + """Return "Mr Nesbitt" on ``/call_alias``.""" return 'Mr Nesbitt' @expose(['alias1', 'alias2']) def andrews(self): - """Return Mr Ken Andrews.""" + """Return a string on ``/andrews``, ``/alias1``, ``/alias2``.""" return 'Mr Ken Andrews' @expose(alias='alias3') def watson(self): - """Return Mr. and Mrs. Watson.""" + """Return "Mr. and Mrs. Watson" on ``/watson``, ``/alias3``.""" return 'Mr. and Mrs. Watson' class ToolExamples(object): - """Test ToolExamples class.""" + """A web app with tools.""" @expose # This is here to demonstrate that using the config decorator @@ -43,5 +43,5 @@ class ToolExamples(object): @cherrypy.config(**{'response.stream': True}) @tools.response_headers(headers=[('Content-Type', 'application/data')]) def blah(self): - """Blah.""" + """Emit "Blah" on ``/blah``.""" yield b'blah' From 248331e490a6e067b9dbf8ee5ca63b8747f060f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 04:36:53 +0200 Subject: [PATCH 65/69] Clarify docstrings in `cherrypy.test._test_states_demo` module --- cherrypy/test/_test_states_demo.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cherrypy/test/_test_states_demo.py b/cherrypy/test/_test_states_demo.py index fb111e1f8..7ccbc1772 100644 --- a/cherrypy/test/_test_states_demo.py +++ b/cherrypy/test/_test_states_demo.py @@ -8,31 +8,31 @@ class Root: - """Root routes handler.""" + """A test web app.""" @cherrypy.expose def index(self): - """Handle index.""" + """Produce HTTP response body of test app index URI.""" return 'Hello World' @cherrypy.expose def mtimes(self): - """Handle mtimes.""" + """Respond with timestamps.""" return repr(cherrypy.engine.publish('Autoreloader', 'mtimes')) @cherrypy.expose def pid(self): - """Handle pid.""" + """Respond with the current process ID.""" return str(os.getpid()) @cherrypy.expose def start(self): - """Handle start.""" + """Respond with the start time.""" return repr(starttime) @cherrypy.expose def exit(self): - """Handle exit.""" + """Stop the server.""" # This handler might be called before the engine is STARTED if an # HTTP worker thread handles it before the HTTP server returns # control to engine.start. We avoid that race condition here @@ -43,7 +43,7 @@ def exit(self): @cherrypy.engine.subscribe('start', priority=100) def unsub_sig(): - """Handle unsub sig.""" + """Unsubscribe the default signal handler.""" cherrypy.log('unsubsig: %s' % cherrypy.config.get('unsubsig', False)) if cherrypy.config.get('unsubsig', False): cherrypy.log('Unsubscribing the default cherrypy signal handler') @@ -62,7 +62,7 @@ def old_term_handler(signum=None, frame=None): @cherrypy.engine.subscribe('start', priority=6) def starterror(): - """Handle start error.""" + """Error out on start.""" if cherrypy.config.get('starterror', False): 1 / 0 From 71951cb747a9aa387e9762802ecf0474d8035164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 04:51:05 +0200 Subject: [PATCH 66/69] Clarify docstrings in `cherrypy.lib.auth_digest` module --- cherrypy/lib/auth_digest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cherrypy/lib/auth_digest.py b/cherrypy/lib/auth_digest.py index abf19b45c..d94b5bab4 100644 --- a/cherrypy/lib/auth_digest.py +++ b/cherrypy/lib/auth_digest.py @@ -160,9 +160,10 @@ def _try_decode_header(header, charset): class HttpDigestAuthorization(object): - """Parses a Digest Authorization header. + """Digest Authorization implementation. - Parses and performs re-calculation of the digest. + Parses a Digest Authorization header and performs + re-calculation of the digest. """ scheme = 'digest' From 98175fb378d652954d518813e6daf402309f50f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 05:11:58 +0200 Subject: [PATCH 67/69] Clarify docstrings in `cherrypy._cpwsgi` module --- cherrypy/_cpwsgi.py | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/cherrypy/_cpwsgi.py b/cherrypy/_cpwsgi.py index f022a469e..eaaf01878 100644 --- a/cherrypy/_cpwsgi.py +++ b/cherrypy/_cpwsgi.py @@ -53,14 +53,29 @@ class VirtualHost(object): cherrypy.tree.graft(vhost) """ - default = None + """The default WSGI application. + + Required. + """ + use_x_forwarded_host = True + """If True (the default), any "X-Forwarded-Host" + request header will be used instead of the "Host" header. This + is commonly added by HTTP servers (such as Apache) when proxying.""" + domains = {} + """A dict of {host header value: application} pairs. + The incoming "Host" request header is looked up in this dict, and, + if a match is found, the corresponding WSGI application will be + called instead of the default. Note that you often need separate + entries for "example.com" and "www.example.com". In addition, "Host" + headers may contain the port number. + """ def __init__(self, default, domains=None, use_x_forwarded_host=True): """ - Initialize VirtualHost. + Initialize a virtual host app. :param default: The default WSGI application :type default: WSGI application @@ -82,7 +97,7 @@ def __init__(self, default, domains=None, use_x_forwarded_host=True): self.use_x_forwarded_host = use_x_forwarded_host def __call__(self, environ, start_response): - """Call VirtualHost.""" + """Route WSGI requests based on host names.""" domain = environ.get('HTTP_HOST', '') if self.use_x_forwarded_host: domain = environ.get('HTTP_X_FORWARDED_HOST', domain) @@ -97,12 +112,12 @@ class InternalRedirector(object): """WSGI middleware that handles raised cherrypy.InternalRedirect.""" def __init__(self, nextapp, recursive=False): - """Initialize InternalRedirector.""" + """Initialize an internal redirector.""" self.nextapp = nextapp self.recursive = recursive def __call__(self, environ, start_response): - """Initialize InternalRedirector.""" + """Process internal WSGI request redirects.""" redirections = [] while True: environ = environ.copy() @@ -146,12 +161,12 @@ class ExceptionTrapper(object): """WSGI middleware that traps exceptions.""" def __init__(self, nextapp, throws=(KeyboardInterrupt, SystemExit)): - """Initialize ExceptionTrapper.""" + """Initialize exception trapper.""" self.nextapp = nextapp self.throws = throws def __call__(self, environ, start_response): - """Call ExceptionTrapper.""" + """Handle exceptions while processing a WSGI request.""" return _TrappedResponse( self.nextapp, environ, @@ -236,7 +251,7 @@ class AppResponse(object): """WSGI response iterable for CherryPy applications.""" def __init__(self, environ, start_response, cpapp): - """Initialize AppResponse.""" + """Initialize the WSGI app response.""" self.cpapp = cpapp try: self.environ = environ @@ -278,11 +293,11 @@ def __init__(self, environ, start_response, cpapp): raise def __iter__(self): - """Handle iteration for AppResponse.""" + """Make an app response iterator.""" return self def __next__(self): - """Handle next for AppResponse.""" + """Iterate over the app response.""" return next(self.iter_response) def close(self): @@ -355,7 +370,7 @@ def run(self): } def recode_path_qs(self, path, qs): - """Recode path qs AppResponse.""" + """Recode app response path query string.""" # This isn't perfect; if the given PATH_INFO is in the # wrong encoding, it may fail to match the appropriate config # section URI. But meh. @@ -426,7 +441,7 @@ class CPWSGIApp(object): """ def __init__(self, cpapp, pipeline=None): - """Initialize CPWSGIApp.""" + """Initialize a framework WSGI app wrapper.""" self.cpapp = cpapp self.pipeline = self.pipeline[:] if pipeline: @@ -442,7 +457,7 @@ def tail(self, environ, start_response): return self.response_class(environ, start_response, self.cpapp) def __call__(self, environ, start_response): - """Handle call to CPWSGIApp.""" + """Process a WSGI request.""" head = self.head if head is None: # Create and nest the WSGI apps in our pipeline (in reverse order). From b0b70a9190a54ac710f8e88cf6a49fb5ca3d7bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 05:13:53 +0200 Subject: [PATCH 68/69] fixup! cherrypy/_cpwsgi.py --- cherrypy/_cpwsgi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cherrypy/_cpwsgi.py b/cherrypy/_cpwsgi.py index eaaf01878..75635f504 100644 --- a/cherrypy/_cpwsgi.py +++ b/cherrypy/_cpwsgi.py @@ -53,6 +53,7 @@ class VirtualHost(object): cherrypy.tree.graft(vhost) """ + default = None """The default WSGI application. From a234f699b12d99a0e71b9f66fe27c6fb5226c40f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sviatoslav=20Sydorenko=20=28=D0=A1=D0=B2=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1=D0=B8=D0=B4=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE=29?= Date: Tue, 2 Jul 2024 05:19:56 +0200 Subject: [PATCH 69/69] Clarify docstrings in `cherrypy.lib.headers` module --- cherrypy/lib/headers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cherrypy/lib/headers.py b/cherrypy/lib/headers.py index ddbe515be..30e4813c5 100644 --- a/cherrypy/lib/headers.py +++ b/cherrypy/lib/headers.py @@ -1,4 +1,4 @@ -"""headers.""" +"""HTTP header parsing helpers.""" def _parse_param(s): @@ -15,11 +15,11 @@ def _parse_param(s): def parse_header(line): - """Parse a Content-type like header. + """Parse a ``Content-Type`` like header. - Return the main content-type and a dictionary of options. + Return the main ``Content-Type`` and a dictionary of options. - Copied from removed stdlib cgi module. See + Copied from removed stdlib :mod:`cgi` module. See `cherrypy/cherrypy#2014 (comment) `_ for background.