Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Working on issue 106 #107

Merged
merged 9 commits into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Changed

* Added GitHub actions to the CI
* Disabled workaround 16806 in Python 3.8+


### Fixed

* Fixed minor test failures
* Fixed #106 - an issue to do with compiling multiline statements in single mode.
* Fixed #108 - an issue to do with compiling semicolon token in eval mode.


## Version 0.15.8 - Released 2021-09-02
Expand Down
120 changes: 88 additions & 32 deletions dev/_compare/demo_issue_106.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,114 @@
"""
r"""
https://github.com/Erotemic/xdoctest/issues/106
cd ~/code/xdoctest/dev/_compare/
python -m xdoctest demo_issue_106.py
python -m doctest demo_issue_106.py

Note:
the reason this fails is because this fails:

compile('try: raise Exception\nexcept Exception: print', mode='single', filename="")


In exec mode we are ok

compile('try: raise Exception\nexcept Exception: print', mode='exec', filename="")

This has to do with the assign ps1 line function that determines if
we should be in exec or single mode

Other tests


compile('if 1:\n a', mode='single', filename="")
compile('if 1:\n print', mode='single', filename="")
compile('if 1:\n x = 1\n y = 2\nelse:\n pass', mode='single', filename="")

compile('try:\n raise Exception\nexcept Exception:\n pass', mode='single', filename="")
compile('try: raise Exception\nexcept Exception: pass', mode='single', filename="")

except Exception: print', mode='single', filename="")

"""
import sys


def logTraceback(logFunction):
def logTracebackThisDoesnt(logFunction):
r""" Logs the exception traceback to the specified log function.

>>> # xdoctest: +IGNORE_WANT
>>> try: raise Exception() # doctest: +ELLIPSIS
... except Exception: logTraceback(lambda *a, **b: sys.stdout.write(a[0] + "\n", *a[1:], **b))
... except Exception: print(lambda *a, **b: sys.stdout.write(str(a) + "\n" + str(b)))
Traceback (most recent call last):
...
Exception
...
"""
sys.exc_info()
import xdev
xdev.embed()
# import xdev
# xdev.embed()
logFunction
pass


# def compact_style_code():
# """
# This compact style is a bit ugly, but it should still be valid python
def slurpFile(path, mode, maxbytes, **kwds):
"""
>>> import os; slurpFile(os.path.abspath(__file__), mode = 'rb')[:9]
b'# coding='
>>> import os; slurpFile(os.path.abspath(__file__), encoding='utf-8')[:9]
'# coding='
"""
pass

# Exception:
# >>> try: raise Exception # doctest: +ELLIPSIS
# ... except Exception: raise
# Traceback (most recent call last):
# ...
# Exception
# ...

# def logTracebackThisWorks(logFunction):
# r""" Logs the exception traceback to the specified log function.

# >>> try: raise Exception() # doctest: +ELLIPSIS
# >>> except Exception: print(lambda *a, **b: sys.stdout.write(str(a) + "\n" + str(b)))
# Traceback (most recent call last):
# ...
# Exception
# ...
# """
# try: raise Exception # NOQA
# except Exception: pass # NOQA
# sys.exc_info()
# # import xdev
# # xdev.embed()
# logFunction
# pass

# # ... except Exception: logTraceback(lambda *a, **b: sys.stdout.write(a[0] + "\n", *a[1:], **b))

def logTraceback2(logFunction):
r""" Logs the exception traceback to the specified log function.
# # def compact_style_code():
# # """
# # This compact style is a bit ugly, but it should still be valid python

>>> try:
... raise Exception()
... except Exception:
... logTraceback(lambda *a, **b: sys.stdout.write(a[0] + "\n", *a[1:], **b))
Traceback (most recent call last):
...
Exception
...
"""
import sys
logFunction(*sys.exec_info)
logFunction()
pass
# # Exception:
# # >>> try: raise Exception # doctest: +ELLIPSIS
# # ... except Exception: raise
# # Traceback (most recent call last):
# # ...
# # Exception
# # ...

# # """
# # try: raise Exception # NOQA
# # except Exception: pass # NOQA


# def logTraceback2(logFunction):
# r""" Logs the exception traceback to the specified log function.

# >>> try:
# ... raise Exception()
# ... except Exception:
# ... logTraceback(lambda *a, **b: sys.stdout.write(a[0] + "\n", *a[1:], **b))
# Traceback (most recent call last):
# ...
# Exception
# ...
# """
# import sys
# logFunction(*sys.exec_info)
# logFunction()
# pass
100 changes: 100 additions & 0 deletions testing/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,106 @@ def test_backwards_compat_indent_value():
assert status['passed']


def test_concise_try_except():
"""
CommandLine:
xdoctest -m ~/code/xdoctest/testing/test_core.py test_concise_try_except
"""
from xdoctest.doctest_example import DocTest
example = DocTest(
utils.codeblock(r"""
>>> # xdoctest: +IGNORE_WANT
>>> try: raise Exception
... except Exception: print(lambda *a, **b: sys.stdout.write(str(a) + "\n" + str(b)))
a bad want string
...
"""))
status = example.run(verbose=0)
assert status['passed']

from xdoctest.doctest_example import DocTest
example = DocTest(
utils.codeblock(r"""
>>> # xdoctest: +IGNORE_WANT
>>> try: raise Exception
>>> except Exception: print(lambda *a, **b: sys.stdout.write(str(a) + "\n" + str(b)))
a bad want string
...
"""))
status = example.run(verbose=0)
assert status['passed']


def test_semicolon_line():
r"""
Test for https://github.com/Erotemic/xdoctest/issues/108

Note:
Notes on the issue:

.. code:: python
# This works
compile("import os; print(os)", filename="", mode='exec')
compile("import os; print(os)", filename="", mode='single')

compile("1; 2", filename="", mode='exec')
compile("1; 2", filename="", mode='single')

compile("print();print()", filename="", mode='single')
compile("print();print()", filename="", mode='exec')

compile("print()", filename="", mode='eval')
compile("print()", filename="", mode='exec')
compile("print()", filename="", mode='single')

# This breaks:
compile("import os; print(os)", filename="", mode='eval')

# I suppose we can't have imports in an eval?
compile("import os\n", filename="", mode='eval')

# Or multiple lines?
compile("print();print()", filename="", mode='eval')

# No imports, no assignments, no semicolons
compile("1; 2", filename="", mode='eval')


CommandLine:
xdoctest -m ~/code/xdoctest/testing/test_core.py test_concise_exceptions
"""
from xdoctest.doctest_example import DocTest
example = DocTest(
utils.codeblock(r"""
>>> import os; print(os.path.abspath('.'))
"""))
status = example.run(verbose=0)
assert status['passed']

# The problem case was when it was compiled with a "want" statement
#
from xdoctest.doctest_example import DocTest
example = DocTest(
utils.codeblock(r"""
>>> import os; print(os.path.abspath('.'))
...
"""))
status = example.run(verbose=0)
assert status['passed']

# Test single import
# import xdoctest
# xdoctest.parser.DEBUG = 100
from xdoctest.doctest_example import DocTest
example = DocTest(
utils.codeblock(r"""
>>> import os
...
"""))
status = example.run(verbose=0)
assert status['passed']


if __name__ == '__main__':
"""
CommandLine:
Expand Down