diff -r dc171b1d8261 -r 362cd1b6f81a eric6/DebugClients/Python/coverage/plugin.py --- a/eric6/DebugClients/Python/coverage/plugin.py Wed Feb 19 19:38:36 2020 +0100 +++ b/eric6/DebugClients/Python/coverage/plugin.py Sat Feb 22 14:27:42 2020 +0100 @@ -1,5 +1,5 @@ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 -# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt """ .. versionadded:: 4.0 @@ -14,6 +14,9 @@ * Configurers add custom configuration, using Python code to change the configuration. +* Dynamic context switchers decide when the dynamic context has changed, for + example, to record what test function produced the coverage. + To write a coverage.py plug-in, create a module with a subclass of :class:`~coverage.CoveragePlugin`. You will override methods in your class to participate in various aspects of coverage.py's processing. @@ -54,6 +57,8 @@ your importable Python package. +.. _file_tracer_plugins: + File Tracers ============ @@ -66,6 +71,8 @@ register your file tracer. +.. _configurer_plugins: + Configurers =========== @@ -78,6 +85,31 @@ In your ``coverage_init`` function, use the ``add_configurer`` method to register your configurer. + +.. _dynamic_context_plugins: + +Dynamic Context Switchers +========================= + +.. versionadded:: 5.0 + +Dynamic context switcher plugins implement the +:meth:`~coverage.CoveragePlugin.dynamic_context` method to dynamically compute +the context label for each measured frame. + +Computed context labels are useful when you want to group measured data without +modifying the source code. + +For example, you could write a plugin that checks `frame.f_code` to inspect +the currently executed method, and set the context label to a fully qualified +method name if it's an instance method of `unittest.TestCase` and the method +name starts with 'test'. Such a plugin would provide basic coverage grouping +by test and could be used with test runners that have no built-in coveragepy +support. + +In your ``coverage_init`` function, use the ``add_dynamic_context`` method to +register your dynamic context switcher. + """ from coverage import files @@ -94,13 +126,14 @@ Every Python source file is offered to your plug-in to give it a chance to take responsibility for tracing the file. If your plug-in can - handle the file, then return a :class:`FileTracer` object. Otherwise - return None. + handle the file, it should return a :class:`FileTracer` object. + Otherwise return None. There is no way to register your plug-in for particular files. - Instead, this method is invoked for all files, and the plug-in decides - whether it can trace the file or not. Be prepared for `filename` to - refer to all kinds of files that have nothing to do with your plug-in. + Instead, this method is invoked for all files as they are executed, + and the plug-in decides whether it can trace the file or not. + Be prepared for `filename` to refer to all kinds of files that have + nothing to do with your plug-in. The file name will be a Python file being executed. There are two broad categories of behavior for a plug-in, depending on the kind of @@ -134,11 +167,28 @@ This will only be invoked if `filename` returns non-None from :meth:`file_tracer`. It's an error to return None from this method. - Returns a :class:`FileReporter` object to use to report on `filename`. + Returns a :class:`FileReporter` object to use to report on `filename`, + or the string `"python"` to have coverage.py treat the file as Python. """ _needs_to_implement(self, "file_reporter") + def dynamic_context(self, frame): # pylint: disable=unused-argument + """Get the dynamically computed context label for `frame`. + + Plug-in type: dynamic context. + + This method is invoked for each frame when outside of a dynamic + context, to see if a new dynamic context should be started. If it + returns a string, a new context label is set for this and deeper + frames. The dynamic context ends when this frame returns. + + Returns a string to start a new dynamic context, or None if no new + context should be started. + + """ + return None + def find_executable_files(self, src_dir): # pylint: disable=unused-argument """Yield all of the executable files in `src_dir`, recursively.