From 08f400c6fd9f0863a8bc3b8cf927670e541ab577 Mon Sep 17 00:00:00 2001 From: spacemanspiff2007 <10754716+spacemanspiff2007@users.noreply.github.com> Date: Fri, 15 Jul 2022 11:15:29 +0200 Subject: [PATCH] 0.7 --- doc/configuration.rst | 26 +++++++++++++++++++++++--- readme.md | 4 ++++ requirements.txt | 6 +++--- src/sphinx_exec_code/__version__.py | 2 +- src/sphinx_exec_code/code_exec.py | 15 +++++++++++---- src/sphinx_exec_code/sphinx_api.py | 13 +++++++++---- tests/test_code_exec.py | 14 ++++++++++++++ 7 files changed, 65 insertions(+), 15 deletions(-) diff --git a/doc/configuration.rst b/doc/configuration.rst index 63eca16..d3db30d 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -1,5 +1,15 @@ Installation and Configuration ================================== + +Installation +---------------------------------- + +.. code-block:: + + pip install sphinx-exec-code + + + To use this extension just add it to the ``extensions`` in your ``conf.py`` .. code-block:: @@ -8,7 +18,10 @@ To use this extension just add it to the ``extensions`` in your ``conf.py`` 'sphinx_exec_code', ] -Additionally the following configuration parameters are available: +Configuration +---------------------------------- + +The following configuration parameters are available: .. _config_options: @@ -35,11 +48,17 @@ Additionally the following configuration parameters are available: - | The directory that is used to create the path to the | example files. Defaults to the parent folder of the ``conf.py``. + * - ``exec_code_stdout_encoding`` + - ``str`` + - | Encoding used to decode stdout. + | The default depends on the operating system but should be ``utf-8``. + + If it's a relative path it will be resolved relative to the parent folder of the ``conf.py`` Example: -.. code-block:: +.. code-block:: python exec_code_working_dir = '..' exec_code_folders = ['../my_src'] @@ -50,8 +69,9 @@ The configured values are logged. Log output for Example: -:: +.. code-block:: text [exec-code] Working dir: C:\Python\sphinx-exec-code [exec-code] Folders: C:\Python\sphinx-exec-code\my_src [exec-code] Example dir: C:\Python\sphinx-exec-code\doc + [exec-code] Stdout encoding: utf-8 diff --git a/readme.md b/readme.md index 9d89949..d9fec87 100644 --- a/readme.md +++ b/readme.md @@ -36,6 +36,10 @@ This code will be executed ``` # Changelog +#### 0.7 (15.07.2022) +- Added config parameter to specify stdout encoding +- Only empty lines of the output get trimmed + #### 0.6 (04.04.2022) - Fixed an issue where the line numbers for error messages were not correct diff --git a/requirements.txt b/requirements.txt index 7489cb0..e24fd58 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pytest==7.0.1 -pre-commit==2.17.0 -sphinx==4.4.0 +pytest==7.1.2 +pre-commit==2.20.0 +sphinx==5.0.2 sphinx-rtd-theme==1.0.0 diff --git a/src/sphinx_exec_code/__version__.py b/src/sphinx_exec_code/__version__.py index 27fda16..e220fa9 100644 --- a/src/sphinx_exec_code/__version__.py +++ b/src/sphinx_exec_code/__version__.py @@ -1 +1 @@ -__version__ = '0.6' +__version__ = '0.7' diff --git a/src/sphinx_exec_code/code_exec.py b/src/sphinx_exec_code/code_exec.py index 854aa60..f21d0d3 100644 --- a/src/sphinx_exec_code/code_exec.py +++ b/src/sphinx_exec_code/code_exec.py @@ -1,6 +1,7 @@ import os import subprocess import sys +from itertools import dropwhile from pathlib import Path from typing import Iterable, Optional @@ -10,12 +11,14 @@ WORKING_DIR: Optional[str] = None ADDITIONAL_FOLDERS: Optional[Iterable[str]] = None +STDOUT_ENCODING: str = sys.stdout.encoding -def setup_code_env(cwd: Path, folders: Iterable[Path]): - global WORKING_DIR, ADDITIONAL_FOLDERS +def setup_code_env(cwd: Path, folders: Iterable[Path], encoding: str): + global WORKING_DIR, ADDITIONAL_FOLDERS, STDOUT_ENCODING WORKING_DIR = str(cwd) ADDITIONAL_FOLDERS = tuple(map(str, folders)) + STDOUT_ENCODING = encoding def execute_code(code: str, file: Path, first_loc: int) -> str: @@ -32,7 +35,11 @@ def execute_code(code: str, file: Path, first_loc: int) -> str: if run.returncode != 0: raise CodeException(code, file, first_loc, run.returncode, run.stderr.decode()) from None - ret = (run.stdout.decode() + run.stderr.decode()).strip() + # decode output and drop tailing spaces + ret_str = (run.stdout.decode(encoding=STDOUT_ENCODING) + run.stderr.decode(encoding=STDOUT_ENCODING)).rstrip() + + # drop leading empty lines + ret_lines = list(dropwhile(lambda x: not x.strip(), ret_str.splitlines())) # Normalize newlines - return '\n'.join(ret.splitlines()) + return '\n'.join(ret_lines) diff --git a/src/sphinx_exec_code/sphinx_api.py b/src/sphinx_exec_code/sphinx_api.py index 7c09f32..643fa65 100644 --- a/src/sphinx_exec_code/sphinx_api.py +++ b/src/sphinx_exec_code/sphinx_api.py @@ -1,3 +1,4 @@ +import sys from pathlib import Path from sphinx_exec_code import __version__ @@ -8,6 +9,7 @@ CONF_NAME_CWD = 'exec_code_working_dir' CONF_NAME_DIRS = 'exec_code_folders' CONF_NAME_SAMPLE_DIR = 'exec_code_example_dir' +CONF_NAME_STDOUT_ENCODING = 'exec_code_stdout_encoding' def mk_path(app, obj) -> Path: @@ -22,10 +24,12 @@ def builder_ready(app): cwd = mk_path(app, getattr(app.config, CONF_NAME_CWD)) folders = tuple(mk_path(app, _p) for _p in getattr(app.config, CONF_NAME_DIRS)) example_dir = mk_path(app, getattr(app.config, CONF_NAME_SAMPLE_DIR)) + stdout_encoding = getattr(app.config, CONF_NAME_STDOUT_ENCODING) log.debug(f'[exec-code] Working dir: {cwd}') log.debug(f'[exec-code] Folders: {", ".join(map(str, folders))}') log.debug(f'[exec-code] Example dir: {example_dir}') + log.debug(f'[exec-code] Stdout encoding: {stdout_encoding}') # Ensure dirs are valid if not cwd.is_dir(): @@ -56,7 +60,7 @@ def builder_ready(app): log.warning(f'[exec-code] No Python packages found in {_f}') setup_example_dir(example_dir) - setup_code_env(cwd, folders) + setup_code_env(cwd, folders, stdout_encoding) return None @@ -73,9 +77,10 @@ def setup(app): code_folders.append(str(src_dir)) # config options - app.add_config_value(CONF_NAME_CWD, cwd, 'env',) - app.add_config_value(CONF_NAME_DIRS, code_folders, 'env') - app.add_config_value(CONF_NAME_SAMPLE_DIR, confdir, 'env') + app.add_config_value(CONF_NAME_CWD, cwd, 'env', (Path, str)) + app.add_config_value(CONF_NAME_DIRS, code_folders, 'env', (Path, str)) + app.add_config_value(CONF_NAME_SAMPLE_DIR, confdir, 'env', (Path, str)) + app.add_config_value(CONF_NAME_STDOUT_ENCODING, sys.stdout.encoding, 'env', str) app.connect('builder-inited', builder_ready) app.add_directive('exec_code', ExecCode) diff --git a/tests/test_code_exec.py b/tests/test_code_exec.py index 21a2574..cd5b543 100644 --- a/tests/test_code_exec.py +++ b/tests/test_code_exec.py @@ -21,6 +21,14 @@ def test_print(setup_env): assert output == 'Line1\nLine2' +def test_print_table(setup_env): + code = "\n \n \n\n" \ + "print(' | A | B |')\n" \ + "print(' Col1 | 1 | 2 |')" + output = execute_code(code, 'my_file', 1) + assert output == ' | A | B |\n Col1 | 1 | 2 |' + + def test_err(setup_env): code = "print('Line1')\nprint('Line2')\n1/0" @@ -37,3 +45,9 @@ def test_err(setup_env): ' File "my_file", line 7', 'ZeroDivisionError: division by zero' ] + + +def test_unicode(setup_env): + code = "print('●')" + output = execute_code(code, 'my_file', 1) + assert output == '●'