This document records the deliberate gaps in flask_hypergen's test coverage: one
xfail placeholder carried over from the original django-hypergen test suite, and a
small number of source lines/branches that are intentionally left uncovered.
These are documented (rather than tested) because exercising them would require behavior that flask_hypergen does not implement, or contrived environments (optional dependencies uninstalled, internal invariants forced into impossible states) that would add maintenance cost without testing anything meaningful.
tests/flask_hypergen_tests/test_core_ported.py contains:
@pytest.mark.xfail(
reason='Django legacy middleware compatibility is intentionally not part of flask_hypergen',
)
def test_context_middleware_old():
raise AssertionError()The upstream django-hypergen project supported Django's old-style middleware via
django.utils.deprecation.MiddlewareMixin. Its context.py did:
try:
from django.utils.deprecation import MiddlewareMixin
except ImportError:
MiddlewareMixin = object # Backwards compatibility.
class ContextMiddleware(MiddlewareMixin):
def process_request(self, request):
context.replace(**_init_context(request))The corresponding upstream test (test_context_middleware_old) only ran on Django 3 or
earlier and asserted that the legacy MiddlewareMixin-based path populated the context:
def test_context_middleware_old():
if int(django.get_version()[0]) > 3:
return
middleware = ContextMiddleware()
middleware.process_request(Request())
assert context.request.user.pk == 1flask_hypergen is a Flask port and has no dependency on Django, so the
MiddlewareMixin deprecation-compatibility shim does not apply. The framework-agnostic
behavior it guarded is ported and tested:
ContextMiddleware.process_requestis covered bytest_context_middleware_class.- The functional
context_middlewarewrapper is covered bytest_context_middleware.
The test_context_middleware_old placeholder is kept as a named xfail purely to
preserve a one-to-one mapping with the upstream test suite, making it obvious to future
readers that this Django-specific legacy path was considered and intentionally dropped
rather than overlooked. It is expected to remain xfailed indefinitely.
As of the latest run, total coverage is 99%. The handful of uncovered lines/branches below are intentional.
Optional-dependency guards. These execute only when an optional package is absent (or its lazy loader is invoked), which is not the case in the standard test environment.
- Lines 62, 66 —
docutils_core_load()/docutils_utils_load()bodies. These lazyimportlib.import_module('docutils.*')loaders run only whenrst()is actually used withdocutilsinstalled. - Lines 73-74 — the
except ImportError: yattag_ok = Falsebranch, which only runs whenyattagis not installed. (The positiveyattagpath and the "yattag required" error path are both tested via mocking.) - Lines 268-271 — the
rst()body that loadsdocutilsand renders reStructuredText. The guard that raises whendocutilsis missing is tested; the success path requiresdocutilsto be installed.
-
Line 22 — the
continuein the flat-namespace dedup loop:for name in getattr(module, '__all__', []): if name in __all__: continue # only hit if two submodules export the same name
This defensive branch fires only if two submodules export the same public name. Given the current module set and their
__all__definitions, no such collision exists, so the line is unreachable today. It is retained to keep the re-export logic robust against future additions.
Two negative branch-partials in LiveviewPluginBase.template_after:
330->349— the path taken when an actionbase_viewproduces a resolver match whosefuncisNone(so the isolated re-render is skipped). The positive case (a resolvable base view) is tested; this negative branch is a guard against an unresolvable referer.356->362— the path taken whenself.morphis false or there is no'into'in the hypergen context, so the morph commands are not appended. The morph-enabled path is tested; this branch covers the non-morphing configuration.
Both are defensive negatives around the action/base_view re-render flow; forcing them would require constructing an unresolvable or morph-disabled liveview state that does not correspond to a real usage scenario.