diff --git a/experiments/__doc__/coverage_macropy/.coveragerc b/experiments/__doc__/coverage_macropy/.coveragerc new file mode 100644 index 00000000..2d724712 --- /dev/null +++ b/experiments/__doc__/coverage_macropy/.coveragerc @@ -0,0 +1,9 @@ +[run] +source = + . + +[report] +exclude_lines = + pragma: no cover +# raise RuntimeError + diff --git a/experiments/__doc__/coverage_macropy/Makefile b/experiments/__doc__/coverage_macropy/Makefile new file mode 100644 index 00000000..1cb8f2e5 --- /dev/null +++ b/experiments/__doc__/coverage_macropy/Makefile @@ -0,0 +1,12 @@ +#!/usr/bin/make +#PY_COV=python3-coverage +PY_COV=$(HOME)/.local/bin/coverage3 + +all: + $(PY_COV) erase + $(PY_COV) run -a --timid ./try_mymacros.py + $(PY_COV) report + $(PY_COV) html + x-www-browser htmlcov/index.html + + diff --git a/experiments/__doc__/coverage_macropy/README.md b/experiments/__doc__/coverage_macropy/README.md new file mode 100644 index 00000000..97f798ef --- /dev/null +++ b/experiments/__doc__/coverage_macropy/README.md @@ -0,0 +1,23 @@ +# Coverage and macropy + +When using the `with` macro block [Coverage.py](https://coverage.readthedocs.io/en/coverage-5.1/) fails to detect some sentences. + +Here is a small example to show it. The `mymacros.py` contains a macro that was reduced to *do nothing*. + +Running `make` you can see how 3 lines in `application.py` are marked as uncovered. + +I commented these lines in the code with `# <--- Not covered?` + +The coverage version used is the Debian stable one: + +``` +Coverage.py, version 4.5.2 with C extension +Documentation at https://coverage.readthedocs.io +``` + +I also tried the code from GitHub (installed on my user: + +``` +Coverage.py, version 5.1.1a0 with C extension +Full documentation is at https://coverage.readthedocs.io/en/coverage-5.1.1a0 +``` diff --git a/experiments/__doc__/coverage_macropy/application.py b/experiments/__doc__/coverage_macropy/application.py new file mode 100644 index 00000000..98cb79f1 --- /dev/null +++ b/experiments/__doc__/coverage_macropy/application.py @@ -0,0 +1,29 @@ +from mymacros import macros, document # noqa: F401 + +with document: # <--- Not covered? + # comentario a + a = "5.1" + """ docu a """ + b = False + """ docu b """ + c = 3 + """ docu c """ # <--- Not covered? + + +class d(object): + def __init__(self): + with document: # <--- Not covered? + self.at1 = 4.5 + """ documenting d.at1 """ + + +# print("a = "+str(a)+" # "+_help_a) # noqa: F821 +# print("b = "+str(b)+" # "+_help_b) # noqa: F821 +# print("c = "+str(c)+" # "+_help_c) # noqa: F821 +# e = d() +# print("e.at1 = "+str(e.at1)+" # "+e._help_at1) # noqa: F821 +print("a = "+str(a)) +print("b = "+str(b)) +print("c = "+str(c)) +e = d() +print("e.at1 = "+str(e.at1)) diff --git a/experiments/__doc__/coverage_macropy/mymacros.py b/experiments/__doc__/coverage_macropy/mymacros.py new file mode 100644 index 00000000..9c187179 --- /dev/null +++ b/experiments/__doc__/coverage_macropy/mymacros.py @@ -0,0 +1,60 @@ +from macropy.core.macros import Macros +from ast import (Assign, Name, Attribute, Expr, Num, Str, NameConstant, Load, Store) + +macros = Macros() + + +@macros.block +def document(tree, **kw): + # Simplify it just to show the problem isn't related to the content of the macro + return tree + """ This macro takes literal strings and converts them into: + _help_ID = type_hint+STRING + where: + ID is the first target of the last assignment. + type_hint is the assigned type and default value (only works for a few types) + STRING is the literal string """ + for n in range(len(tree)): + s = tree[n] + if not n: + prev = s + continue + # The whole sentence is a string? + if (isinstance(s, Expr) and isinstance(s.value, Str) and + # and the previous is an assign + isinstance(prev, Assign)): # noqa: E128 + # Apply it to the first target + target = prev.targets[0] + value = prev.value + # Extract its name + # variables and attributes are supported + if isinstance(target, Name): + name = target.id + is_attr = False + elif isinstance(target, Attribute): + name = target.attr + is_attr = True + else: + continue + # Remove starting underscore + if name[0] == '_': + name = name[1:] + # Create a _help_ID + doc_id = '_help_'+name + # Create the type hint for numbers, strings and booleans + type_hint = '' + if isinstance(value, Num): + type_hint = '[number={}]'.format(value.n) + elif isinstance(value, Str): + type_hint = "[string='{}']".format(value.s) + elif isinstance(value, NameConstant) and isinstance(value.value, bool): + type_hint = '[boolean={}]'.format(str(value.value).lower()) + # Transform the string into an assign for _help_ID + if is_attr: + target = Attribute(value=Name(id='self', ctx=Load()), attr=doc_id, ctx=Store()) + else: + target = Name(id=doc_id, ctx=Store()) + tree[n] = Assign(targets=[target], value=Str(s=type_hint+s.value.s)) + prev = s + # Return the modified AST + return tree diff --git a/experiments/__doc__/coverage_macropy/try_mymacros.py b/experiments/__doc__/coverage_macropy/try_mymacros.py new file mode 100755 index 00000000..beeabda1 --- /dev/null +++ b/experiments/__doc__/coverage_macropy/try_mymacros.py @@ -0,0 +1,3 @@ +#!/usr/bin/python3 +import macropy.activate # noqa: F401 +import application # noqa: F401 diff --git a/experiments/__doc__/coverage_mcpy/.coveragerc b/experiments/__doc__/coverage_mcpy/.coveragerc new file mode 100644 index 00000000..2d724712 --- /dev/null +++ b/experiments/__doc__/coverage_mcpy/.coveragerc @@ -0,0 +1,9 @@ +[run] +source = + . + +[report] +exclude_lines = + pragma: no cover +# raise RuntimeError + diff --git a/experiments/__doc__/coverage_mcpy/Makefile b/experiments/__doc__/coverage_mcpy/Makefile new file mode 100644 index 00000000..1cb8f2e5 --- /dev/null +++ b/experiments/__doc__/coverage_mcpy/Makefile @@ -0,0 +1,12 @@ +#!/usr/bin/make +#PY_COV=python3-coverage +PY_COV=$(HOME)/.local/bin/coverage3 + +all: + $(PY_COV) erase + $(PY_COV) run -a --timid ./try_mymacros.py + $(PY_COV) report + $(PY_COV) html + x-www-browser htmlcov/index.html + + diff --git a/experiments/__doc__/coverage_mcpy/README.md b/experiments/__doc__/coverage_mcpy/README.md new file mode 100644 index 00000000..fdb20ced --- /dev/null +++ b/experiments/__doc__/coverage_mcpy/README.md @@ -0,0 +1,23 @@ +# Coverage and mcpy + +When using the `with` macro block [Coverage.py](https://coverage.readthedocs.io/en/coverage-5.1/) fails to detect some sentences. + +Here is a small example to show it. The `mymacros.py` contains a macro that was reduced to *do nothing*. + +Running `make` you can see how 3 lines in `application.py` are marked as uncovered. + +I commented these lines in the code with `# <--- Not covered?` + +The coverage version used is the Debian stable one: + +``` +Coverage.py, version 4.5.2 with C extension +Documentation at https://coverage.readthedocs.io +``` + +I also tried the code from GitHub (installed on my user: + +``` +Coverage.py, version 5.1.1a0 with C extension +Full documentation is at https://coverage.readthedocs.io/en/coverage-5.1.1a0 +``` diff --git a/experiments/__doc__/coverage_mcpy/application.py b/experiments/__doc__/coverage_mcpy/application.py new file mode 100644 index 00000000..db56c6c1 --- /dev/null +++ b/experiments/__doc__/coverage_mcpy/application.py @@ -0,0 +1,29 @@ +from mymacros import macros, document # noqa: F401 + +with document: # <--- Not covered? + # comentario a + a = "5.1" + """ docu a """ + b = False + """ docu b """ + c = 3 + """ docu c """ # <--- Not covered? + + +class d(object): + def __init__(self): + with document: + self.at1 = 4.5 + """ documenting d.at1 """ # <--- Not covered? + + +# print("a = "+str(a)+" # "+_help_a) # noqa: F821 +# print("b = "+str(b)+" # "+_help_b) # noqa: F821 +# print("c = "+str(c)+" # "+_help_c) # noqa: F821 +# e = d() +# print("e.at1 = "+str(e.at1)+" # "+e._help_at1) # noqa: F821 +print("a = "+str(a)) +print("b = "+str(b)) +print("c = "+str(c)) +e = d() +print("e.at1 = "+str(e.at1)) diff --git a/experiments/__doc__/coverage_mcpy/mymacros.py b/experiments/__doc__/coverage_mcpy/mymacros.py new file mode 100644 index 00000000..661391c3 --- /dev/null +++ b/experiments/__doc__/coverage_mcpy/mymacros.py @@ -0,0 +1,56 @@ +from ast import (Assign, Name, Attribute, Expr, Num, Str, NameConstant, Load, Store) + + +def document(tree, **kw): + """ This macro takes literal strings and converts them into: + _help_ID = type_hint+STRING + where: + ID is the first target of the last assignment. + type_hint is the assigned type and default value (only works for a few types) + STRING is the literal string """ + # Simplify it just to show the problem isn't related to the content of the macro + return tree + for n in range(len(tree)): + s = tree[n] + if not n: + prev = s + continue + # The whole sentence is a string? + if (isinstance(s, Expr) and isinstance(s.value, Str) and + # and the previous is an assign + isinstance(prev, Assign)): # noqa: E128 + # Apply it to the first target + target = prev.targets[0] + value = prev.value + # Extract its name + # variables and attributes are supported + if isinstance(target, Name): + name = target.id + is_attr = False + elif isinstance(target, Attribute): + name = target.attr + is_attr = True + else: + continue + # Remove starting underscore + if name[0] == '_': + name = name[1:] + # Create a _help_ID + doc_id = '_help_'+name + # Create the type hint for numbers, strings and booleans + type_hint = '' + if isinstance(value, Num): + type_hint = '[number={}]'.format(value.n) + elif isinstance(value, Str): + type_hint = "[string='{}']".format(value.s) + elif isinstance(value, NameConstant) and isinstance(value.value, bool): + type_hint = '[boolean={}]'.format(str(value.value).lower()) + # Transform the string into an assign for _help_ID + if is_attr: + target = Attribute(value=Name(id='self', ctx=Load()), attr=doc_id, ctx=Store()) + else: + target = Name(id=doc_id, ctx=Store()) + tree[n] = Assign(targets=[target], value=Str(s=type_hint+s.value.s)) + prev = s + # Return the modified AST + return tree diff --git a/experiments/__doc__/coverage_mcpy/try_mymacros.py b/experiments/__doc__/coverage_mcpy/try_mymacros.py new file mode 100755 index 00000000..f7b184bb --- /dev/null +++ b/experiments/__doc__/coverage_mcpy/try_mymacros.py @@ -0,0 +1,3 @@ +#!/usr/bin/python3 +import mcpy.activate # noqa: F401 +import application # noqa: F401