Bases: BaseService
A service class for running code coverage analysis.
This class provides methods for measuring code coverage for both Django and Python projects.
The constructor for the CoverageService class.
Parameters:
-
config
(dict[str, Any] | None, default:
None
)
–
The configuration dictionary for coverage settings.
Source code in dev_tool/services/coverage/service.py
| def __init__(self, config: dict[str, Any] | None = None) -> None:
"""
The constructor for the CoverageService class.
:param config: The configuration dictionary for coverage settings.
"""
super().__init__()
self.set_config(config or {})
self.manager, self.fallback = PackageManagerFactory.create_package_manager()
|
A method that sets the configuration for the coverage service.
Parameters:
-
config
(dict[str, Any])
–
The configuration dictionary containing coverage settings.
Source code in dev_tool/services/coverage/service.py
| def set_config(self, config: dict[str, Any]) -> None:
"""
A method that sets the configuration for the coverage service.
:param config: The configuration dictionary containing coverage settings.
"""
self.config = config
self.apps = config.get('apps', ['.'])
self.settings = config.get('settings', 'system.testing.settings')
self.nobrowser = config.get('nobrowser', False)
self.noerase = config.get('noerase', False)
self.nohtml = config.get('nohtml', False)
self.failfast = config.get('failfast', False)
self.exclude = config.get('exclude', [])
|
A method that installs the coverage package.
Source code in dev_tool/services/coverage/service.py
| def install_coverage(self) -> None:
"""A method that installs the coverage package."""
try:
if not self.manager.install_package('coverage'):
message = 'Failed to install coverage with preferred manager, falling back...'
self.notification.error_banner(message)
log.debug(message)
if not self.fallback.install_package('coverage'):
message = 'Failed to install coverage package with any package manager'
log.debug(message)
raise CoverageInstallationError(message)
except (OSError, PermissionError):
message = 'Unexpected error installing coverage package'
log.exception(message)
raise CoverageInstallationError(message) from None
|
A method that runs coverage analysis for Django projects.
This method requires Django settings to be properly configured.
Source code in dev_tool/services/coverage/service.py
| @is_settings
def run_django_coverage(self) -> None:
"""
A method that runs coverage analysis for Django projects.
This method requires Django settings to be properly configured.
"""
if not self.apps:
message = 'No apps to test.'
self.notification.warning_text(message)
log.debug(message)
return
self._validate_directories(self.apps, CoverageRunError)
message = 'Running Django coverage...'
self.notification.normal_text(message)
self.install_coverage()
apps = list(self.apps)
omit = ','.join(self.exclude)
command = [
'coverage',
'run',
'--branch',
'--source=.',
f'--omit={omit}',
'manage.py',
'test',
*apps,
f'--settings={self.settings}',
'--noinput',
'-v'
]
if self.failfast:
command.append('--failfast')
try:
subprocess.run(self.with_venv(command), check=False)
self.generate_html_report()
self.erase_coverage()
self.open_browser()
except Exception:
message = 'Failed to run Django coverage analysis'
log.exception(message)
raise CoverageRunError(message) from None
|
A method that runs coverage analysis for Python projects.
Source code in dev_tool/services/coverage/service.py
| def run_python_coverage(self) -> None:
"""A method that runs coverage analysis for Python projects."""
if not self.apps:
message = 'No test directory specified for Python coverage.'
self.notification.warning_text(message)
log.debug(message)
return
self._validate_directories(self.apps, CoverageRunError)
self.install_coverage()
apps = list(self.apps)
omit = ','.join(self.exclude)
command = [
'coverage',
'run',
'--branch',
'--source=.',
f'--omit={omit}',
'-m',
'unittest',
'discover',
'-s', *apps,
'-v'
]
if self.failfast:
command.append('--failfast')
try:
subprocess.run(self.with_venv(command), check=False)
self.generate_html_report()
self.erase_coverage()
self.open_browser()
except Exception:
message = 'Failed to run Python coverage analysis'
log.exception(message)
raise CoverageRunError(message) from None
|
A method that generates an HTML report of the coverage results.
Source code in dev_tool/services/coverage/service.py
| def generate_html_report(self) -> None:
"""A method that generates an HTML report of the coverage results."""
if self.nohtml:
return
directory = '.coverage_html_report'
command = [
'coverage',
'html',
f'--directory={directory}'
]
try:
subprocess.run(self.with_venv(command), check=True)
except subprocess.CalledProcessError:
message = 'Failed to generate HTML coverage report'
log.exception(message)
raise CoverageReportError(message) from None
except Exception:
message = 'Unexpected error during HTML report generation'
log.exception(message)
raise CoverageReportError(message) from None
|
A method that erases previously collected coverage data.
Source code in dev_tool/services/coverage/service.py
| def erase_coverage(self) -> None:
"""A method that erases previously collected coverage data."""
if self.noerase:
return
command = ['coverage', 'erase']
try:
subprocess.run(self.with_venv(command), check=True)
except subprocess.CalledProcessError:
message = 'Failed to erase coverage data'
log.debug(message)
raise CoverageReportError(message) from None
except Exception:
message = 'Unexpected error during coverage data cleanup'
log.exception(message)
raise CoverageReportError(message) from None
|
A method that opens the coverage report in a web browser.
Source code in dev_tool/services/coverage/service.py
| def open_browser(self) -> None:
"""A method that opens the coverage report in a web browser."""
if self.nobrowser:
return
directory = '.coverage_html_report'
index = str(BASE / directory / 'index.html')
command = f'start "" "{index}"'
try:
subprocess.run(command, check=True, shell=True)
except subprocess.CalledProcessError:
message = 'Failed to open coverage report in browser'
log.debug(message)
raise CoverageReportError(message) from None
except Exception:
message = 'Unexpected error opening browser'
log.exception(message)
raise CoverageReportError(message) from None
|
A method that prepends the virtual environment Python to a command.
Parameters:
Returns:
-
list[Path | str]
–
The modified command with virtual environment Python.
Source code in dev_tool/services/coverage/service.py
| def with_venv(self, command: list[str]) -> list[Path | str]:
"""
A method that prepends the virtual environment Python to a command.
:param command: The command to modify.
:return: The modified command with virtual environment Python.
"""
return [VENV_PYTHON, '-m', *command]
|