Skip to content

Commit

Permalink
ci
Browse files Browse the repository at this point in the history
  • Loading branch information
spacemanspiff2007 committed Nov 15, 2024
1 parent b7d6b0d commit 18b0433
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 29 deletions.
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

# -- Project information -----------------------------------------------------
project = 'sphinx-exec-code'
copyright = '2021, spacemanspiff2007'
copyright = '2024, spacemanspiff2007'
author = 'spacemanspiff2007'

# The full version, including alpha/beta/rc tags
Expand Down
23 changes: 17 additions & 6 deletions doc/description.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ for a detailed description

hide/hide_output:
Will hide the corresponding block
name
Define implicit target name that can be referenced by using ref. For example:
name/name_output
Define implicit target name that can be referenced by using ref
caption/caption_output
Will add a caption above the block
linenos/linenos_output
Expand Down Expand Up @@ -183,16 +183,18 @@ With the combination of ``skip`` and ``hide`` it's possible to "simulate" every
Further Examples
------------------------------

This is an example with captions, highlights and name
This is an example with captions, highlights and name.


.. code-block:: python
.. exec_code::
:lineno-start: 5
:emphasize-lines: 1, 3
:emphasize-lines: 1, 4
:caption: This is an important caption
:caption_output: This is an important output caption
:name: my_example_1
:name_output: my_output_1
print('My')
# This is a comment
Expand All @@ -205,10 +207,11 @@ Generated view

.. exec_code::
:lineno-start: 5
:emphasize-lines: 1, 3
:emphasize-lines: 1, 4
:caption: This is an important caption
:caption_output: This is an important output caption
:name: my_example_1
:name_output: my_output_1

print('My')
# This is a comment
Expand All @@ -217,4 +220,12 @@ Generated view

----

See :ref:`this code snippet <my_example_1>` for an example.
Create a link using to the blocks by using the name:

.. code-block:: text
See :ref:`this code snippet <my_example_1>` for an example
See :ref:`this code snippet <my_output_1>` for an example output
See :ref:`this code snippet <my_example_1>` for an example
See :ref:`this code snippet <my_output_1>` for an example output
56 changes: 36 additions & 20 deletions src/sphinx_exec_code/sphinx_spec.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Any, ClassVar, Dict, Final, Tuple

from docutils.nodes import literal_block
from docutils.parsers.rst import directives # type: ignore
from docutils.parsers.rst import directives
from sphinx.directives.code import CodeBlock
from sphinx.util.typing import OptionSpec

Expand All @@ -10,14 +10,17 @@

class SphinxSpecBase:
defaults: ClassVar[Dict[str, str]]
drop_code_block_option: ClassVar[Tuple[str, ...]]

@staticmethod
def _alias_to_name(alias: str) -> str:
def alias_to_name(alias: str) -> str:
raise NotImplementedError()

@staticmethod
def _name_to_alias(name: str) -> str:
def name_to_alias(name: str) -> str:
raise NotImplementedError()

@staticmethod
def post_process_spec(spec: Dict[str, Any], options: Dict[str, Any]) -> None:
raise NotImplementedError()

def __init__(self, spec: Dict[str, Any]) -> None:
Expand All @@ -34,12 +37,13 @@ def set_block_spec(self, block: literal_block) -> None:
def from_options(cls, options: Dict[str, Any]) -> 'SphinxSpecBase':
spec_names = tuple(cls.create_spec().keys())

spec = {cls._alias_to_name(n): v for n, v in cls.defaults.items()}
spec = {cls.alias_to_name(n): v for n, v in cls.defaults.items()}
for name in spec_names:
if name not in options:
continue
spec[cls._alias_to_name(name)] = options[name]
spec[cls.alias_to_name(name)] = options[name]

cls.post_process_spec(spec, options)
return cls(spec=spec)

@classmethod
Expand All @@ -48,17 +52,15 @@ def create_spec(cls) -> OptionSpec:
# spec from CodeBlock
this_spec: OptionSpec = {}
for name, directive in CodeBlock.option_spec.items():
if name in cls.drop_code_block_option:
continue
this_spec[cls._name_to_alias(name)] = directive
this_spec[cls.name_to_alias(name)] = directive

# own flags after the default flags so we overwrite them in case we have duplicate names
for name, default in cls.defaults.items():
# all own options are currently strings
if isinstance(default, str):
this_spec[cls._name_to_alias(name)] = directives.unchanged
this_spec[cls.name_to_alias(name)] = directives.unchanged
elif isinstance(default, bool):
this_spec[cls._name_to_alias(name)] = directives.flag
this_spec[cls.name_to_alias(name)] = directives.flag
else:
msg = f'Unsupported type {type(default)} for default "{name:s}"!'
raise TypeError(msg)
Expand Down Expand Up @@ -88,47 +90,61 @@ def get_specs(options: Dict[str, Any]) -> Tuple['SpecCode', 'SpecOutput']:


class SpecCode(SphinxSpecBase):
drop_code_block_option: ClassVar = ()
defaults: ClassVar = {
'caption': '',
'filename': '',
'hide_code': False, # deprecated 2024 - remove after some time, must come before the new hide flag!
'hide': False,
'language': 'python',
}

@staticmethod
def _alias_to_name(alias: str) -> str:
def alias_to_name(alias: str) -> str:
if alias == 'hide_code':
log.info('The "hide_code" directive is deprecated! Use "hide" instead!')
return 'hide'
return alias

@staticmethod
def _name_to_alias(name: str) -> str:
def name_to_alias(name: str) -> str:
return name

@staticmethod
def post_process_spec(spec: Dict[str, Any], options :Dict[str, Any]) -> None:
return None

def __init__(self, **kwargs: Dict[str, Any]) -> None:
super().__init__(**kwargs)
self.filename: Final[str] = self.spec.pop('filename')


class SpecOutput(SphinxSpecBase):
@staticmethod
def _alias_to_name(alias: str) -> str:
def alias_to_name(alias: str) -> str:
if alias.endswith('_output'):
return alias[:-7]
return alias

@staticmethod
def _name_to_alias(name: str) -> str:
def name_to_alias(name: str) -> str:
if name.endswith('_output'):
return name[:-7]
return name
return name + '_output'

drop_code_block_option: ClassVar = ('name', )
@staticmethod
def post_process_spec(spec: Dict[str, Any], options: Dict[str, Any]) -> None:
# if we have a name for code but not for output we programmatically build it by appending the _output suffix
name_output = SpecOutput.name_to_alias('name')
if name_output in options:
return None

name_code = SpecCode.name_to_alias('name')
if name_code not in options:
return None

# if we have a name for input we create a name for output
spec['name'] = f'{options[name_code]:s}_output'

defaults: ClassVar = {
'caption': '',
'hide': False,
'language': 'none',
}
10 changes: 8 additions & 2 deletions tests/test_sphinx_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_invalid_options() -> None:
'Invalid option: hide-output! '
'Supported: caption, caption_output, class, class_output, dedent, dedent_output, '
'emphasize-lines, emphasize-lines_output, filename, force, force_output, hide, hide_code, hide_output, '
'language, language_output, lineno-start, lineno-start_output, linenos, linenos_output, name'
'language, language_output, lineno-start, lineno-start_output, linenos, linenos_output, name, name_output'
)

with pytest.raises(ValueError) as e: # noqa: PT011
Expand All @@ -41,5 +41,11 @@ def test_invalid_options() -> None:
'Invalid options: caption-output, hide-output! '
'Supported: caption, caption_output, class, class_output, dedent, dedent_output, '
'emphasize-lines, emphasize-lines_output, filename, force, force_output, hide, hide_code, hide_output, '
'language, language_output, lineno-start, lineno-start_output, linenos, linenos_output, name'
'language, language_output, lineno-start, lineno-start_output, linenos, linenos_output, name, name_output'
)


def test_post_process() -> None:
assert SpecOutput.from_options({'name': 'asdf'}).spec == {'name': 'asdf_output'}
assert SpecOutput.from_options({'name_output': 'asdf'}).spec == {'name': 'asdf'}
assert SpecOutput.from_options({'name': '1', 'name_output': '2'}).spec == {'name': '2'}

0 comments on commit 18b0433

Please sign in to comment.