Skip to content

Commit

Permalink
Merge pull request #155 from Erotemic/dev/1.1.5
Browse files Browse the repository at this point in the history
Start branch for dev/1.1.5
  • Loading branch information
Erotemic authored Jun 8, 2024
2 parents 6850e64 + 2749cab commit 607f57d
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 91 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ We are currently working on porting this changelog to the specifications in
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## Version 1.1.4 - Unreleased
## Version 1.1.5 - Unreleased

### Changed
* Minor modification to `xdoctest --version-info` and exposed it in CLI help.

### Fixed
* `ub.modname_to_modpath` fixed in cases where editable installs use type annotations in their MAPPING definition.


## Version 1.1.4 - Released 2024-05-31

### Fixed
* Working around a `modname_to_modpath` issue.
Expand Down
18 changes: 18 additions & 0 deletions dev/demo/demo_dynamic_analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
CommandLine:
xdoctest ~/code/xdoctest/dev/demo/demo_dynamic_analysis.py --analysis=auto
xdoctest ~/code/xdoctest/dev/demo/demo_dynamic_analysis.py --analysis=dynamic
xdoctest ~/code/xdoctest/dev/demo/demo_dynamic_analysis.py --xdoc-force-dynamic
"""


def func() -> None:
r''' Dynamic doctest
>>> %s
%s
'''
return

func.__doc__ %= ('print(1)', '1')
12 changes: 6 additions & 6 deletions dev/demo_errors.py → dev/demo/demo_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
def demo1():
"""
CommandLine:
xdoctest -m ~/code/xdoctest/dev/demo_errors.py demo1
xdoctest -m ~/code/xdoctest/dev/demo/demo_errors.py demo1
Example:
>>> raise Exception('demo1')
Expand All @@ -20,7 +20,7 @@ def demo1():
def demo2():
"""
CommandLine:
xdoctest -m ~/code/xdoctest/dev/demo_errors.py demo2
xdoctest -m ~/code/xdoctest/dev/demo/demo_errors.py demo2
Example:
>>> print('error on different line')
Expand All @@ -32,7 +32,7 @@ def demo2():
def demo3():
"""
CommandLine:
xdoctest -m ~/code/xdoctest/dev/demo_errors.py demo3
xdoctest -m ~/code/xdoctest/dev/demo/demo_errors.py demo3
Example:
>>> print('demo5')
Expand All @@ -44,15 +44,15 @@ def demo3():
class Demo5(object):
"""
CommandLine:
xdoctest -m ~/code/xdoctest/dev/demo_errors.py Demo5
xdoctest -m ~/code/xdoctest/dev/demo/demo_errors.py Demo5
Example:
>>> raise Exception
"""
def demo5(self):
"""
CommandLine:
xdoctest -m ~/code/xdoctest/dev/demo_errors.py Demo5.demo5
xdoctest -m ~/code/xdoctest/dev/demo/demo_errors.py Demo5.demo5
Example:
>>> raise Exception
Expand Down Expand Up @@ -100,7 +100,7 @@ def demo_runtime_warning():
if __name__ == '__main__':
"""
CommandLine:
python ~/code/xdoctest/dev/demo_errors.py all
python ~/code/xdoctest/dev/demo/demo_errors.py all
"""
import xdoctest
xdoctest.doctest_module(__file__)
10 changes: 5 additions & 5 deletions dev/demo_issues.py → dev/demo/demo_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ def demo():
# Correctly reports skipped (although an only skipped test report
# should probably be yellow)
xdoctest -m dev/demo_issues.py demo_requires_skips_all_v1
xdoctest -m dev/demo/demo_issues.py demo_requires_skips_all_v1
# Incorrectly reports success
xdoctest -m dev/demo_issues.py demo_requires_skips_all_v2
xdoctest -m dev/demo/demo_issues.py demo_requires_skips_all_v2
# Correctly reports success
xdoctest -m dev/demo_issues.py demo_requires_skips_all_v2 --cliflag
xdoctest -m dev/demo/demo_issues.py demo_requires_skips_all_v2 --cliflag
# Correctly reports success
xdoctest -m dev/demo_issues.py demo_requires_skips_all_v1 --cliflag
xdoctest -m dev/demo/demo_issues.py demo_requires_skips_all_v1 --cliflag
"""

# Programatic reproduction (notice the first one also reports itself in
Expand All @@ -40,7 +40,7 @@ def demo():
xdoctest.doctest_callable(demo_requires_skips_all_v2)

import sys, ubelt
sys.path.append(ubelt.expandpath('~/code/xdoctest/dev'))
sys.path.append(ubelt.expandpath('~/code/xdoctest/dev/demo'))
import demo_issues

# Correctly reports skipped
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
CommandLine:
# Run with xdoctest runner
xdoctest ~/code/xdoctest/dev/demo_usage_with_logger.py
xdoctest ~/code/xdoctest/dev/demo/demo_usage_with_logger.py
# Run with pytest runner
pytest -s --xdoctest --xdoctest-verbose=3 ~/code/xdoctest/dev/demo_usage_with_logger.py
pytest -s --xdoctest --xdoctest-verbose=3 ~/code/xdoctest/dev/demo/demo_usage_with_logger.py
# Run with builtin main
python ~/code/xdoctest/dev/demo_usage_with_logger.py
python ~/code/xdoctest/dev/demo/demo_usage_with_logger.py
References:
.. [Issue111] https://github.com/Erotemic/xdoctest/issues/111
Expand Down
18 changes: 0 additions & 18 deletions dev/demo_dynamic_analysis.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
def interative_test_xdev_embed():
"""
CommandLine:
xdoctest -m dev/interactive_embed_tests.py interative_test_xdev_embed
xdoctest -m dev/demo/interactive_embed_tests.py interative_test_xdev_embed
Example:
>>> interative_test_xdev_embed()
Expand All @@ -16,7 +16,7 @@ def interative_test_xdev_embed():
def interative_test_ipdb_embed():
"""
CommandLine:
xdoctest -m dev/interactive_embed_tests.py interative_test_ipdb_embed
xdoctest -m dev/demo/interactive_embed_tests.py interative_test_ipdb_embed
Example:
>>> interative_test_ipdb_embed()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,6 @@ def _autogen_xdoctest_utils():
if __name__ == '__main__':
"""
CommandLine:
python ~/code/xdoctest/dev/port_ubelt_utils.py
python ~/code/xdoctest/dev/maintain/port_ubelt_utils.py
"""
_autogen_xdoctest_utils()
2 changes: 1 addition & 1 deletion src/xdoctest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def fib(n):
mkinit xdoctest --nomods
'''

__version__ = '1.1.4'
__version__ = '1.1.5'


# Expose only select submodules
Expand Down
10 changes: 6 additions & 4 deletions src/xdoctest/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,18 @@ def main(argv=None):
argv = sys.argv

version_info = {
'version': xdoctest.__version__,
'sys_version': sys.version,
'version': xdoctest.__version__,
}

if '--version' in argv:
print(version_info['version'])
return 0

if '--version-info' in argv:
for key, value in sorted(version_info.items()):
print('{} = {}'.format(key, value))
print('sys_version = {}'.format(version_info['sys_version']))
print('file = {}'.format(__file__))
print('version = {}'.format(version_info['version']))
return 0

import argparse
Expand Down Expand Up @@ -69,7 +70,8 @@ class RawDescriptionDefaultsHelpFormatter(
If the `--command` key / value pair is unspecified, the first
positional argument is used as the command.
'''))
parser.add_argument('--version', action='store_true', help='Display version info and quit')
parser.add_argument('--version', action='store_true', help='Display version and quit')
parser.add_argument('--version-info', action='store_true', help='Display version and other info and quit')

# The bulk of the argparse CLI is defined in the doctest example
from xdoctest import doctest_example
Expand Down
106 changes: 56 additions & 50 deletions src/xdoctest/utils/util_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,37 @@ def _importlib_import_modpath(modpath): # nocover
return module


def _pkgutil_modname_to_modpath(modname): # nocover
"""
faster version of :func:`_syspath_modname_to_modpath` using builtin python
mechanisms, but unfortunately it doesn't play nice with pytest.
Note:
pkgutil.find_loader is deprecated in 3.12 and removed in 3.14
Args:
modname (str): the module name.
Example:
>>> # xdoctest: +SKIP
>>> modname = 'xdoctest.static_analysis'
>>> _pkgutil_modname_to_modpath(modname)
...static_analysis.py
>>> # xdoctest: +REQUIRES(CPython)
>>> _pkgutil_modname_to_modpath('_ctypes')
..._ctypes...
Ignore:
>>> _pkgutil_modname_to_modpath('cv2')
"""
import pkgutil
loader = pkgutil.find_loader(modname)
if loader is None:
raise Exception('No module named {} in the PYTHONPATH'.format(modname))
modpath = loader.get_filename().replace('.pyc', '.py')
return modpath


class PythonPathContext(object):
"""
Context for temporarily adding a dir to the PYTHONPATH.
Expand Down Expand Up @@ -180,9 +211,10 @@ def _custom_import_modpath(modpath, index=-1):
with PythonPathContext(dpath, index=index):
module = import_module_from_name(modname)
except Exception as ex: # nocover
msg_parts = [
'ERROR: Failed to import modname={} with modpath={}'.format(
modname, modpath)
msg_parts = [(
'ERROR: Failed to import modname={} with modpath={} and '
'sys.path modified with {} at index={}').format(
modname, modpath, repr(dpath), index)
]
msg_parts.append('Caused by: {}'.format(repr(ex)))
raise RuntimeError('\n'.join(msg_parts))
Expand Down Expand Up @@ -292,13 +324,14 @@ def import_module_from_path(modpath, index=-1):
>>> assert module.testvar == 1
Example:
>>> # xdoctest: +SKIP("ubelt dependency")
>>> import pytest
>>> # xdoctest: +SKIP("ubelt dependency")
>>> with pytest.raises(IOError):
>>> ub.import_module_from_path('does-not-exist')
>>> with pytest.raises(IOError):
>>> ub.import_module_from_path('does-not-exist.zip/')
"""
modpath = os.fspath(modpath)
if not os.path.exists(modpath):
import re
import zipimport
Expand Down Expand Up @@ -452,6 +485,13 @@ def _static_parse(varname, fpath):
"""
Statically parse the a constant variable from a python file
Args:
varname (str): variable name to extract
fpath (str | PathLike): path to python file to parse
Returns:
Any: the static value
Example:
>>> # xdoctest: +SKIP("ubelt dependency")
>>> dpath = ub.Path.appdir('tests/import/staticparse').ensuredir()
Expand All @@ -475,6 +515,10 @@ def _static_parse(varname, fpath):
>>> with pytest.raises(AttributeError):
>>> fpath.write_text('a = list(range(10))')
>>> assert _static_parse('c', fpath) is None
>>> if sys.version_info[0:2] >= (3, 6):
>>> # Test with type annotations
>>> fpath.write_text('b: int = 10')
>>> assert _static_parse('b', fpath) == 10
"""
import ast

Expand All @@ -487,9 +531,16 @@ def _static_parse(varname, fpath):
class StaticVisitor(ast.NodeVisitor):
def visit_Assign(self, node):
for target in node.targets:
if getattr(target, 'id', None) == varname:
target_id = getattr(target, 'id', None)
if target_id == varname:
self.static_value = _parse_static_node_value(node.value)

def visit_AnnAssign(self, node):
target = node.target
target_id = getattr(target, 'id', None)
if target_id == varname:
self.static_value = _parse_static_node_value(node.value)

visitor = StaticVisitor()
visitor.visit(pt)
try:
Expand Down Expand Up @@ -743,51 +794,6 @@ def check_dpath(dpath):
return found_modpath


def _importlib_modname_to_modpath(modname): # nocover
import importlib.util
spec = importlib.util.find_spec(modname)
print(f'spec={spec}')
modpath = spec.origin.replace('.pyc', '.py')
return modpath


def _pkgutil_modname_to_modpath(modname): # nocover
"""
faster version of :func:`_syspath_modname_to_modpath` using builtin python
mechanisms, but unfortunately it doesn't play nice with pytest.
Note:
pkgutil.find_loader is deprecated in 3.12 and removed in 3.14
Args:
modname (str): the module name.
Example:
>>> # xdoctest: +SKIP
>>> modname = 'xdoctest.static_analysis'
>>> _pkgutil_modname_to_modpath(modname)
...static_analysis.py
>>> # xdoctest: +REQUIRES(CPython)
>>> _pkgutil_modname_to_modpath('_ctypes')
..._ctypes...
Ignore:
>>> _pkgutil_modname_to_modpath('cv2')
"""
import pkgutil
loader = pkgutil.find_loader(modname)
if loader is None:
raise Exception('No module named {} in the PYTHONPATH'.format(modname))
try:
modpath = loader.get_filename().replace('.pyc', '.py')
except Exception:
print('Issue in _pkgutil_modname_to_modpath')
print(f'loader = {loader!r}')
print(f'modname = {modname!r}')
raise
return modpath


def modname_to_modpath(modname, hide_init=True, hide_main=False, sys_path=None):
"""
Finds the path to a python module from its name.
Expand Down

0 comments on commit 607f57d

Please sign in to comment.