bottle.py is a fast and simple micro-framework for python web-applications.
This report summarizes scanner evidence for bottlepy/bottle, a Python project with 8,793 GitHub stars. SynthScan examined 9,485 lines of code across 39 source files, recording 118 pattern matches distributed across 8 syntactic categories. The legacy adjusted pattern signal is 19.8 (Elevated pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 68 finding(s).
Are imports declared and package/API names verified? 32 finding(s).
Are wrappers, guards, and repeated structures necessary? 74 finding(s).
Which changes need focused human review? 118 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 118 distinct pattern matches across 8 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | bottle.py | 133 | except (IOError, AttributeError): | CODE |
| HIGH | bottle.py | 141 | except AttributeError: | CODE |
| HIGH | bottle.py | 2538 | except Exception: | CODE |
| HIGH | bottle.py | 3881 | except KeyboardInterrupt: | CODE |
| HIGH | bottle.py | 2108 | except Exception: | CODE |
| HIGH | bottle.py | 2900 | except ValueError: | CODE |
| HIGH | bottle.py | 3833 | except KeyboardInterrupt: | CODE |
| HIGH | bottle.py | 3648 | except KeyError: | CODE |
| HIGH | bottle.py | 3714 | except ImportError: | CODE |
| HIGH | test/__init__.py | 9 | except ImportError: | CODE |
| HIGH | test/test_wsgi.py | 242 | except RuntimeError: | CODE |
| HIGH | test/test_environ.py | 667 | except CookieError: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | test/test_plugins.py | 53 | def test_uninstall_by_instance(self): | CODE |
| LOW | test/test_plugins.py | 155 | def test_json_plugin_catches_httpresponse(self): | CODE |
| LOW | test/test_plugins.py | 196 | def test_instance_method_wrapper(self): | CODE |
| LOW | test/test_mount.py | 90 | def test_mount_wsgi_ctype_bug(self): | CODE |
| LOW⚡ | test/test_router.py | 136 | def test_dynamic_before_static_any(self): | CODE |
| LOW⚡ | test/test_router.py | 143 | def test_any_static_before_dynamic(self): | CODE |
| LOW⚡ | test/test_router.py | 150 | def test_dynamic_any_if_method_exists(self): | CODE |
| LOW | test/test_config.py | 68 | def test_overlay_filter_error_keeps_virtual_key(self): | CODE |
| LOW | test/test_multipart.py | 183 | def test_missing_content_type(self): | CODE |
| LOW | test/test_multipart.py | 186 | def test_unsupported_content_type(self): | CODE |
| LOW⚡ | test/test_multipart.py | 198 | def test_no_newline_after_content(self): | CODE |
| LOW⚡ | test/test_multipart.py | 204 | def test_no_newline_after_middle_content(self): | CODE |
| LOW⚡ | test/test_multipart.py | 214 | def test_preamble_before_start_boundary(self): | CODE |
| LOW | test/test_multipart.py | 251 | def test_content_length_to_small(self): | CODE |
| LOW | test/test_multipart.py | 258 | def test_no_disposition_header(self): | CODE |
| LOW | test/test_stpl.py | 20 | def test_self_as_variable_name(self): | CODE |
| LOW | test/test_stpl.py | 101 | def test_newline_in_parameterlist(self): | CODE |
| LOW | test/test_stpl.py | 231 | def test_bug_no_whitespace_before_stmt(self): | CODE |
| LOW | test/test_stpl.py | 234 | def test_bug_block_keywords_eat_prefixed_code(self): | CODE |
| LOW | test/test_stpl.py | 277 | def test_multiline_ignore_eob_in_string(self): | STRING |
| LOW | test/test_stpl.py | 289 | def test_multiline_find_eob_in_comments(self): | STRING |
| LOW | test/test_stpl.py | 316 | def test_multiline_eob_after_end(self): | STRING |
| LOW | test/test_stpl.py | 327 | def test_multiline_eob_in_single_line_code(self): | STRING |
| LOW | test/test_stpl.py | 337 | def test_multiline_strings_in_code_line(self): | STRING |
| LOW | test/test_stpl.py | 348 | def test_multiline_comprehensions_in_code_line(self): | STRING |
| LOW | test/test_stpl.py | 361 | def test_end_keyword_on_same_line(self): | STRING |
| LOW | test/test_outputfilter.py | 85 | def test_json_serialization_error(self): | CODE |
| LOW | test/test_outputfilter.py | 109 | def test_json_config_enable_false(self): | CODE |
| LOW | test/test_outputfilter.py | 116 | def test_json_config_dump_func(self): | CODE |
| LOW⚡ | test/test_outputfilter.py | 139 | def test_empty_generator_callback(self): | CODE |
| LOW⚡ | test/test_outputfilter.py | 147 | def test_error_in_generator_callback(self): | CODE |
| LOW⚡ | test/test_outputfilter.py | 154 | def test_fatal_error_in_generator_callback(self): | CODE |
| LOW⚡ | test/test_outputfilter.py | 161 | def test_httperror_in_generator_callback(self): | CODE |
| LOW⚡ | test/test_outputfilter.py | 170 | def test_httpresponse_in_generator_callback(self): | CODE |
| LOW⚡ | test/test_outputfilter.py | 176 | def test_unicode_generator_callback(self): | CODE |
| LOW⚡ | test/test_outputfilter.py | 182 | def test_invalid_generator_callback(self): | CODE |
| LOW | test/test_wsgi.py | 353 | def test_after_request_hooks_run_after_exception(self): | CODE |
| LOW | test/test_wsgi.py | 373 | def test_after_request_hooks_run_after_exception_in_before_hook(self): | CODE |
| LOW | test/test_wsgi.py | 393 | def test_after_request_hooks_may_rise_response_exception(self): | CODE |
| LOW | test/test_wsgi.py | 410 | def test_after_response_hook_can_set_headers(self): | CODE |
| LOW | test/test_wsgi.py | 543 | def test_module_shortcuts_with_different_name(self): | CODE |
| LOW | test/test_route.py | 44 | def test_callback_inspection_multiple_args(self): | CODE |
| LOW | test/test_route.py | 66 | def test_callback_inspection_newsig(self): | CODE |
| LOW | test/test_route.py | 98 | def test_unwrap_closure_callable(self): | CODE |
| LOW | test/test_environ.py | 140 | def test_header_access_special(self): | CODE |
| LOW⚡ | test/test_environ.py | 308 | def test_chunked_not_terminated(self): | CODE |
| LOW⚡ | test/test_environ.py | 314 | def test_chunked_illegal_size(self): | CODE |
| LOW⚡ | test/test_environ.py | 317 | def test_chunked_not_chunked_at_all(self): | CODE |
| LOW | test/test_environ.py | 403 | def test_json_header_empty_body(self): | CODE |
| LOW | test/test_environ.py | 452 | def test_user_defined_attributes(self): | CODE |
| LOW | test/test_environ.py | 493 | def test_constructor_headerlist(self): | CODE |
| LOW | test/test_environ.py | 611 | def test_set_cookie_value_long_string(self): | CODE |
| LOW | test/test_environ.py | 615 | def test_set_cookie_name_long_string(self): | CODE |
| LOW | test/test_environ.py | 735 | def test_prevent_control_characters_in_headers(self): | CODE |
| LOW | test/test_environ.py | 870 | def test_redirect_preserve_cookies(self): | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | test/test_formsdict.py | 5 | CODE | |
| LOW | test/test_formsdict.py | 5 | CODE | |
| LOW | test/test_plugins.py | 2 | CODE | |
| LOW | test/test_plugins.py | 5 | CODE | |
| LOW | test/tools.py | 2 | CODE | |
| LOW | test/tools.py | 14 | CODE | |
| LOW | test/__init__.py | 1 | CODE | |
| LOW | test/__init__.py | 2 | CODE | |
| LOW | test/__init__.py | 3 | CODE | |
| LOW | test/__init__.py | 4 | CODE | |
| LOW | test/__init__.py | 4 | CODE | |
| LOW | test/test_fileupload.py | 5 | CODE | |
| LOW | test/test_fileupload.py | 6 | CODE | |
| LOW | test/test_fileupload.py | 7 | CODE | |
| LOW | test/test_oorouting.py | 14 | CODE | |
| LOW | test/test_multipart.py | 4 | CODE | |
| LOW | test/test_multipart.py | 4 | CODE | |
| LOW | test/test_multipart.py | 4 | CODE | |
| LOW | test/test_stpl.py | 2 | CODE | |
| LOW | test/test_outputfilter.py | 7 | CODE | |
| LOW | test/test_outputfilter.py | 12 | CODE | |
| LOW | test/test_wsgi.py | 2 | CODE | |
| LOW | test/test_mako.py | 1 | CODE | |
| LOW | test/test_mako.py | 54 | CODE | |
| LOW | test/test_jinja2.py | 69 | CODE | |
| LOW | test/test_jinja2.py | 43 | CODE | |
| LOW | test/test_jinja2.py | 50 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | bottle.py | 1091 | default_app.push(self) | CODE |
| HIGH | bottle.py | 2500 | return self.push() | CODE |
| HIGH | bottle.py | 3772 | tmp = default_app.push() # Create a new "default application" | CODE |
| HIGH | test/test_securecookies.py | 13 | bottle.app.push() | CODE |
| HIGH | test/tools.py | 86 | self.app = bottle.app.push() | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | bottle.py | 130 | def _stderr(*args): | CODE |
| LOW | bottle.py | 968 | except Exception as E: | CODE |
| LOW | bottle.py | 1032 | except Exception as error: | CODE |
| LOW | bottle.py | 1070 | except Exception as E: | CODE |
| LOW | bottle.py | 2108 | except Exception: | CODE |
| LOW | bottle.py | 2538 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bottle.py | 2885 | CODE | |
| LOW | bottle.py | 2908 | CODE | |
| LOW | bottle.py | 3784 | CODE | |
| LOW | bottle.py | 4507 | CODE | |
| LOW | bottle.py | 430 | CODE | |
| LOW | bottle.py | 533 | CODE | |
| LOW | bottle.py | 1172 | CODE | |
| LOW | bottle.py | 2604 | CODE | |
| LOW | bottle.py | 3179 | CODE | |
| LOW | bottle.py | 4275 | CODE | |
| LOW | test/test_multipart.py | 81 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | bottle.py | 3772 | tmp = default_app.push() # Create a new "default application" | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bottle.py | 3784 | CODE |