Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/tags/cherrypy-3.1.0beta2/cherrypy/_cpchecker.py

Revision 1732 (checked in by fumanchu, 1 year ago)

Port to trunk of [1706] and [1714].

  • Property svn:eol-style set to native
Line 
1 import os
2 import warnings
3
4 import cherrypy
5
6
7 class Checker(object):
8     """A checker for CherryPy sites and their mounted applications.
9     
10     on: set this to False to turn off the checker completely.
11     
12     When this object is called at engine startup, it executes each
13     of its own methods whose names start with "check_". If you wish
14     to disable selected checks, simply add a line in your global
15     config which sets the appropriate method to False:
16     
17     [global]
18     checker.check_skipped_app_config = False
19     
20     You may also dynamically add or replace check_* methods in this way.
21     """
22    
23     on = True
24    
25     def __init__(self):
26         self._populate_known_types()
27    
28     def __call__(self):
29         """Run all check_* methods."""
30         if self.on:
31             oldformatwarning = warnings.formatwarning
32             warnings.formatwarning = self.formatwarning
33             try:
34                 for name in dir(self):
35                     if name.startswith("check_"):
36                         method = getattr(self, name)
37                         if method and callable(method):
38                             method()
39             finally:
40                 warnings.formatwarning = oldformatwarning
41    
42     def formatwarning(self, message, category, filename, lineno):
43         """Function to format a warning."""
44         return "CherryPy Checker:\n%s\n\n" % message
45    
46     # This value should be set inside _cpconfig.
47     global_config_contained_paths = False
48    
49     def check_skipped_app_config(self):
50         for sn, app in cherrypy.tree.apps.iteritems():
51             if not isinstance(app, cherrypy.Application):
52                 continue
53             if not app.config:
54                 msg = "The Application mounted at %r has an empty config." % sn
55                 if self.global_config_contained_paths:
56                     msg += (" It looks like the config you passed to "
57                             "cherrypy.config.update() contains application-"
58                             "specific sections. You must explicitly pass "
59                             "application config via "
60                             "cherrypy.tree.mount(..., config=app_config)")
61                 warnings.warn(msg)
62                 return
63    
64     def check_static_paths(self):
65         # Use the dummy Request object in the main thread.
66         request = cherrypy.request
67         for sn, app in cherrypy.tree.apps.iteritems():
68             if not isinstance(app, cherrypy.Application):
69                 continue
70             request.app = app
71             for section in app.config:
72                 # get_resource will populate request.config
73                 request.get_resource(section + "/dummy.html")
74                 conf = request.config.get
75                
76                 if conf("tools.staticdir.on", False):
77                     msg = ""
78                     root = conf("tools.staticdir.root")
79                     dir = conf("tools.staticdir.dir")
80                     if dir is None:
81                         msg = "tools.staticdir.dir is not set."
82                     else:
83                         fulldir = ""
84                         if os.path.isabs(dir):
85                             fulldir = dir
86                             if root:
87                                 msg = ("dir is an absolute path, even "
88                                        "though a root is provided.")
89                                 testdir = os.path.join(root, dir[1:])
90                                 if os.path.exists(testdir):
91                                     msg += ("\nIf you meant to serve the "
92                                             "filesystem folder at %r, remove "
93                                             "the leading slash from dir." % testdir)
94                         else:
95                             if not root:
96                                 msg = "dir is a relative path and no root provided."
97                             else:
98                                 fulldir = os.path.join(root, dir)
99                                 if not os.path.isabs(fulldir):
100                                     msg = "%r is not an absolute path." % fulldir
101                        
102                         if fulldir and not os.path.exists(fulldir):
103                             if msg:
104                                 msg += "\n"
105                             msg += ("%r (root + dir) is not an existing "
106                                     "filesystem path." % fulldir)
107                    
108                     if msg:
109                         warnings.warn("%s\nsection: [%s]\nroot: %r\ndir: %r"
110                                       % (msg, section, root, dir))
111    
112    
113     # -------------------------- Compatibility -------------------------- #
114    
115     obsolete = {
116         'server.default_content_type': 'tools.response_headers.headers',
117         'log_access_file': 'log.access_file',
118         'log_config_options': None,
119         'log_file': 'log.error_file',
120         'log_file_not_found': None,
121         'log_request_headers': 'tools.log_headers.on',
122         'log_to_screen': 'log.screen',
123         'show_tracebacks': 'request.show_tracebacks',
124         'throw_errors': 'request.throw_errors',
125         'profiler.on': ('cherrypy.tree.mount(profiler.make_app('
126                         'cherrypy.Application(Root())))'),
127         }
128    
129     deprecated = {}
130    
131     def _compat(self, config):
132         """Process config and warn on each obsolete or deprecated entry."""
133         for section, conf in config.iteritems():
134             if isinstance(conf, dict):
135                 for k, v in conf.iteritems():
136                     if k in self.obsolete:
137                         warnings.warn("%r is obsolete. Use %r instead.\n"
138                                       "section: [%s]" %
139                                       (k, self.obsolete[k], section))
140                     elif k in self.deprecated:
141                         warnings.warn("%r is deprecated. Use %r instead.\n"
142                                       "section: [%s]" %
143                                       (k, self.deprecated[k], section))
144             else:
145                 if section in self.obsolete:
146                     warnings.warn("%r is obsolete. Use %r instead."
147                                   % (section, self.obsolete[section]))
148                 elif section in self.deprecated:
149                     warnings.warn("%r is deprecated. Use %r instead."
150                                   % (section, self.deprecated[section]))
151    
152     def check_compatibility(self):
153         """Process config and warn on each obsolete or deprecated entry."""
154         self._compat(cherrypy.config)
155         for sn, app in cherrypy.tree.apps.iteritems():
156             if not isinstance(app, cherrypy.Application):
157                 continue
158             self._compat(app.config)
159    
160    
161     # ------------------------ Known Namespaces ------------------------ #
162    
163     extra_config_namespaces = []
164    
165     def _known_ns(self, app):
166         ns = ["wsgi"]
167         ns.extend(app.toolboxes.keys())
168         ns.extend(app.request_class.namespaces.keys())
169         ns.extend(cherrypy.config.namespaces.keys())
170         ns += self.extra_config_namespaces
171        
172         for section, conf in app.config.iteritems():
173             is_path_section = section.startswith("/")
174             if is_path_section and isinstance(conf, dict):
175                 for k, v in conf.iteritems():
176                     atoms = k.split(".")
177                     if len(atoms) > 1:
178                         if atoms[0] not in ns:
179                             # Spit out a special warning if a known
180                             # namespace is preceded by "cherrypy."
181                             if (atoms[0] == "cherrypy" and atoms[1] in ns):
182                                 msg = ("The config entry %r is invalid; "
183                                        "try %r instead.\nsection: [%s]"
184                                        % (k, ".".join(atoms[1:]), section))
185                             else:
186                                 msg = ("The config entry %r is invalid, because "
187                                        "the %r config namespace is unknown.\n"
188                                        "section: [%s]" % (k, atoms[0], section))
189                             warnings.warn(msg)
190                         elif atoms[0] == "tools":
191                             if atoms[1] not in dir(cherrypy.tools):
192                                 msg = ("The config entry %r may be invalid, "
193                                        "because the %r tool was not found.\n"
194                                        "section: [%s]" % (k, atoms[1], section))
195                                 warnings.warn(msg)
196    
197     def check_config_namespaces(self):
198         """Process config and warn on each unknown config namespace."""
199         for sn, app in cherrypy.tree.apps.iteritems():
200             if not isinstance(app, cherrypy.Application):
201                 continue
202             self._known_ns(app)
203
204
205    
206    
207     # -------------------------- Config Types -------------------------- #
208    
209     known_config_types = {}
210    
211     def _populate_known_types(self):
212         import __builtin__
213         builtins = [x for x in vars(__builtin__).values()
214                     if type(x) is type(str)]
215        
216         def traverse(obj, namespace):
217             for name in dir(obj):
218                 vtype = type(getattr(obj, name, None))
219                 if vtype in builtins:
220                     self.known_config_types[namespace + "." + name] = vtype
221        
222         traverse(cherrypy.request, "request")
223         traverse(cherrypy.response, "response")
224         traverse(cherrypy.server, "server")
225         traverse(cherrypy.engine, "engine")
226         traverse(cherrypy.log, "log")
227    
228     def _known_types(self, config):
229         msg = ("The config entry %r in section %r is of type %r, "
230                "which does not match the expected type %r.")
231        
232         for section, conf in config.iteritems():
233             if isinstance(conf, dict):
234                 for k, v in conf.iteritems():
235                     if v is not None:
236                         expected_type = self.known_config_types.get(k, None)
237                         vtype = type(v)
238                         if expected_type and vtype != expected_type:
239                             warnings.warn(msg % (k, section, vtype.__name__,
240                                                  expected_type.__name__))
241             else:
242                 k, v = section, conf
243                 if v is not None:
244                     expected_type = self.known_config_types.get(k, None)
245                     vtype = type(v)
246                     if expected_type and vtype != expected_type:
247                         warnings.warn(msg % (k, section, vtype.__name__,
248                                              expected_type.__name__))
249    
250     def check_config_types(self):
251         """Assert that config values are of the same type as default values."""
252         self._known_types(cherrypy.config)
253         for sn, app in cherrypy.tree.apps.iteritems():
254             if not isinstance(app, cherrypy.Application):
255                 continue
256             self._known_types(app.config)
257    
258    
259     # -------------------- Specific config warnings -------------------- #
260    
261     def check_localhost(self):
262         """Warn if any socket_host is 'localhost'. See #711."""
263         for k, v in cherrypy.config.iteritems():
264             if k == 'server.socket_host' and v == 'localhost':
265                 warnings.warn("The use of 'localhost' as a socket host can "
266                     "cause problems on newer systems, since 'localhost' can "
267                     "map to either an IPv4 or an IPv6 address. You should "
268                     "use '127.0.0.1' or '[::1]' instead.")
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets