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

support reading Argparse instances inside classes #60

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 24 additions & 16 deletions sphinxarg/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,28 @@
# raise exception
raise FileNotFoundError(self.options['filename'])

def _get_parser(self, obj, path):
for attr in path.split('.'):
try:
if isinstance(obj, dict):
obj = obj[attr]
else:
obj = getattr(obj, attr)
except (KeyError, AttributeError) as exc:
msg = (

Check warning on line 497 in sphinxarg/ext.py

View check run for this annotation

Codecov / codecov/patch

sphinxarg/ext.py#L496-L497

Added lines #L496 - L497 were not covered by tests
f'"{obj}" has no key/attribute "{attr} (path: {path})"\n'
f'Incorrect argparse :module: or :func: values?'
)
raise self.error(msg) from exc

Check failure on line 501 in sphinxarg/ext.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (PERF203)

sphinxarg/ext.py:496:13: PERF203 `try`-`except` within a loop incurs performance overhead

Check warning on line 501 in sphinxarg/ext.py

View check run for this annotation

Codecov / codecov/patch

sphinxarg/ext.py#L501

Added line #L501 was not covered by tests
if isinstance(obj, ArgumentParser):
parser = obj
elif 'passparser' in self.options:
parser = ArgumentParser()
obj(parser)

Check warning on line 506 in sphinxarg/ext.py

View check run for this annotation

Codecov / codecov/patch

sphinxarg/ext.py#L505-L506

Added lines #L505 - L506 were not covered by tests
else:
parser = obj()
return parser

def run(self):
if 'module' in self.options and 'func' in self.options:
module_name = self.options['module']
Expand All @@ -501,7 +523,7 @@
exec(code, mod)
module_name = None
attr_name = self.options['func']
func = mod[attr_name]
parser = self._get_parser(mod, attr_name)
else:
msg = ':module: and :func: should be specified, or :ref:, or :filename: and :func:'
raise self.error(msg)
Expand All @@ -517,22 +539,8 @@
f'{sys.exc_info()[1]}'
)
raise self.error(msg) from exc
parser = self._get_parser(mod, attr_name)

Check warning on line 542 in sphinxarg/ext.py

View check run for this annotation

Codecov / codecov/patch

sphinxarg/ext.py#L542

Added line #L542 was not covered by tests

if not hasattr(mod, attr_name):
msg = (
f'Module "{module_name}" has no attribute "{attr_name}"\n'
f'Incorrect argparse :module: or :func: values?'
)
raise self.error(msg)
func = getattr(mod, attr_name)

if isinstance(func, ArgumentParser):
parser = func
elif 'passparser' in self.options:
parser = ArgumentParser()
func(parser)
else:
parser = func()
if 'path' not in self.options:
self.options['path'] = ''
path = str(self.options['path'])
Expand Down
15 changes: 15 additions & 0 deletions test/roots/test-default-html/inside-class.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Argparse inside class Foo
#########################

.. argparse::
:filename: test/sample-inside-class.py
:prog: sample-inside-class-foo
:func: Foo.parser

Argparse inside class Foo.Bar
#############################

.. argparse::
:filename: test/sample-inside-class.py
:prog: sample-inside-class-foo-bar
:func: Foo.Bar.parser
17 changes: 17 additions & 0 deletions test/sample-inside-class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import argparse

Check failure on line 1 in test/sample-inside-class.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (N999)

test/sample-inside-class.py:1:1: N999 Invalid module name: 'sample-inside-class'


desc = 'Test parsing of Argparse instances inside classes'

Check failure on line 4 in test/sample-inside-class.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

test/sample-inside-class.py:1:1: I001 Import block is un-sorted or un-formatted

class Foo:

Check failure on line 6 in test/sample-inside-class.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E302)

test/sample-inside-class.py:6:1: E302 Expected 2 blank lines, found 1
parser = argparse.ArgumentParser(prog=f'{__name__}-foo',
description=desc)
parser.add_argument('--foo-arg1', help='foo-arg1 help')
parser.add_argument('--foo-arg2', help='foo-arg2 help')


class Bar:

Check failure on line 13 in test/sample-inside-class.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E303)

test/sample-inside-class.py:13:5: E303 Too many blank lines (2)
parser = argparse.ArgumentParser(prog=f'{__name__}-foo-bar',
description=desc)
parser.add_argument('--foo-bar-arg1', help='foo-bar-arg1 help')
parser.add_argument('--foo-bar-arg2', help='foo-bar-arg2 help')
16 changes: 16 additions & 0 deletions test/test_default_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,22 @@
('.//section/dl/dd/p', 'Default', False),
],
),
(
'inside-class.html',
[
(".//section[@id='argparse-inside-class-foo']/h1", 'Argparse inside class Foo'),

Check failure on line 104 in test/test_default_html.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

test/test_default_html.py:104:96: E501 Line too long (96 > 95)
(".//section[@id='argparse-inside-class-foo']//div[@class='highlight']//span", 'usage'),

Check failure on line 105 in test/test_default_html.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

test/test_default_html.py:105:96: E501 Line too long (104 > 95)
(".//section[@id='Foo.parser-named-arguments']/h2", 'Named Arguments'),
(".//section[@id='Foo.parser-named-arguments']/dl/dt[1]/kbd", '--foo-arg1'),
(".//section[@id='Foo.parser-named-arguments']/dl/dt[2]/kbd", '--foo-arg2'),

(".//section[@id='argparse-inside-class-foo-bar']/h1", 'Argparse inside class Foo.Bar'),

Check failure on line 110 in test/test_default_html.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

test/test_default_html.py:110:96: E501 Line too long (104 > 95)
(".//section[@id='argparse-inside-class-foo-bar']//div[@class='highlight']//span", 'usage'),

Check failure on line 111 in test/test_default_html.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

test/test_default_html.py:111:96: E501 Line too long (108 > 95)
(".//section[@id='Foo.Bar.parser-named-arguments']/h2", 'Named Arguments'),
(".//section[@id='Foo.Bar.parser-named-arguments']/dl/dt[1]/kbd", '--foo-bar-arg1'),

Check failure on line 113 in test/test_default_html.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

test/test_default_html.py:113:96: E501 Line too long (100 > 95)
(".//section[@id='Foo.Bar.parser-named-arguments']/dl/dt[2]/kbd", '--foo-bar-arg2'),
],
),
],
)
@pytest.mark.sphinx('html', testroot='default-html')
Expand Down