From: <gr...@us...> - 2024-08-15 08:43:44
|
Revision: 9906 http://sourceforge.net/p/docutils/code/9906 Author: grubert Date: 2024-08-15 08:43:38 +0000 (Thu, 15 Aug 2024) Log Message: ----------- rename txt to rst Modified Paths: -------------- trunk/docutils/docs/user/Makefile.docutils-update trunk/docutils/docutils/transforms/references.py trunk/docutils/docutils/writers/latex2e/__init__.py trunk/docutils/docutils/writers/odf_odt/__init__.py trunk/docutils/docutils.conf trunk/docutils/pyproject.toml trunk/docutils/test/functional/expected/compact_lists.html trunk/docutils/test/functional/expected/dangerous.html trunk/docutils/test/functional/expected/field_name_limit.html trunk/docutils/test/functional/expected/latex_cornercases.tex trunk/docutils/test/functional/expected/latex_memoir.tex trunk/docutils/test/functional/expected/math_experiments_mathml_blahtexml.html trunk/docutils/test/functional/expected/math_experiments_mathml_pandoc.html trunk/docutils/test/functional/expected/math_experiments_mathml_ttm.html trunk/docutils/test/functional/expected/mathematics_mathml_blahtexml.html trunk/docutils/test/functional/expected/mathematics_mathml_pandoc.html trunk/docutils/test/functional/expected/mathematics_mathml_ttm.html trunk/docutils/test/functional/expected/standalone_rst_docutils_xml.xml trunk/docutils/test/functional/expected/standalone_rst_html4css1.html trunk/docutils/test/functional/expected/standalone_rst_html5.html trunk/docutils/test/functional/expected/standalone_rst_latex.tex trunk/docutils/test/functional/expected/standalone_rst_xetex.tex trunk/docutils/test/functional/tests/compact_lists.py trunk/docutils/test/functional/tests/dangerous.py trunk/docutils/test/functional/tests/field_name_limit.py trunk/docutils/test/functional/tests/footnotes_html5.py trunk/docutils/test/functional/tests/latex_babel.py trunk/docutils/test/functional/tests/latex_cornercases.py trunk/docutils/test/functional/tests/latex_cyrillic.py trunk/docutils/test/functional/tests/latex_docinfo.py trunk/docutils/test/functional/tests/latex_leavevmode.py trunk/docutils/test/functional/tests/latex_literal_block.py trunk/docutils/test/functional/tests/latex_literal_block_fancyvrb.py trunk/docutils/test/functional/tests/latex_literal_block_listings.py trunk/docutils/test/functional/tests/latex_literal_block_verbatim.py trunk/docutils/test/functional/tests/latex_literal_block_verbatimtab.py trunk/docutils/test/functional/tests/latex_memoir.py trunk/docutils/test/functional/tests/math_output_html.py trunk/docutils/test/functional/tests/math_output_latex.py trunk/docutils/test/functional/tests/math_output_mathjax.py trunk/docutils/test/functional/tests/math_output_mathml.py trunk/docutils/test/functional/tests/misc_rst_html4css1.py trunk/docutils/test/functional/tests/misc_rst_html5.py trunk/docutils/test/functional/tests/pep_html.py trunk/docutils/test/functional/tests/standalone_rst_docutils_xml.py trunk/docutils/test/functional/tests/standalone_rst_html4css1.py trunk/docutils/test/functional/tests/standalone_rst_html5.py trunk/docutils/test/functional/tests/standalone_rst_html5_tuftig.py trunk/docutils/test/functional/tests/standalone_rst_latex.py trunk/docutils/test/functional/tests/standalone_rst_manpage.py trunk/docutils/test/functional/tests/standalone_rst_pseudoxml.py trunk/docutils/test/functional/tests/standalone_rst_s5_html_1.py trunk/docutils/test/functional/tests/standalone_rst_s5_html_2.py trunk/docutils/test/functional/tests/standalone_rst_xetex.py trunk/docutils/test/functional/tests/xetex_cyrillic.py trunk/docutils/test/test_CLI.py trunk/docutils/test/test_dependencies.py trunk/docutils/test/test_functional.py trunk/docutils/test/test_io.py trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py trunk/docutils/test/test_parsers/test_rst/test_directives/test_raw.py trunk/docutils/test/test_parsers/test_rst/test_directives/test_tables.py trunk/docutils/test/test_parsers/test_rst/test_root_prefix.py trunk/docutils/test/test_parsers/test_rst/test_source_line.py trunk/docutils/test/test_parsers/test_rst/test_tables.py trunk/docutils/test/test_publisher.py trunk/docutils/test/test_readers/test_pep/test_inline_markup.py trunk/docutils/test/test_settings.py trunk/docutils/test/test_transforms/test_hyperlinks.py trunk/docutils/test/test_utils/test__init__.py trunk/docutils/test/test_utils/test_math/test_tex2mathml_extern.py trunk/docutils/test/test_writers/test_html4css1_template.py trunk/docutils/test/test_writers/test_html5_template.py trunk/docutils/test/test_writers/test_odt.py trunk/docutils/tools/dev/profile_docutils.py trunk/docutils/tools/dev/unicode2rstsubs.py trunk/docutils/tools/test/test_buildhtml.py Added Paths: ----------- trunk/docutils/BUGS.rst trunk/docutils/COPYING.rst trunk/docutils/FAQ.rst trunk/docutils/HISTORY.rst trunk/docutils/README.rst trunk/docutils/RELEASE-NOTES.rst trunk/docutils/THANKS.rst trunk/docutils/docs/api/publisher.rst trunk/docutils/docs/api/runtime-settings.rst trunk/docutils/docs/api/transforms.rst trunk/docutils/docs/dev/distributing.rst trunk/docutils/docs/dev/enthought-plan.rst trunk/docutils/docs/dev/enthought-rfp.rst trunk/docutils/docs/dev/hacking.rst trunk/docutils/docs/dev/policies.rst trunk/docutils/docs/dev/pysource.rst trunk/docutils/docs/dev/release.rst trunk/docutils/docs/dev/repository.rst trunk/docutils/docs/dev/rst/alternatives.rst trunk/docutils/docs/dev/rst/problems.rst trunk/docutils/docs/dev/runtime-settings-processing.rst trunk/docutils/docs/dev/semantics.rst trunk/docutils/docs/dev/testing.rst trunk/docutils/docs/dev/todo.rst trunk/docutils/docs/dev/website.rst trunk/docutils/docs/header.rst trunk/docutils/docs/header0.rst trunk/docutils/docs/header2.rst trunk/docutils/docs/howto/cmdline-tool.rst trunk/docutils/docs/howto/html-stylesheets.rst trunk/docutils/docs/howto/i18n.rst trunk/docutils/docs/howto/rst-directives.rst trunk/docutils/docs/howto/rst-roles.rst trunk/docutils/docs/howto/security.rst trunk/docutils/docs/index.rst trunk/docutils/docs/peps/pep-0256.rst trunk/docutils/docs/peps/pep-0257.rst trunk/docutils/docs/peps/pep-0258.rst trunk/docutils/docs/peps/pep-0287.rst trunk/docutils/docs/ref/doctree.rst trunk/docutils/docs/ref/rst/definitions.rst trunk/docutils/docs/ref/rst/directives.rst trunk/docutils/docs/ref/rst/history.rst trunk/docutils/docs/ref/rst/introduction.rst trunk/docutils/docs/ref/rst/mathematics.rst trunk/docutils/docs/ref/rst/restructuredtext.rst trunk/docutils/docs/ref/rst/roles.rst trunk/docutils/docs/user/config.rst trunk/docutils/docs/user/emacs.rst trunk/docutils/docs/user/html.rst trunk/docutils/docs/user/latex.rst trunk/docutils/docs/user/links.rst trunk/docutils/docs/user/mailing-lists.rst trunk/docutils/docs/user/manpage.rst trunk/docutils/docs/user/odt.rst trunk/docutils/docs/user/rst/cheatsheet.rst trunk/docutils/docs/user/rst/demo.rst trunk/docutils/docs/user/rst/quickstart.rst trunk/docutils/docs/user/slide-shows.rst trunk/docutils/docs/user/smartquotes.rst trunk/docutils/docs/user/todo-lists.rst trunk/docutils/docs/user/tools.rst trunk/docutils/docutils/writers/s5_html/themes/README.rst trunk/docutils/licenses/BSD-0-Clause.rst trunk/docutils/licenses/BSD-2-Clause.rst trunk/docutils/licenses/ZPL-2-1.rst trunk/docutils/licenses/gpl-3-0.rst trunk/docutils/test/data/config_1.rst trunk/docutils/test/data/config_2.rst trunk/docutils/test/data/config_encoding.rst trunk/docutils/test/data/config_encoding_2.rst trunk/docutils/test/data/config_list.rst trunk/docutils/test/data/config_list_2.rst trunk/docutils/test/data/config_old.rst trunk/docutils/test/data/config_syntax_error.rst trunk/docutils/test/data/csv_dep.rst trunk/docutils/test/data/dependencies.rst trunk/docutils/test/data/full-template.rst trunk/docutils/test/data/help/docutils.rst trunk/docutils/test/data/help/rst2html.rst trunk/docutils/test/data/help/rst2latex.rst trunk/docutils/test/data/include.rst trunk/docutils/test/data/latin1.rst trunk/docutils/test/data/latin2.rst trunk/docutils/test/data/raw.rst trunk/docutils/test/data/stylesheet.rst trunk/docutils/test/data/utf-16-le-sig.rst trunk/docutils/test/data/utf-8-sig.rst trunk/docutils/test/data/utf8.rst trunk/docutils/test/functional/README.rst trunk/docutils/test/functional/expected/standalone_rst_pseudoxml.rst trunk/docutils/test/functional/input/compact_lists.rst trunk/docutils/test/functional/input/cyrillic.rst trunk/docutils/test/functional/input/dangerous.rst trunk/docutils/test/functional/input/data/classes_latex.rst trunk/docutils/test/functional/input/data/comprehensive-math-test.rst trunk/docutils/test/functional/input/data/custom_roles.rst trunk/docutils/test/functional/input/data/custom_roles_latex.rst trunk/docutils/test/functional/input/data/embed_images.rst trunk/docutils/test/functional/input/data/errors.rst trunk/docutils/test/functional/input/data/header_footer.rst trunk/docutils/test/functional/input/data/html5-features.rst trunk/docutils/test/functional/input/data/html5-text-level-tags.rst trunk/docutils/test/functional/input/data/hyperlinking.rst trunk/docutils/test/functional/input/data/latex-problematic.rst trunk/docutils/test/functional/input/data/latex_encoding.rst trunk/docutils/test/functional/input/data/list_table.rst trunk/docutils/test/functional/input/data/math.rst trunk/docutils/test/functional/input/data/math_experiments.rst trunk/docutils/test/functional/input/data/nonalphanumeric.rst trunk/docutils/test/functional/input/data/option_lists.rst trunk/docutils/test/functional/input/data/section_titles.rst trunk/docutils/test/functional/input/data/standard.rst trunk/docutils/test/functional/input/data/svg_images.rst trunk/docutils/test/functional/input/data/swf_images.rst trunk/docutils/test/functional/input/data/table_colspan.rst trunk/docutils/test/functional/input/data/table_complex.rst trunk/docutils/test/functional/input/data/table_rowspan.rst trunk/docutils/test/functional/input/data/tables_latex.rst trunk/docutils/test/functional/input/data/unicode.rst trunk/docutils/test/functional/input/data/urls.rst trunk/docutils/test/functional/input/data/video.rst trunk/docutils/test/functional/input/field_list.rst trunk/docutils/test/functional/input/footnotes.rst trunk/docutils/test/functional/input/latex_babel.rst trunk/docutils/test/functional/input/latex_cornercases.rst trunk/docutils/test/functional/input/latex_docinfo.rst trunk/docutils/test/functional/input/latex_leavevmode.rst trunk/docutils/test/functional/input/latex_literal_block.rst trunk/docutils/test/functional/input/misc_rst_html4css1.rst trunk/docutils/test/functional/input/misc_rst_html5.rst trunk/docutils/test/functional/input/odt_basic.rst trunk/docutils/test/functional/input/odt_classifier.rst trunk/docutils/test/functional/input/odt_contents.rst trunk/docutils/test/functional/input/odt_custom_headfoot.rst trunk/docutils/test/functional/input/odt_footnotes.rst trunk/docutils/test/functional/input/odt_header_footer.rst trunk/docutils/test/functional/input/odt_image.rst trunk/docutils/test/functional/input/odt_literal_block.rst trunk/docutils/test/functional/input/odt_nested_class.rst trunk/docutils/test/functional/input/odt_no_class.rst trunk/docutils/test/functional/input/odt_raw.rst trunk/docutils/test/functional/input/odt_tables1.rst trunk/docutils/test/functional/input/odt_unnested_class.rst trunk/docutils/test/functional/input/pep_html.rst trunk/docutils/test/functional/input/rst_html5_tuftig.rst trunk/docutils/test/functional/input/simple.rst trunk/docutils/test/functional/input/standalone_rst_docutils_xml.rst trunk/docutils/test/functional/input/standalone_rst_html4css1.rst trunk/docutils/test/functional/input/standalone_rst_html5.rst trunk/docutils/test/functional/input/standalone_rst_latex.rst trunk/docutils/test/functional/input/standalone_rst_manpage.rst trunk/docutils/test/functional/input/standalone_rst_pseudoxml.rst trunk/docutils/test/functional/input/standalone_rst_s5_html.rst trunk/docutils/test/functional/input/standalone_rst_xetex.rst trunk/docutils/test/functional/output/README.rst trunk/docutils/test/test_parsers/test_rst/includes/include14.rst trunk/docutils/test/test_parsers/test_rst/includes/include9.rst trunk/docutils/test/test_parsers/test_rst/test_directives/empty.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include 11.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include1.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include10.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include12.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include13.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include2.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include3.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include8.rst trunk/docutils/test/test_parsers/test_rst/test_directives/include_literal.rst trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include14.rst trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include15.rst trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include16.rst trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include4.rst trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include5.rst trunk/docutils/test/test_parsers/test_rst/test_directives/includes/more/include6.rst trunk/docutils/test/test_parsers/test_rst/test_directives/includes/sibling/include7.rst trunk/docutils/test/test_parsers/test_rst/test_directives/raw1.rst trunk/docutils/tools/dev/README.rst trunk/docutils/tools/editors/README.rst trunk/docutils/tools/editors/emacs/README.rst trunk/docutils/tools/editors/emacs/tests/README.rst Removed Paths: ------------- trunk/docutils/BUGS.txt trunk/docutils/COPYING.txt trunk/docutils/FAQ.txt trunk/docutils/HISTORY.txt trunk/docutils/README.txt trunk/docutils/RELEASE-NOTES.txt trunk/docutils/THANKS.txt trunk/docutils/docs/api/publisher.txt trunk/docutils/docs/api/runtime-settings.txt trunk/docutils/docs/api/transforms.txt trunk/docutils/docs/dev/distributing.txt trunk/docutils/docs/dev/enthought-plan.txt trunk/docutils/docs/dev/enthought-rfp.txt trunk/docutils/docs/dev/hacking.txt trunk/docutils/docs/dev/policies.txt trunk/docutils/docs/dev/pysource.txt trunk/docutils/docs/dev/release.txt trunk/docutils/docs/dev/repository.txt trunk/docutils/docs/dev/rst/alternatives.txt trunk/docutils/docs/dev/rst/problems.txt trunk/docutils/docs/dev/runtime-settings-processing.txt trunk/docutils/docs/dev/semantics.txt trunk/docutils/docs/dev/testing.txt trunk/docutils/docs/dev/todo.txt trunk/docutils/docs/dev/website.txt trunk/docutils/docs/header.txt trunk/docutils/docs/header0.txt trunk/docutils/docs/header2.txt trunk/docutils/docs/howto/cmdline-tool.txt trunk/docutils/docs/howto/html-stylesheets.txt trunk/docutils/docs/howto/i18n.txt trunk/docutils/docs/howto/rst-directives.txt trunk/docutils/docs/howto/rst-roles.txt trunk/docutils/docs/howto/security.txt trunk/docutils/docs/index.txt trunk/docutils/docs/peps/pep-0256.txt trunk/docutils/docs/peps/pep-0257.txt trunk/docutils/docs/peps/pep-0258.txt trunk/docutils/docs/peps/pep-0287.txt trunk/docutils/docs/ref/doctree.txt trunk/docutils/docs/ref/rst/definitions.txt trunk/docutils/docs/ref/rst/directives.txt trunk/docutils/docs/ref/rst/history.txt trunk/docutils/docs/ref/rst/introduction.txt trunk/docutils/docs/ref/rst/mathematics.txt trunk/docutils/docs/ref/rst/restructuredtext.txt trunk/docutils/docs/ref/rst/roles.txt trunk/docutils/docs/user/config.txt trunk/docutils/docs/user/emacs.txt trunk/docutils/docs/user/html.txt trunk/docutils/docs/user/latex.txt trunk/docutils/docs/user/links.txt trunk/docutils/docs/user/mailing-lists.txt trunk/docutils/docs/user/manpage.txt trunk/docutils/docs/user/odt.txt trunk/docutils/docs/user/rst/cheatsheet.txt trunk/docutils/docs/user/rst/demo.txt trunk/docutils/docs/user/rst/quickstart.txt trunk/docutils/docs/user/slide-shows.txt trunk/docutils/docs/user/smartquotes.txt trunk/docutils/docs/user/todo-lists.txt trunk/docutils/docs/user/tools.txt trunk/docutils/docutils/writers/s5_html/themes/README.txt trunk/docutils/licenses/BSD-0-Clause.txt trunk/docutils/licenses/BSD-2-Clause.txt trunk/docutils/licenses/ZPL-2-1.txt trunk/docutils/licenses/gpl-3-0.txt trunk/docutils/test/data/config_1.txt trunk/docutils/test/data/config_2.txt trunk/docutils/test/data/config_encoding.txt trunk/docutils/test/data/config_encoding_2.txt trunk/docutils/test/data/config_list.txt trunk/docutils/test/data/config_list_2.txt trunk/docutils/test/data/config_old.txt trunk/docutils/test/data/config_syntax_error.txt trunk/docutils/test/data/csv_dep.txt trunk/docutils/test/data/dependencies.txt trunk/docutils/test/data/full-template.txt trunk/docutils/test/data/help/docutils.txt trunk/docutils/test/data/help/rst2html.txt trunk/docutils/test/data/help/rst2latex.txt trunk/docutils/test/data/include.txt trunk/docutils/test/data/latin1.txt trunk/docutils/test/data/latin2.txt trunk/docutils/test/data/raw.txt trunk/docutils/test/data/stylesheet.txt trunk/docutils/test/data/utf-16-le-sig.txt trunk/docutils/test/data/utf-8-sig.txt trunk/docutils/test/data/utf8.txt trunk/docutils/test/functional/README.txt trunk/docutils/test/functional/expected/standalone_rst_pseudoxml.txt trunk/docutils/test/functional/input/compact_lists.txt trunk/docutils/test/functional/input/cyrillic.txt trunk/docutils/test/functional/input/dangerous.txt trunk/docutils/test/functional/input/data/classes_latex.txt trunk/docutils/test/functional/input/data/comprehensive-math-test.txt trunk/docutils/test/functional/input/data/custom_roles.txt trunk/docutils/test/functional/input/data/custom_roles_latex.txt trunk/docutils/test/functional/input/data/embed_images.txt trunk/docutils/test/functional/input/data/errors.txt trunk/docutils/test/functional/input/data/header_footer.txt trunk/docutils/test/functional/input/data/html5-features.txt trunk/docutils/test/functional/input/data/html5-text-level-tags.txt trunk/docutils/test/functional/input/data/hyperlinking.txt trunk/docutils/test/functional/input/data/latex-problematic.txt trunk/docutils/test/functional/input/data/latex_encoding.txt trunk/docutils/test/functional/input/data/list_table.txt trunk/docutils/test/functional/input/data/math.txt trunk/docutils/test/functional/input/data/math_experiments.txt trunk/docutils/test/functional/input/data/nonalphanumeric.txt trunk/docutils/test/functional/input/data/option_lists.txt trunk/docutils/test/functional/input/data/section_titles.txt trunk/docutils/test/functional/input/data/standard.txt trunk/docutils/test/functional/input/data/svg_images.txt trunk/docutils/test/functional/input/data/swf_images.txt trunk/docutils/test/functional/input/data/table_colspan.txt trunk/docutils/test/functional/input/data/table_complex.txt trunk/docutils/test/functional/input/data/table_rowspan.txt trunk/docutils/test/functional/input/data/tables_latex.txt trunk/docutils/test/functional/input/data/unicode.txt trunk/docutils/test/functional/input/data/urls.txt trunk/docutils/test/functional/input/data/video.txt trunk/docutils/test/functional/input/field_list.txt trunk/docutils/test/functional/input/footnotes.txt trunk/docutils/test/functional/input/latex_babel.txt trunk/docutils/test/functional/input/latex_cornercases.txt trunk/docutils/test/functional/input/latex_docinfo.txt trunk/docutils/test/functional/input/latex_leavevmode.txt trunk/docutils/test/functional/input/latex_literal_block.txt trunk/docutils/test/functional/input/misc_rst_html4css1.txt trunk/docutils/test/functional/input/misc_rst_html5.txt trunk/docutils/test/functional/input/odt_basic.txt trunk/docutils/test/functional/input/odt_classifier.txt trunk/docutils/test/functional/input/odt_contents.txt trunk/docutils/test/functional/input/odt_custom_headfoot.txt trunk/docutils/test/functional/input/odt_footnotes.txt trunk/docutils/test/functional/input/odt_header_footer.txt trunk/docutils/test/functional/input/odt_image.txt trunk/docutils/test/functional/input/odt_literal_block.txt trunk/docutils/test/functional/input/odt_nested_class.txt trunk/docutils/test/functional/input/odt_no_class.txt trunk/docutils/test/functional/input/odt_raw.txt trunk/docutils/test/functional/input/odt_tables1.txt trunk/docutils/test/functional/input/odt_unnested_class.txt trunk/docutils/test/functional/input/pep_html.txt trunk/docutils/test/functional/input/rst_html5_tuftig.txt trunk/docutils/test/functional/input/simple.txt trunk/docutils/test/functional/input/standalone_rst_docutils_xml.txt trunk/docutils/test/functional/input/standalone_rst_html4css1.txt trunk/docutils/test/functional/input/standalone_rst_html5.txt trunk/docutils/test/functional/input/standalone_rst_latex.txt trunk/docutils/test/functional/input/standalone_rst_manpage.txt trunk/docutils/test/functional/input/standalone_rst_pseudoxml.txt trunk/docutils/test/functional/input/standalone_rst_s5_html.txt trunk/docutils/test/functional/input/standalone_rst_xetex.txt trunk/docutils/test/functional/output/README.txt trunk/docutils/test/test_parsers/test_rst/includes/include14.txt trunk/docutils/test/test_parsers/test_rst/includes/include9.txt trunk/docutils/test/test_parsers/test_rst/test_directives/empty.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include 11.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include1.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include10.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include12.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include13.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include2.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include3.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include8.txt trunk/docutils/test/test_parsers/test_rst/test_directives/include_literal.txt trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include14.txt trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include15.txt trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include16.txt trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include4.txt trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include5.txt trunk/docutils/test/test_parsers/test_rst/test_directives/includes/more/include6.txt trunk/docutils/test/test_parsers/test_rst/test_directives/includes/sibling/include7.txt trunk/docutils/test/test_parsers/test_rst/test_directives/raw1.txt trunk/docutils/tools/dev/README.txt trunk/docutils/tools/editors/README.txt trunk/docutils/tools/editors/emacs/README.txt trunk/docutils/tools/editors/emacs/tests/README.txt Copied: trunk/docutils/BUGS.rst (from rev 9905, trunk/docutils/BUGS.txt) =================================================================== --- trunk/docutils/BUGS.rst (rev 0) +++ trunk/docutils/BUGS.rst 2024-08-15 08:43:38 UTC (rev 9906) @@ -0,0 +1,295 @@ +.. include:: docs/header0.rst + +================ + Docutils_ Bugs +================ + +:Author: David Goodger; open to all Docutils developers +:Contact: go...@py... +:Date: $Date$ +:Revision: $Revision$ +:Copyright: This document has been placed in the public domain. + +.. _Docutils: https://docutils.sourceforge.io/ + + +Bugs in Docutils?!? Yes, we do have a few. Some are old-timers that +tend to stay in the shadows and don't bother anybody. Once in a while +new bugs are born. From time to time some bugs (new and old) crawl +out into the light and must be dealt with. Icky. + +This document describes how to report a bug, and lists known bugs. + +.. contents:: + + +How To Report A Bug +=================== + +If you think you've discovered a bug, please read through these +guidelines before reporting it. + +First, make sure it's a new bug: + +* Please check the list of `known bugs`_ below and the `SourceForge + Bug Tracker`_ to see if it has already been reported. + +* Are you using the very latest version of Docutils? The bug may have + already been fixed. Please get the latest version of Docutils from + the repository_ or from the current snapshot_ and check again. Even + if your bug has not been fixed, others probably have, and you're + better off with the most up-to-date code. + + If you don't have time to check the latest snapshot, please report + the bug anyway. We'd rather tell you that it's already fixed than + miss reports of unfixed bugs. + +* If Docutils does not behave the way you expect, look in the + documentation_ (don't forget the FAQ_!) and `mailing list archives`_ + for evidence that it should behave the way you expect. + +If you're not sure, please ask on the Docutils-users_ mailing list +first. + +--------------------------------------------------------------------- + +If it's a new bug, the most important thing you can do is to write a +simple description and a recipe that reproduces the bug. Try to +create a `minimal example`_ that demonstrates the bug. The easier you +make it to understand and track down the bug, the more likely a fix +will be. + +.. _minimal example: + +.. sidebar:: minimal example + + A `minimal working example` is a complete example which is as as small and + simple as possible. It should be complete and working, so that + + * you cannot accidentally omit information important to diagnosing + the problem and + * the person responding can just copy-and-paste the code to try it out. + + To construct an example which is as small as possible, the rule + quite simple: *remove/leave out anything which is not necessary*. + + See also: `What is a minimal working example?`__, `LaTeX FAQ`__ + + __ http://www.minimalbeispiel.de/mini-en.html + __ http://www.tex.ac.uk/cgi-bin/texfaq2html?label=minxampl + +Now you're ready to write the bug report. Please include: + +* A clear description of the bug. Describe how you expected Docutils + to behave, and contrast that with how it actually behaved. While + the bug may seem obvious to you, it may not be so obvious to someone + else, so it's best to avoid a guessing game. + +* A complete description of the environment in which you reproduced + the bug: + + - Your operating system & version. + - The version of Python (``python -V``). + - The version of Docutils (use the "-V" option to most Docutils + front-end tools). + - Any private modifications you made to Docutils. + - Anything else that could possibly be relevant. Err on the side + of too much information, rather than too little. + +* A literal transcript of the *exact* command you ran, and the *exact* + output. Use the "--traceback" option to get a complete picture. + +* The exact input and output files. Create a `minimal example`_ + of the failing behaviour — it is better to attach complete files + to your bug report than to include just a summary or excerpt. + +* If you also want to include speculation as to the cause, and even a + patch to fix the bug, that would be great! + +The best place to send your bug report is to the `SourceForge Bug +Tracker`_. That way, it won't be misplaced or forgotten. In fact, an +open bug report on SourceForge is a constant irritant that begs to be +squashed. + +Thank you! + +(This section was inspired by the `Subversion project's`__ BUGS__ +file.) + +__ http://subversion.tigris.org/ +__ http://svn.collab.net/viewcvs/svn/trunk/BUGS?view=markup + +.. _repository: docs/dev/repository.html +.. _snapshot: https://docutils.sourceforge.io/#download +.. _documentation: docs/ +.. _FAQ: FAQ.html +.. _mailing list archives: https://docutils.sourceforge.io/#mailing-lists +.. _Docutils-users: docs/user/mailing-lists.html#docutils-users +.. _SourceForge Bug Tracker: + https://sourceforge.net/p/docutils/bugs/ + + +Known Bugs +========== + +Also see the `SourceForge Bug Tracker`_. + +* .. _error reporting: + + Calling rst2s5 with a non-existent theme (``--theme + does_not_exist``) + causes exceptions. Such errors should be handled more gracefully. + +* The "stylesheet" setting (a URL, to be used verbatim) should be + allowed to be combined with "embed_stylesheet". The stylesheet data + should be read in using urllib. There was an assumption that a + stylesheet to be embedded should exist as a file on the local + system, and only the "stylesheet_path" setting should be used. + +* ``utils.relative_path()`` sometimes returns absolute _`paths on + Windows` (like ``C:/test/foo.css``) where it could have chosen a + relative path. + + Furthermore, absolute pathnames are inserted verbatim, like + ``href="C:/test/foo.css"`` instead of + ``href="file:///C:/test/foo.css"``. + + .. gmane web interface is down. + TODO: find this article in the Sourceforge mail archives + For details, see `this posting by Alan G. Isaac + <http://article.gmane.org/gmane.text.docutils.user/1569>`_. + +* Footnote label "5" should be "4" when processing the following + input:: + + ref [#abc]_ [#]_ [1]_ [#4]_ + + .. [#abc] footnote + .. [#] two + .. [1] one + .. [#4] four + + Output:: + + <document source="<stdin>"> + <paragraph> + ref + <footnote_reference auto="1" ids="id1" refid="abc"> + 2 + + <footnote_reference auto="1" ids="id2" refid="id5"> + 3 + + <footnote_reference ids="id3" refid="id6"> + 1 + + <footnote_reference auto="1" ids="id4" refid="id7"> + 5 + <footnote auto="1" backrefs="id1" ids="abc" names="abc"> + <label> + 2 + <paragraph> + footnote + <footnote auto="1" backrefs="id2" ids="id5" names="3"> + <label> + 3 + <paragraph> + two + <footnote backrefs="id3" ids="id6" names="1"> + <label> + 1 + <paragraph> + one + <footnote auto="1" backrefs="id4" ids="id7" names="4"> + <label> + 5 + <paragraph> + four + +* IDs are based on names. Explicit hyperlink targets have priority + over implicit targets. But if an explicit target comes after an + implicit target with the same name, the ID of the first (implicit) + target remains based on the implicit name. Since HTML fragment + identifiers are based on the IDs, the first target keeps the name. + For example:: + + .. contents:: + + Section + ======= + + .. _contents: + + Subsection + ---------- + + text with a reference to contents_ and section_ + + .. _section: + + This paragraph is explicitly targeted with the name "section". + + When processed to HTML, the 2 internal hyperlinks (to "contents" & + "section") will work fine, but hyperlinks from outside the document + using ``href="...#contents"`` and ``href="...#section"`` won't work. + Such external links will connect to the implicit targets (table of + contents and "Section" title) instead of the explicit targets + ("Subsection" title and last paragraph). + + Hyperlink targets with duplicate names should be assigned new IDs + unrelated to the target names (i.e., "id"-prefix serial IDs). + +* The "contents" ID of the local table of contents in + ``test/functional/expected/standalone_rst_pseudoxml.rst`` is lost in + the HTML output at + ``test/functional/expected/standalone_rst_html4css1.html``. + +* _`Blank first columns` in simple tables with explicit row separators + silently swallow their input. They should at least produce system + error messages. But, with explicit row separators, the meaning is + unambiguous and ought to be supported:: + + ============== ========== + Table with row separators + ============== ========== + and blank + -------------- ---------- + entries + -------------- ---------- + in first + -------------- ---------- + columns. + ============== ========== + + Added a commented-out test case to + test/test_parsers/test_rst/test_SimpleTableParser.py. + +* _`Footnote references with hyperlink targets` cause a possibly + invalid node tree and make the HTML writer crash:: + + $ rst2pseudoxml + [1]_ + + .. _1: URI + <document source="<stdin>"> + <paragraph> + <footnote_reference ids="id1" refuri="URI"> + 1 + <target ids="id2" names="1" refuri="URI"> + +* Anonymous references have "name" attributes. Should they? Are they + used? See ``test/test_parsers/test_rst/test_inline_markup.py``. + +* <reference> elements have a "name" attribute, not "names". The + attribute should be "names"; this is an inconsistency. + + +.. Emacs settings + + Local Variables: + mode: indented-text + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + End: Deleted: trunk/docutils/BUGS.txt =================================================================== --- trunk/docutils/BUGS.txt 2024-08-15 07:31:04 UTC (rev 9905) +++ trunk/docutils/BUGS.txt 2024-08-15 08:43:38 UTC (rev 9906) @@ -1,295 +0,0 @@ -.. include:: docs/header0.txt - -================ - Docutils_ Bugs -================ - -:Author: David Goodger; open to all Docutils developers -:Contact: go...@py... -:Date: $Date$ -:Revision: $Revision$ -:Copyright: This document has been placed in the public domain. - -.. _Docutils: https://docutils.sourceforge.io/ - - -Bugs in Docutils?!? Yes, we do have a few. Some are old-timers that -tend to stay in the shadows and don't bother anybody. Once in a while -new bugs are born. From time to time some bugs (new and old) crawl -out into the light and must be dealt with. Icky. - -This document describes how to report a bug, and lists known bugs. - -.. contents:: - - -How To Report A Bug -=================== - -If you think you've discovered a bug, please read through these -guidelines before reporting it. - -First, make sure it's a new bug: - -* Please check the list of `known bugs`_ below and the `SourceForge - Bug Tracker`_ to see if it has already been reported. - -* Are you using the very latest version of Docutils? The bug may have - already been fixed. Please get the latest version of Docutils from - the repository_ or from the current snapshot_ and check again. Even - if your bug has not been fixed, others probably have, and you're - better off with the most up-to-date code. - - If you don't have time to check the latest snapshot, please report - the bug anyway. We'd rather tell you that it's already fixed than - miss reports of unfixed bugs. - -* If Docutils does not behave the way you expect, look in the - documentation_ (don't forget the FAQ_!) and `mailing list archives`_ - for evidence that it should behave the way you expect. - -If you're not sure, please ask on the Docutils-users_ mailing list -first. - ---------------------------------------------------------------------- - -If it's a new bug, the most important thing you can do is to write a -simple description and a recipe that reproduces the bug. Try to -create a `minimal example`_ that demonstrates the bug. The easier you -make it to understand and track down the bug, the more likely a fix -will be. - -.. _minimal example: - -.. sidebar:: minimal example - - A `minimal working example` is a complete example which is as as small and - simple as possible. It should be complete and working, so that - - * you cannot accidentally omit information important to diagnosing - the problem and - * the person responding can just copy-and-paste the code to try it out. - - To construct an example which is as small as possible, the rule - quite simple: *remove/leave out anything which is not necessary*. - - See also: `What is a minimal working example?`__, `LaTeX FAQ`__ - - __ http://www.minimalbeispiel.de/mini-en.html - __ http://www.tex.ac.uk/cgi-bin/texfaq2html?label=minxampl - -Now you're ready to write the bug report. Please include: - -* A clear description of the bug. Describe how you expected Docutils - to behave, and contrast that with how it actually behaved. While - the bug may seem obvious to you, it may not be so obvious to someone - else, so it's best to avoid a guessing game. - -* A complete description of the environment in which you reproduced - the bug: - - - Your operating system & version. - - The version of Python (``python -V``). - - The version of Docutils (use the "-V" option to most Docutils - front-end tools). - - Any private modifications you made to Docutils. - - Anything else that could possibly be relevant. Err on the side - of too much information, rather than too little. - -* A literal transcript of the *exact* command you ran, and the *exact* - output. Use the "--traceback" option to get a complete picture. - -* The exact input and output files. Create a `minimal example`_ - of the failing behaviour — it is better to attach complete files - to your bug report than to include just a summary or excerpt. - -* If you also want to include speculation as to the cause, and even a - patch to fix the bug, that would be great! - -The best place to send your bug report is to the `SourceForge Bug -Tracker`_. That way, it won't be misplaced or forgotten. In fact, an -open bug report on SourceForge is a constant irritant that begs to be -squashed. - -Thank you! - -(This section was inspired by the `Subversion project's`__ BUGS__ -file.) - -__ http://subversion.tigris.org/ -__ http://svn.collab.net/viewcvs/svn/trunk/BUGS?view=markup - -.. _repository: docs/dev/repository.html -.. _snapshot: https://docutils.sourceforge.io/#download -.. _documentation: docs/ -.. _FAQ: FAQ.html -.. _mailing list archives: https://docutils.sourceforge.io/#mailing-lists -.. _Docutils-users: docs/user/mailing-lists.html#docutils-users -.. _SourceForge Bug Tracker: - https://sourceforge.net/p/docutils/bugs/ - - -Known Bugs -========== - -Also see the `SourceForge Bug Tracker`_. - -* .. _error reporting: - - Calling rst2s5 with a non-existent theme (``--theme - does_not_exist``) - causes exceptions. Such errors should be handled more gracefully. - -* The "stylesheet" setting (a URL, to be used verbatim) should be - allowed to be combined with "embed_stylesheet". The stylesheet data - should be read in using urllib. There was an assumption that a - stylesheet to be embedded should exist as a file on the local - system, and only the "stylesheet_path" setting should be used. - -* ``utils.relative_path()`` sometimes returns absolute _`paths on - Windows` (like ``C:/test/foo.css``) where it could have chosen a - relative path. - - Furthermore, absolute pathnames are inserted verbatim, like - ``href="C:/test/foo.css"`` instead of - ``href="file:///C:/test/foo.css"``. - - .. gmane web interface is down. - TODO: find this article in the Sourceforge mail archives - For details, see `this posting by Alan G. Isaac - <http://article.gmane.org/gmane.text.docutils.user/1569>`_. - -* Footnote label "5" should be "4" when processing the following - input:: - - ref [#abc]_ [#]_ [1]_ [#4]_ - - .. [#abc] footnote - .. [#] two - .. [1] one - .. [#4] four - - Output:: - - <document source="<stdin>"> - <paragraph> - ref - <footnote_reference auto="1" ids="id1" refid="abc"> - 2 - - <footnote_reference auto="1" ids="id2" refid="id5"> - 3 - - <footnote_reference ids="id3" refid="id6"> - 1 - - <footnote_reference auto="1" ids="id4" refid="id7"> - 5 - <footnote auto="1" backrefs="id1" ids="abc" names="abc"> - <label> - 2 - <paragraph> - footnote - <footnote auto="1" backrefs="id2" ids="id5" names="3"> - <label> - 3 - <paragraph> - two - <footnote backrefs="id3" ids="id6" names="1"> - <label> - 1 - <paragraph> - one - <footnote auto="1" backrefs="id4" ids="id7" names="4"> - <label> - 5 - <paragraph> - four - -* IDs are based on names. Explicit hyperlink targets have priority - over implicit targets. But if an explicit target comes after an - implicit target with the same name, the ID of the first (implicit) - target remains based on the implicit name. Since HTML fragment - identifiers are based on the IDs, the first target keeps the name. - For example:: - - .. contents:: - - Section - ======= - - .. _contents: - - Subsection - ---------- - - text with a reference to contents_ and section_ - - .. _section: - - This paragraph is explicitly targeted with the name "section". - - When processed to HTML, the 2 internal hyperlinks (to "contents" & - "section") will work fine, but hyperlinks from outside the document - using ``href="...#contents"`` and ``href="...#section"`` won't work. - Such external links will connect to the implicit targets (table of - contents and "Section" title) instead of the explicit targets - ("Subsection" title and last paragraph). - - Hyperlink targets with duplicate names should be assigned new IDs - unrelated to the target names (i.e., "id"-prefix serial IDs). - -* The "contents" ID of the local table of contents in - ``test/functional/expected/standalone_rst_pseudoxml.txt`` is lost in - the HTML output at - ``test/functional/expected/standalone_rst_html4css1.html``. - -* _`Blank first columns` in simple tables with explicit row separators - silently swallow their input. They should at least produce system - error messages. But, with explicit row separators, the meaning is - unambiguous and ought to be supported:: - - ============== ========== - Table with row separators - ============== ========== - and blank - -------------- ---------- - entries - -------------- ---------- - in first - -------------- ---------- - columns. - ============== ========== - - Added a commented-out test case to - test/test_parsers/test_rst/test_SimpleTableParser.py. - -* _`Footnote references with hyperlink targets` cause a possibly - invalid node tree and make the HTML writer crash:: - - $ rst2pseudoxml - [1]_ - - .. _1: URI - <document source="<stdin>"> - <paragraph> - <footnote_reference ids="id1" refuri="URI"> - 1 - <target ids="id2" names="1" refuri="URI"> - -* Anonymous references have "name" attributes. Should they? Are they - used? See ``test/test_parsers/test_rst/test_inline_markup.py``. - -* <reference> elements have a "name" attribute, not "names". The - attribute should be "names"; this is an inconsistency. - - -.. Emacs settings - - Local Variables: - mode: indented-text - mode: rst - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - End: Copied: trunk/docutils/COPYING.rst (from rev 9905, trunk/docutils/COPYING.txt) =================================================================== --- trunk/docutils/COPYING.rst (rev 0) +++ trunk/docutils/COPYING.rst 2024-08-15 08:43:38 UTC (rev 9906) @@ -0,0 +1,159 @@ +.. include:: docs/header0.rst + +================== + Copying Docutils +================== + +:Author: David Goodger +:Contact: go...@py... +:Date: $Date$ +:Web site: https://docutils.sourceforge.io/ +:Copyright: This document has been placed in the public domain. + +Most of the files included in this project have been placed in the +public domain, and therefore have no license requirements and no +restrictions on copying or usage; see the `Public Domain Dedication`_ +below. There are exceptions_, listed below. +Files in the Sandbox_ are not distributed with Docutils releases and +may have different license terms. + + +Public Domain Dedication +======================== + +The persons who have associated their work with this project (the +"Dedicator": David Goodger and the many contributors to the Docutils +project) hereby dedicate the entire copyright, less the exceptions_ +listed below, in the work of authorship known as "Docutils" identified +below (the "Work") to the public domain. + +The primary repository for the Work is the Internet World Wide Web +site <https://docutils.sourceforge.io/>. The Work consists of the +files within the "docutils" module of the Docutils project Subversion +repository (http://svn.code.sf.net/p/docutils/code/), +whose Internet web interface is located at +<https://sourceforge.net/p/docutils/code>. Files dedicated to the +public domain may be identified by the inclusion, near the beginning +of each file, of a declaration of the form:: + + Copyright: This document/module/DTD/stylesheet/file/etc. has been + placed in the public domain. + +Dedicator makes this dedication for the benefit of the public at large +and to the detriment of Dedicator's heirs and successors. Dedicator +intends this dedication to be an overt act of relinquishment in +perpetuity of all present and future rights under copyright law, +whether vested or contingent, in the Work. Dedicator understands that +such relinquishment of all rights includes the relinquishment of all +rights to enforce (by lawsuit or otherwise) those copyrights in the +Work. + +Dedicator recognizes that, once placed in the public domain, the Work +may be freely reproduced, distributed, transmitted, used, modified, +built upon, or otherwise exploited by anyone for any purpose, +commercial or non-commercial, and in any way, including by methods +that have not yet been invented or conceived. + +(This dedication is derived from the text of the `Creative Commons +Public Domain Dedication`. [#]_) + +.. [#] Creative Commons has `retired this legal tool`__ and does not + recommend that it be applied to works: This tool is based on United + States law and may not be applicable outside the US. For dedicating new + works to the public domain, Creative Commons recommend the replacement + Public Domain Dedication CC0_ (CC zero, "No Rights Reserved"). So does + the Free Software Foundation in its license-list_. + + __ http://creativecommons.org/retiredlicenses + .. _CC0: http://creativecommons.org/about/cc0 + +Exceptions +========== + +The exceptions to the `Public Domain Dedication`_ above are: + +* docutils/utils/smartquotes.py + + Copyright © 2011 Günter Milde, + based on `SmartyPants`_ © 2003 John Gruber + (released under a "revised" `BSD 3-Clause License`_ included in the file) + and smartypants.py © 2004, 2007 Chad Miller. + Released under the terms of the `BSD 2-Clause License`_ + (`local copy <licenses/BSD-2-Clause.rst>`__). + + .. _SmartyPants: http://daringfireball.net/projects/smartypants/ + +* docutils/utils/math/latex2mathml.py + + Copyright © Jens Jørgen Mortensen, Günter Milde. + Released under the terms of the `BSD 2-Clause License`_ + (`local copy <licenses/BSD-2-Clause.rst>`__). + +* | docutils/utils/math/math2html.py, + | docutils/writers/html5_polyglot/math.css + + Copyright © 2009,2010 Alex Fernández; 2021 Günter Milde + + These files were part of eLyXer_, released under the `GNU + General Public License`_ version 3 or later. The author relicensed + them for Docutils under the terms of the `BSD 2-Clause License`_ + (`local copy <licenses/BSD-2-Clause.rst>`__). + + .. _eLyXer: https://github.com/alexfernandez/elyxer + +* | docutils/__main__.py, + | docutils/parsers/commonmark_wrapper.py, + | docutils/parsers/recommonmark_wrapper.py, + | docutils/utils/error_reporting.py, + | docutils/utils/math/__init__.py, + | docutils/utils/math/latex2mathml.py, + | docutils/utils/math/tex2mathml_extern.py, + | docutils/utils/punctuation_chars.py, + | docutils/utils/smartquotes.py, + | docutils/writers/html5_polyglot/__init__.py, + | docutils/writers/html5_polyglot/\*.css, + | docutils/writers/latex2e/docutils.sty, + | docutils/writers/xetex/__init__.py, + | test/test_parsers/test_recommonmark/\*.py, + | test/test_parsers/test_rst/test_directives/test__init__.py, + | test/test_parsers/test_rst/test_directives/test_code_parsing.py, + | test/test_parsers/test_rst/test_line_length_limit_default.py, + | test/test_parsers/test_rst/test_line_length_limit.py, + | test/test_writers/test_latex2e_misc.py, + | test/transforms/test_smartquotes.py, + | tools/docutils-cli.py, + | tools/rst2html5.py + + Copyright © Günter Milde. + Released under the terms of the `BSD 2-Clause License`_ + (`local copy <licenses/BSD-2-Clause.rst>`__). + +* docutils/utils/roman.py + + copyright by Mark Pilgrim, released under the + `Zope Public License Version 2.1`_ (`local copy`__). + + __ licenses/ZPL-2-1.rst + +* tools/editors/emacs/rst.el + + copyright by Free Software Foundation, Inc., + released under the `GNU General Public License`_ version 3 or later + (`local copy`__). + + __ licenses/gpl-3-0.rst + +All used licenses are OSI-approved_ and GPL-compatible_. + +Plaintext versions of all the linked-to licenses are provided in the +licenses_ directory. + +.. _sandbox: https://docutils.sourceforge.io/sandbox/README.html +.. _licenses: licenses/ +.. _GNU General Public License: https://www.gnu.org/copyleft/gpl.html +.. _BSD 2-Clause License: http://opensource.org/licenses/BSD-2-Clause +.. _BSD 3-Clause License: https://opensource.org/licenses/BSD-3-Clause +.. _Zope Public License Version 2.1: https://opensource.org/license/zpl-2-1/ +.. _OSI-approved: http://opensource.org/licenses/ +.. _license-list: +.. _GPL-compatible: https://www.gnu.org/licenses/license-list.html Deleted: trunk/docutils/COPYING.txt =================================================================== --- trunk/docutils/COPYING.txt 2024-08-15 07:31:04 UTC (rev 9905) +++ trunk/docutils/COPYING.txt 2024-08-15 08:43:38 UTC (rev 9906) @@ -1,159 +0,0 @@ -.. include:: docs/header0.txt - -================== - Copying Docutils -================== - -:Author: David Goodger -:Contact: go...@py... -:Date: $Date$ -:Web site: https://docutils.sourceforge.io/ -:Copyright: This document has been placed in the public domain. - -Most of the files included in this project have been placed in the -public domain, and therefore have no license requirements and no -restrictions on copying or usage; see the `Public Domain Dedication`_ -below. There are exceptions_, listed below. -Files in the Sandbox_ are not distributed with Docutils releases and -may have different license terms. - - -Public Domain Dedication -======================== - -The persons who have associated their work with this project (the -"Dedicator": David Goodger and the many contributors to the Docutils -project) hereby dedicate the entire copyright, less the exceptions_ -listed below, in the work of authorship known as "Docutils" identified -below (the "Work") to the public domain. - -The primary repository for the Work is the Internet World Wide Web -site <https://docutils.sourceforge.io/>. The Work consists of the -files within the "docutils" module of the Docutils project Subversion -repository (http://svn.code.sf.net/p/docutils/code/), -whose Internet web interface is located at -<https://sourceforge.net/p/docutils/code>. Files dedicated to the -public domain may be identified by the inclusion, near the beginning -of each file, of a declaration of the form:: - - Copyright: This document/module/DTD/stylesheet/file/etc. has been - placed in the public domain. - -Dedicator makes this dedication for the benefit of the public at large -and to the detriment of Dedicator's heirs and successors. Dedicator -intends this dedication to be an overt act of relinquishment in -perpetuity of all present and future rights under copyright law, -whether vested or contingent, in the Work. Dedicator understands that -such relinquishment of all rights includes the relinquishment of all -rights to enforce (by lawsuit or otherwise) those copyrights in the -Work. - -Dedicator recognizes that, once placed in the public domain, the Work -may be freely reproduced, distributed, transmitted, used, modified, -built upon, or otherwise exploited by anyone for any purpose, -commercial or non-commercial, and in any way, including by methods -that have not yet been invented or conceived. - -(This dedication is derived from the text of the `Creative Commons -Public Domain Dedication`. [#]_) - -.. [#] Creative Commons has `retired this legal tool`__ and does not - recommend that it be applied to works: This tool is based on United - States law and may not be applicable outside the US. For dedicating new - works to the public domain, Creative Commons recommend the replacement - Public Domain Dedication CC0_ (CC zero, "No Rights Reserved"). So does - the Free Software Foundation in its license-list_. - - __ http://creativecommons.org/retiredlicenses - .. _CC0: http://creativecommons.org/about/cc0 - -Exceptions -========== - -The exceptions to the `Public Domain Dedication`_ above are: - -* docutils/utils/smartquotes.py - - Copyright © 2011 Günter Milde, - based on `SmartyPants`_ © 2003 John Gruber - (released under a "revised" `BSD 3-Clause License`_ included in the file) - and smartypants.py © 2004, 2007 Chad Miller. - Released under the terms of the `BSD 2-Clause License`_ - (`local copy <licenses/BSD-2-Clause.txt>`__). - - .. _SmartyPants: http://daringfireball.net/projects/smartypants/ - -* docutils/utils/math/latex2mathml.py - - Copyright © Jens Jørgen Mortensen, Günter Milde. - Released under the terms of the `BSD 2-Clause License`_ - (`local copy <licenses/BSD-2-Clause.txt>`__). - -* | docutils/utils/math/math2html.py, - | docutils/writers/html5_polyglot/math.css - - Copyright © 2009,2010 Alex Fernández; 2021 Günter Milde - - These files were part of eLyXer_, released under the `GNU - General Public License`_ version 3 or later. The author relicensed - them for Docutils under the terms of the `BSD 2-Clause License`_ - (`local copy <licenses/BSD-2-Clause.txt>`__). - - .. _eLyXer: https://github.com/alexfernandez/elyxer - -* | docutils/__main__.py, - | docutils/parsers/commonmark_wrapper.py, - | docutils/parsers/recommonmark_wrapper.py, - | docutils/utils/error_reporting.py, - | docutils/utils/math/__init__.py, - | docutils/utils/math/latex2mathml.py, - | docutils/utils/math/tex2mathml_extern.py, - | docutils/utils/punctuation_chars.py, - | docutils/utils/smartquotes.py, - | docutils/writers/html5_polyglot/__init__.py, - | docutils/writers/html5_polyglot/\*.css, - | docutils/writers/latex2e/docutils.sty, - | docutils/writers/xetex/__init__.py, - | test/test_parsers/test_recommonmark/\*.py, - | test/test_parsers/test_rst/test_directives/test__init__.py, - | test/test_parsers/test_rst/test_directives/test_code_parsing.py, - | test/test_parsers/test_rst/test_line_length_limit_default.py, - | test/test_parsers/test_rst/test_line_length_limit.py, - | test/test_writers/test_latex2e_misc.py, - | test/transforms/test_smartquotes.py, - | tools/docutils-cli.py, - | tools/rst2html5.py - - Copyright © Günter Milde. - Released under the terms of the `BSD 2-Clause License`_ - (`local copy <licenses/BSD-2-Clause.txt>`__). - -* docutils/utils/roman.py - - copyright by Mark Pilgrim, released under the - `Zope Public License Version 2.1`_ (`local copy`__). - - __ licenses/ZPL-2-1.txt - -* tools/editors/emacs/rst.el - - copyright by Free Software Foundation, Inc., - released under the `GNU General Public License`_ version 3 or later - (`local copy`__). - - __ licenses/gpl-3-0.txt - -All used licenses are OSI-approved_ and GPL-compatible_. - -Plaintext versions of all the linked-to licenses are provided in the -licenses_ directory. - -.. _sandbox: https://docutils.sourceforge.io/sandbox/README.html -.. _licenses: licenses/ -.. _GNU General Public License: https://www.gnu.org/copyleft/gpl.html -.. _BSD 2-Clause License: http://opensource.org/licenses/BSD-2-Clause -.. _BSD 3-Clause License: https://opensource.org/licenses/BSD-3-Clause -.. _Zope Public License Version 2.1: https://opensource.org/license/zpl-2-1/ -.. _OSI-approved: http://opensource.org/licenses/ -.. _license-list: -.. _GPL-compatible: https://www.gnu.org/licenses/license-list.html Copied: trunk/docutils/FAQ.rst (from rev 9905, trunk/docutils/FAQ.txt) =================================================================== --- trunk/docutils/FAQ.rst (rev 0) +++ trunk/docutils/FAQ.rst 2024-08-15 08:43:38 UTC (rev 9906) @@ -0,0 +1,1339 @@ +.. include:: docs/header0.rst + +.. NOTE TO MAINTAINERS: Please add new questions to the end of their + sections, so section/question numbers remain stable. + +=========================================== + Docutils FAQ (Frequently Asked Questions) +=========================================== + +:Date: $Date$ +:Revision: $Revision$ +:Web site: https://docutils.sourceforge.io/ +:Copyright: This document has been placed in the public domain. + +.. contents:: +.. sectnum:: + + +This is a work in progress. If you are reading a local copy, the +`master copy`_ might be newer. This document uses relative links; +if they don't work, please use the master copy. + +Please feel free to ask questions and/or provide answers; send email +to the `Docutils-users`_ mailing list. Project members should feel +free to edit the source text file directly. + +.. _master copy: https://docutils.sourceforge.io/FAQ.html +.. _let us know: +.. _Docutils-users: docs/user/mailing-lists.html#docutils-users + + + +Docutils +======== + +What is Docutils? +----------------- + +Docutils_ is a system for processing plaintext documentation into +useful formats, such as HTML, XML, and LaTeX. It supports multiple +types of input, such as standalone files, `PEPs (Python Enhancement +Proposals)`_, and string input. Client code may add other input types, +e.g. Sphinx_ comes with an extension to extract inline documentation +from Python modules and packages. + +The Docutils distribution consists of: + +* a library (the "docutils" package), which `can be used by client + code`_; +* several `front-end tools`_ (such as ``rst2html``, which converts + reStructuredText input into HTML output); +* a `test suite`_; and +* documentation_. + +For an overview of the Docutils project implementation, +see :PEP:`258`, "Docutils Design Specification". + +Docutils is implemented in Python_. + +.. _Docutils: https... [truncated message content] |
From: <mi...@us...> - 2024-08-15 16:35:37
|
Revision: 9909 http://sourceforge.net/p/docutils/code/9909 Author: milde Date: 2024-08-15 16:35:34 +0000 (Thu, 15 Aug 2024) Log Message: ----------- Refactor "Include" directive class. Disentangle actions and simplify interface of auxiliary methods. `Include.run()` sets up instance attributes and calls helper functions to read the file content and process it according to the options. (Helper methods depend on setup in `run()`.) Input sanity checks (too long lines and circular inclusions) are only required when when inserting the file content into the "input_lines" of the calling parser (which did these checks on the other "input_lines" before starting to parsing it). Adapt formatting. Adapt tests. Use shorter URL to the "include" directive documentation. Modified Paths: -------------- trunk/docutils/docutils/parsers/rst/directives/misc.py trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py trunk/docutils/test/test_parsers/test_rst/test_line_length_limit.py Modified: trunk/docutils/docutils/parsers/rst/directives/misc.py =================================================================== --- trunk/docutils/docutils/parsers/rst/directives/misc.py 2024-08-15 14:14:24 UTC (rev 9908) +++ trunk/docutils/docutils/parsers/rst/directives/misc.py 2024-08-15 16:35:34 UTC (rev 9909) @@ -9,6 +9,7 @@ __docformat__ = 'reStructuredText' import re +import sys import time from pathlib import Path from typing import TYPE_CHECKING @@ -23,11 +24,21 @@ if TYPE_CHECKING: import os + if sys.version_info[:2] >= (3, 12): + from typing import TypeAlias + else: + from typing_extensions import TypeAlias from docutils.nodes import Node + PathString: TypeAlias = str | os.PathLike[str] + """File system path.""" -def adapt_path(path, source='', root_prefix='/'): + SourceString: TypeAlias = str | os.PathLike[str] + """Path to or informal description of a Docutils input source.""" + + +def adapt_path(path: str, source='', root_prefix='/') -> str: # Adapt path to files to include or embed. # `root_prefix` is prepended to absolute paths (cf. root_prefix setting), # `source` is the `current_source` of the including directive (which may @@ -52,7 +63,7 @@ start and end line or text to match before and/or after the text to be used. - https://docutils.sourceforge.io/docs/ref/rst/directives.html#including-an-external-document-fragment + https://docutils.sourceforge.io/docs/ref/rst/directives.html#include """ required_arguments = 1 @@ -68,7 +79,7 @@ 'start-after': directives.unchanged_required, 'end-before': directives.unchanged_required, # ignored except for 'literal' or 'code': - 'number-lines': directives.unchanged, # integer or None + 'number-lines': directives.value_or((None,), int), 'class': directives.class_option, 'name': directives.unchanged} @@ -77,14 +88,17 @@ def run(self) -> list[Node]: """Include a file as part of the content of this reST file. - Depending on the options, the file (or a clipping) is + Depending on the options, the file content (or a clipping) is converted to nodes and returned or inserted into the input stream. """ - settings = self.state.document.settings + self.settings = settings = self.state.document.settings if not settings.file_insertion_enabled: raise self.warning('"%s" directive disabled.' % self.name) - tab_width = self.options.get('tab-width', settings.tab_width) - current_source = self.state.document.current_source + self.tab_width = self.options.get('tab-width', settings.tab_width) + self.clip_options = (self.options.get('start-line', None), + self.options.get('end-line', None), + self.options.get('start-after', ''), + self.options.get('end-before', '')) path = directives.path(self.arguments[0]) if path.startswith('<') and path.endswith('>'): path = '/' + path[1:-1] @@ -91,152 +105,92 @@ root_prefix = self.standard_include_path else: root_prefix = settings.root_prefix - path = adapt_path(path, current_source, root_prefix) - rawtext, clip_options = self._read_source(path) - include_lines = statemachine.string2lines(rawtext, tab_width, - convert_whitespace=True) - for i, line in enumerate(include_lines): - if len(line) > settings.line_length_limit: - raise self.warning('"%s": line %d exceeds the' - ' line-length-limit.' % (path, i+1)) + path = adapt_path(path, + self.state.document.current_source, + root_prefix) + self.options['source'] = path + inputstring = self.read_file(path) + if 'literal' in self.options: - return self.include_literal_block( - source=path, - rawtext=rawtext, - tab_width=tab_width, - include_lines=include_lines, - ) - + return self.as_literal_block(inputstring) if 'code' in self.options: - return self.include_code_block( - source=path, - rawtext=rawtext, - tab_width=tab_width, - include_lines=include_lines, - ) - - # Prevent circular inclusion: - include_log = self.state.document.include_log - # log entries are tuples (<source>, <clip-options>) - if not include_log: # new document, initialize with document source - include_log.append((utils.relative_path(None, current_source), - (None, None, None, None))) - if (path, clip_options) in include_log: - master_paths = (pth for (pth, opt) in reversed(include_log)) - inclusion_chain = '\n> '.join((path, *master_paths)) - raise self.warning('circular inclusion in "%s" directive:\n%s' - % (self.name, inclusion_chain)) - + return self.as_code_block(inputstring) if 'parser' in self.options: - return self.include_parsed( - source=path, - include_lines=include_lines, - clip_options=clip_options, - ) - - # Include as rST source: - self.include_text( - rawtext, - source=path, - tab_width=tab_width, - include_lines=include_lines, - ) - # update include-log - include_log.append((path, clip_options)) + return self.custom_parse(inputstring) + self.insert_into_input_lines(inputstring) return [] - def _read_source( - self, source: str | os.PathLike[str], /, - ) -> tuple[str, tuple[int | None, int | None, str | None, str | None]]: - """Read and clip the content of *source*.""" - settings = self.state.document.settings - encoding = self.options.get('encoding', settings.input_encoding) - error_handler = settings.input_encoding_error_handler + def read_file(self, path: PathString) -> str: + """Read text file at `path`. Clip and return content. + + Provisional. + """ + encoding = self.options.get('encoding', self.settings.input_encoding) + error_handler = self.settings.input_encoding_error_handler try: - include_file = io.FileInput( - source_path=source, - encoding=encoding, - error_handler=error_handler, - ) + include_file = io.FileInput(source_path=path, + encoding=encoding, + error_handler=error_handler) except UnicodeEncodeError: raise self.severe(f'Problems with "{self.name}" directive path:\n' - f'Cannot encode input file path "{source}" ' + f'Cannot encode input file path "{path}" ' '(wrong locale?).') except OSError as error: - raise self.severe(f'Problems with "{self.name}" directive ' - f'path:\n{io.error_string(error)}.') + raise self.severe(f'Problems with "{self.name}" directive path:\n' + f'{io.error_string(error)}.') else: - settings.record_dependencies.add(source) - - # Get to-be-included content - startline = self.options.get('start-line', None) - endline = self.options.get('end-line', None) + self.settings.record_dependencies.add(path) try: - if startline or (endline is not None): - lines = include_file.readlines() - rawtext = ''.join(lines[startline:endline]) - else: - rawtext = include_file.read() + text = include_file.read() except UnicodeError as error: raise self.severe(f'Problem with "{self.name}" directive:\n' + io.error_string(error)) + # Clip to-be-included content + startline, endline, starttext, endtext = self.clip_options + if startline or (endline is not None): + lines = text.splitlines() + text = '\n'.join(lines[startline:endline]) # start-after/end-before: no restrictions on newlines in match-text, # and no restrictions on matching inside lines vs. line boundaries - after_text = self.options.get('start-after', None) - if after_text: - # skip content in rawtext before *and incl.* a matching text - after_index = rawtext.find(after_text) + if starttext: + # skip content in text before *and incl.* a matching text + after_index = text.find(starttext) if after_index < 0: - raise self.severe('Problem with "start-after" option of "%s" ' - 'directive:\nText not found.' % self.name) - rawtext = rawtext[after_index + len(after_text):] - before_text = self.options.get('end-before', None) - if before_text: - # skip content in rawtext after *and incl.* a matching text - before_index = rawtext.find(before_text) + raise self.severe('Problem with "start-after" option of ' + f'"{self.name}" directive:\nText not found.') + text = text[after_index + len(starttext):] + if endtext: + # skip content in text after *and incl.* a matching text + before_index = text.find(endtext) if before_index < 0: - raise self.severe('Problem with "end-before" option of "%s" ' - 'directive:\nText not found.' % self.name) - rawtext = rawtext[:before_index] + raise self.severe('Problem with "end-before" option of ' + f'"{self.name}" directive:\nText not found.') + text = text[:before_index] + return text - clip_options = (startline, endline, before_text, after_text) - return rawtext, clip_options + def as_literal_block(self, text: str) -> list[nodes.literal_block]: + """Return list with literal_block containing `text`. - def include_literal_block( - self, - *, - source: str | os.PathLike[str], - rawtext: str, - include_lines: list[str], - tab_width: int, - ) -> list[nodes.literal_block]: - """Return the content from *source* as a literal block.""" - # Don't convert tabs to spaces, if `tab_width` is negative. - if tab_width >= 0: - text = rawtext.expandtabs(tab_width) - else: - text = rawtext + Provisional + """ + source = self.options['source'] + # Convert tabs to spaces unless `tab_width` is negative. + if self.tab_width >= 0: + text = text.expandtabs(self.tab_width) literal_block = nodes.literal_block( - rawtext, source=source, - classes=self.options.get('class', [])) - literal_block.line = 1 + '', source=source, classes=self.options.get('class', [])) + literal_block.source = source + literal_block.line = self.options.get('start-line', 0) + 1 self.add_name(literal_block) if 'number-lines' in self.options: - try: - startline = int(self.options['number-lines'] or 1) - except ValueError: - msg = ':number-lines: with non-integer start value' - raise self.error(msg) - endline = startline + len(include_lines) - if text.endswith('\n'): - text = text[:-1] - tokens = NumberLines([([], text)], startline, endline) + firstline = self.options['number-lines'] or 1 + text = text.removesuffix('\n') + lastline = firstline + len(text.splitlines()) + tokens = NumberLines([([], text)], firstline, lastline) for classes, value in tokens: if classes: - literal_block += nodes.inline( - value, value, classes=classes, - ) + literal_block += nodes.inline('', value, classes=classes) else: literal_block += nodes.Text(value) else: @@ -243,50 +197,41 @@ literal_block += nodes.Text(text) return [literal_block] - def include_code_block( - self, - *, - source: str | os.PathLike[str], - rawtext: str, - include_lines: list[str], - tab_width: int, - ) -> list[nodes.literal_block]: - """Return the content from *source* as a code block.""" - self.options['source'] = source - # Don't convert tabs to spaces, if `tab_width` is negative: - if tab_width < 0: - include_lines = rawtext.splitlines() - codeblock = CodeBlock( - self.name, - [self.options.pop('code')], # arguments - self.options, - include_lines, # content - self.lineno, - self.content_offset, - self.block_text, - self.state, - self.state_machine, - ) + def as_code_block(self, text: str) -> list[nodes.literal_block]: + """Pass `text` to the `CodeBlock` directive class. + + Provisional. + """ + # convert tabs to spaces unless `tab_width` is negative: + if self.tab_width >= 0: + text = text.expandtabs(self.tab_width) + codeblock = CodeBlock(self.name, + [self.options.pop('code')], # pass as argument + self.options, + [text.removesuffix('\n')], # content + self.lineno, + self.content_offset, + self.block_text, + self.state, + self.state_machine, + ) return codeblock.run() - def include_parsed( - self, - *, - source: str | os.PathLike[str], - include_lines: list[str], - clip_options: tuple[int | str, int | str, str, str], - ) -> list[Node]: - """Return content from *source* after parsing with the given parser.""" - settings = self.state.document.settings - include_log = self.state.document.include_log + def custom_parse(self, text: str) -> list[Node]: + """Parse with custom parser. - # parse into a dummy document and return created nodes - _settings = settings.copy() - _settings._source = source - document = utils.new_document(source, _settings) - document.include_log = include_log + [(source, clip_options)] + Parse with ``self.options['parser']`` into a new (dummy) document, + apply the parser's default transforms, + return child elements. + + Provisional. + """ + settings = self.settings.copy() + settings._source = self.options['source'] + document = utils.new_document(settings._source, settings) + document.include_log = self.state.document.include_log parser = self.options['parser']() - parser.parse('\n'.join(include_lines), document) + parser.parse(text, document) self.state.document.parse_messages.extend(document.parse_messages) # clean up doctree and complete parsing document.transformer.populate_from_components((parser,)) @@ -295,26 +240,42 @@ document.transform_messages) return document.children - def include_text( - self, - text: str, - *, - source: str | os.PathLike[str], - tab_width: int, - include_lines: list[str] | None = None, - ) -> None: - """Insert *text* into the input stream.""" - # *text* is passed for use in subclasses, but if we have already - # split the lines and nothing is changing, reuse those lines. - if include_lines is not None: - include_lines = statemachine.string2lines( - text, tab_width, convert_whitespace=True, - ) - # Mark end (cf. parsers.rst.states.Body.comment()) - include_lines += ['', '.. end of inclusion from "%s"' % source] - self.state_machine.insert_input(include_lines, source) + def insert_into_input_lines(self, text: str) -> None: + """Insert file content into the rST input of the calling parser. + Returns an empty list to comply with the API of `Directive.run()`. + Provisional. + """ + source = self.options['source'] + textlines = statemachine.string2lines(text, self.tab_width, + convert_whitespace=True) + # Sanity checks: + # excessively long lines + for i, line in enumerate(textlines): + if len(line) > self.settings.line_length_limit: + line_no = i + 1 + self.options.get('start-line', 0) + raise self.warning(f'"{source}": line {line_no} exceeds the' + ' line-length-limit.') + # circular inclusion + include_log = self.state.document.include_log + if not include_log: # new document, initialize with document source + current_source = utils.relative_path( + None, self.state.document.current_source) + include_log.append((current_source, (None, None, '', ''))) + if (source, self.clip_options) in include_log: + source_chain = (pth for (pth, opt) in reversed(include_log)) + inclusion_chain = '\n> '.join((source, *source_chain)) + raise self.warning(f'circular inclusion in "{self.name}"' + f' directive:\n{inclusion_chain}') + include_log.append((source, self.clip_options)) + # marker for removing log entry (cf. parsers.rst.states.Body.comment()) + textlines += ['', f'.. end of inclusion from "{source}"'] + + self.state_machine.insert_input(textlines, source) + # TODO: if startline != 0, line numbers are wrong. + + class Raw(Directive): """ Modified: trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py =================================================================== --- trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py 2024-08-15 14:14:24 UTC (rev 9908) +++ trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py 2024-08-15 16:35:34 UTC (rev 9909) @@ -1457,7 +1457,6 @@ {include15} > {include16} > {include15} - > test data <literal_block xml:space="preserve"> .. include:: include15.rst <paragraph> Modified: trunk/docutils/test/test_parsers/test_rst/test_line_length_limit.py =================================================================== --- trunk/docutils/test/test_parsers/test_rst/test_line_length_limit.py 2024-08-15 14:14:24 UTC (rev 9908) +++ trunk/docutils/test/test_parsers/test_rst/test_line_length_limit.py 2024-08-15 16:35:34 UTC (rev 9909) @@ -35,6 +35,8 @@ class ParserTestCase(unittest.TestCase): + maxDiff = None + def test_parser(self): parser = Parser() settings = get_default_settings(Parser) @@ -77,7 +79,6 @@ ============ .. include:: {docutils_conf} - :literal: A paragraph. """, @@ -91,10 +92,30 @@ "{docutils_conf}": line 5 exceeds the line-length-limit. <literal_block xml:space="preserve"> .. include:: {docutils_conf} - :literal: <paragraph> A paragraph. """], +[f"""\ +Include Test 2 + +.. include:: {docutils_conf} + :start-line: 3 + +A paragraph. +""", +f"""\ +<document source="test data"> + <paragraph> + Include Test 2 + <system_message level="2" line="3" source="test data" type="WARNING"> + <paragraph> + "{docutils_conf}": line 5 exceeds the line-length-limit. + <literal_block xml:space="preserve"> + .. include:: {docutils_conf} + :start-line: 3 + <paragraph> + A paragraph. +"""], ] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-08-21 13:44:40
|
Revision: 9912 http://sourceforge.net/p/docutils/code/9912 Author: milde Date: 2024-08-21 13:44:37 +0000 (Wed, 21 Aug 2024) Log Message: ----------- HTML writer: Fix part "html_head" if "output_encoding" setting is 'unicode'. If the output encoding is not determined, part "head" does not contain a "charset" `<meta>` element. So we must not drop the first element from "head" when completing "html_head". Fixup for [r9240]. Modified Paths: -------------- trunk/docutils/docutils/writers/_html_base.py trunk/docutils/test/test_writers/test_html5_polyglot_parts.py Modified: trunk/docutils/docutils/writers/_html_base.py =================================================================== --- trunk/docutils/docutils/writers/_html_base.py 2024-08-21 08:05:47 UTC (rev 9911) +++ trunk/docutils/docutils/writers/_html_base.py 2024-08-21 13:44:37 UTC (rev 9912) @@ -963,8 +963,12 @@ self.head.extend(self.math_header) else: self.stylesheet.extend(self.math_header) - # skip content-type meta tag with interpolated charset value: - self.html_head.extend(self.head[1:]) + if (self.settings.output_encoding # may be None + and self.settings.output_encoding.lower() != 'unicode'): + # skip content-type meta tag with interpolated charset value: + self.html_head.extend(self.head[1:]) + else: + self.html_head.extend(self.head) self.body_prefix.append(self.starttag(node, **self.documenttag_args)) self.body_suffix.insert(0, f'</{self.documenttag_args["tagname"]}>\n') self.fragment.extend(self.body) # self.fragment is the "naked" body Modified: trunk/docutils/test/test_writers/test_html5_polyglot_parts.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot_parts.py 2024-08-21 08:05:47 UTC (rev 9911) +++ trunk/docutils/test/test_writers/test_html5_polyglot_parts.py 2024-08-21 13:44:37 UTC (rev 9912) @@ -84,7 +84,7 @@ settings_overrides={ '_disable_config': True, 'strict_visitor': True, - 'stylesheet': '', + 'stylesheet_path': '', 'section_self_link': True, **settings_overrides, } @@ -143,8 +143,7 @@ totest = {} -totest['standard'] = ({'stylesheet_path': '', - 'embed_stylesheet': False}, [ +totest['standard'] = ({}, [ ["""\ Simple String """, @@ -288,12 +287,22 @@ }], ]) -totest['no_title_promotion'] = ({'doctitle_xform': False, - 'stylesheet_path': '', - 'embed_stylesheet': False}, [ +totest['standard'] = ({'output_encoding': 'unicode'}, [ ["""\ Simple String """, +{'fragment': '<p>Simple String</p>\n', + 'meta': """\ +<meta name="generator" content="Docutils 0.22b.dev: https://docutils.sourceforge.io/" /> +<meta name="viewport" content="width=device-width, initial-scale=1" /> +""", +}], +]) + +totest['no_title_promotion'] = ({'doctitle_xform': False}, [ +["""\ +Simple String +""", '<p>Simple String</p>\n', ], ["""\ @@ -574,8 +583,6 @@ totest['lazy_loading'] = ({'image_loading': 'lazy', - 'stylesheet_path': '', - 'embed_stylesheet': False, 'report_level': 4}, [ ["""\ Lazy loading by default, overridden by :loading: option @@ -606,9 +613,7 @@ totest['root_prefix'] = ({'root_prefix': ROOT_PREFIX, 'image_loading': 'embed', - 'stylesheet_path': '', 'warning_stream': '', - 'embed_stylesheet': False }, [ ["""\ .. image:: /data/blue%20square.png @@ -630,9 +635,7 @@ ]) -totest['no_backlinks'] = ({'footnote_backlinks': False, - 'stylesheet_path': '', - 'embed_stylesheet': False}, [ +totest['no_backlinks'] = ({'footnote_backlinks': False}, [ ["""\ Two footnotes [#f1]_ [#f2]_ and two citations [once]_ [twice]_. @@ -673,7 +676,6 @@ totest['syntax_highlight'] = ({'syntax_highlight': 'short', - 'stylesheet_path': '', }, [ ["""\ .. code:: shell @@ -701,9 +703,7 @@ ]) -totest['system_messages'] = ({'stylesheet_path': '', - 'embed_stylesheet': False, - 'math_output': 'mathml', +totest['system_messages'] = ({'math_output': 'mathml', 'warning_stream': '', }, [ ["""\ @@ -748,9 +748,7 @@ """], ]) -totest['system_messages-PIL'] = ({'stylesheet_path': '', - 'embed_stylesheet': False, - 'math_output': 'mathml', +totest['system_messages-PIL'] = ({'math_output': 'mathml', 'warning_stream': '', }, [ ["""\ @@ -816,9 +814,7 @@ ], ]) -totest['no_system_messages'] = ({'stylesheet_path': '', - 'embed_stylesheet': False, - 'math_output': 'mathml', +totest['no_system_messages'] = ({'math_output': 'mathml', 'report_level': 4, 'warning_stream': '', }, [ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-08-21 13:44:51
|
Revision: 9913 http://sourceforge.net/p/docutils/code/9913 Author: milde Date: 2024-08-21 13:44:48 +0000 (Wed, 21 Aug 2024) Log Message: ----------- Refactor HTML5 writer tests. New test script "test_html5_polyglot.py": Split basic output tests (which happen to use the "fragment" returned by `publish_parts()` to get the interesting part of the output) from other tests of `publish_parts()` Really test all returned parts in "test_html5_polyglot_parts.py". Fill in parts that are built out of other parts in a helper function instead of pruning parts. Add test cases for input that goes to special parts. Disable default style sheet ("stylesheet_path" setting) by for tests not requiring a stylesheet. Modified Paths: -------------- trunk/docutils/docs/api/publisher.rst trunk/docutils/test/test_writers/test_html5_polyglot_misc.py trunk/docutils/test/test_writers/test_html5_polyglot_parts.py Added Paths: ----------- trunk/docutils/test/test_writers/test_html5_polyglot.py Modified: trunk/docutils/docs/api/publisher.rst =================================================================== --- trunk/docutils/docs/api/publisher.rst 2024-08-21 13:44:37 UTC (rev 9912) +++ trunk/docutils/docs/api/publisher.rst 2024-08-21 13:44:48 UTC (rev 9913) @@ -603,7 +603,7 @@ Default: "restructuredtext". -_`writer` : str | docutils.parsers.Writer +_`writer` : str | docutils.writers.Writer `Writer component name`_ or instance. [#component-names]_ Default: "pseudoxml". Copied: trunk/docutils/test/test_writers/test_html5_polyglot.py (from rev 9912, trunk/docutils/test/test_writers/test_html5_polyglot_parts.py) =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot.py (rev 0) +++ trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-08-21 13:44:48 UTC (rev 9913) @@ -0,0 +1,672 @@ +#! /usr/bin/env python3 + +# $Id$ +# Author: reggie dugard <re...@us...> +# Copyright: This module has been placed in the public domain. + +"""Test HTML5 writer output ("fragment" part). + +This is the document body (not HTML <body>). +""" + +from pathlib import Path +import re +import sys +import unittest + +if __name__ == '__main__': + # prepend the "docutils root" to the Python library path + # so we import the local `docutils` package. + sys.path.insert(0, str(Path(__file__).resolve().parents[2])) + +import docutils +import docutils.core +from docutils.parsers.rst.directives.images import PIL +from docutils.utils.code_analyzer import with_pygments + +if with_pygments: + import pygments + _pv = re.match(r'^([0-9]+)\.([0-9]*)', pygments.__version__) + if (int(_pv[1]), int(_pv[2])) >= (2, 14): + # pygments output changed in version 2.14 + with_pygments = False + +# TEST_ROOT is ./test/ from the docutils root +TEST_ROOT = Path(__file__).parents[1] +DATA_ROOT = TEST_ROOT / 'data' +ROOT_PREFIX = (TEST_ROOT / 'functional/input').as_posix() + +# Pillow/PIL is optional: +if PIL: + REQUIRES_PIL = '' + ONLY_LOCAL = 'Can only read local images.' + DUMMY_PNG_NOT_FOUND = "[Errno 2] No such file or directory: 'dummy.png'" + # Pillow reports the absolute path since version 10.3.0 (cf. [bugs: 485]) + if (tuple(int(i) for i in PIL.__version__.split('.')) >= (10, 3)): + DUMMY_PNG_NOT_FOUND = ("[Errno 2] No such file or directory: '%s'" + % Path('dummy.png').resolve()) + SCALING_OUTPUT = 'style="width: 32.0px; height: 32.0px;" ' + NO_PIL_SYSTEM_MESSAGE = '' +else: + REQUIRES_PIL = '\n Requires Python Imaging Library.' + ONLY_LOCAL = 'Requires Python Imaging Library.' + DUMMY_PNG_NOT_FOUND = 'Requires Python Imaging Library.' + SCALING_OUTPUT = '' + NO_PIL_SYSTEM_MESSAGE = ( + '<aside class="system-message">\n' + '<p class="system-message-title">System Message:' + ' WARNING/2 (<span class="docutils literal">' + '<string></span>, line 1)</p>\n' + '<p>Cannot scale image!\n' + ' Could not get size from "/data/blue%20square.png":\n' + ' Requires Python Imaging Library.</p>\n' + '</aside>\n') + + +class Html5WriterPublishPartsTestCase(unittest.TestCase): + """Test case for HTML5 writer via the publish_parts() interface.""" + + maxDiff = None + + def test_publish(self): + if not with_pygments: + del totest['syntax_highlight'] + writer = 'html5' + for name, (settings_overrides, cases) in totest.items(): + for casenum, (case_input, case_expected) in enumerate(cases): + with self.subTest(id=f'totest[{name!r}][{casenum}]'): + parts = docutils.core.publish_parts( + source=case_input, + writer=writer, + settings_overrides={ + '_disable_config': True, + 'strict_visitor': True, + 'stylesheet_path': '', + 'section_self_link': True, + **settings_overrides, + } + ) + self.assertEqual(case_expected, parts['body']) + + +totest = {} + +totest['standard'] = ({}, [ +["""\ +Simple String +""", +'<p>Simple String</p>\n', +], +["""\ +Simple String with *markup* +""", +'<p>Simple String with <em>markup</em></p>\n', +], +["""\ +Simple String with an even simpler ``inline literal`` +""", +'<p>Simple String with an even simpler <span class="docutils literal">inline literal</span></p>\n', +], +["""\ +A simple `anonymous reference`__ + +__ http://www.test.com/test_url +""", +'<p>A simple <a class="reference external" href="http://www.test.com/test_url">anonymous reference</a></p>\n', +], +["""\ +One paragraph. + +Two paragraphs. +""", +"""\ +<p>One paragraph.</p> +<p>Two paragraphs.</p> +""", +], +["""\ +A simple `named reference`_ with stuff in between the +reference and the target. + +.. _`named reference`: http://www.test.com/test_url +""", +"""\ +<p>A simple <a class="reference external" href="http://www.test.com/test_url">named reference</a> with stuff in between the +reference and the target.</p> +""", +], +["""\ +.. [CIT2022] A citation. +""", +"""\ +<div role="list" class="citation-list"> +<div class="citation" id="cit2022" role="doc-biblioentry"> +<span class="label"><span class="fn-bracket">[</span>CIT2022<span class="fn-bracket">]</span></span> +<p>A citation.</p> +</div> +</div> +""", +], +]) + + +totest['no_title_promotion'] = ({'doctitle_xform': False}, [ +["""\ ++++++ +Title ++++++ + +Not A Subtitle +============== + +Some stuff + +Section +------- + +Some more stuff + +Another Section +............... + +And even more stuff +""", +"""\ +<section id="title"> +<h2>Title<a class="self-link" title="link to this section" href="#title"></a></h2> +<section id="not-a-subtitle"> +<h3>Not A Subtitle<a class="self-link" title="link to this section" href="#not-a-subtitle"></a></h3> +<p>Some stuff</p> +<section id="section"> +<h4>Section<a class="self-link" title="link to this section" href="#section"></a></h4> +<p>Some more stuff</p> +<section id="another-section"> +<h5>Another Section<a class="self-link" title="link to this section" href="#another-section"></a></h5> +<p>And even more stuff</p> +</section> +</section> +</section> +</section> +""", +], +["""\ +* bullet +* list +""", +"""\ +<ul class="simple"> +<li><p>bullet</p></li> +<li><p>list</p></li> +</ul> +""", +], +["""\ +.. table:: + :align: right + + +-----+-----+ + | 1 | 2 | + +-----+-----+ + | 3 | 4 | + +-----+-----+ +""", +"""\ +<table class="align-right"> +<tbody> +<tr><td><p>1</p></td> +<td><p>2</p></td> +</tr> +<tr><td><p>3</p></td> +<td><p>4</p></td> +</tr> +</tbody> +</table> +""", +], +["""\ +Not a docinfo. + +:This: .. _target: + + is +:a: +:simple: +:field: list +""", +"""\ +<p>Not a docinfo.</p> +<dl class="field-list simple"> +<dt>This<span class="colon">:</span></dt> +<dd><p id="target">is</p> +</dd> +<dt>a<span class="colon">:</span></dt> +<dd><p></p></dd> +<dt>simple<span class="colon">:</span></dt> +<dd><p></p></dd> +<dt>field<span class="colon">:</span></dt> +<dd><p>list</p> +</dd> +</dl> +""", +], +["""\ +Not a docinfo. + +:This is: a +:simple field list with loooong field: names +""", +"""\ +<p>Not a docinfo.</p> +<dl class="field-list simple"> +<dt>This is<span class="colon">:</span></dt> +<dd><p>a</p> +</dd> +<dt>simple field list with loooong field<span class="colon">:</span></dt> +<dd><p>names</p> +</dd> +</dl> +""", +], +["""\ +Not a docinfo. + +.. class:: field-indent-200 + +:This: is a +:simple: field list with custom indent. +""", +"""\ +<p>Not a docinfo.</p> +<dl class="field-list simple" style="--field-indent: 200px;"> +<dt>This<span class="colon">:</span></dt> +<dd><p>is a</p> +</dd> +<dt>simple<span class="colon">:</span></dt> +<dd><p>field list with custom indent.</p> +</dd> +</dl> +""", +], +["""\ +Not a docinfo. + +.. class:: field-indent-200uf + +:This: is a +:simple: field list without custom indent, + because the unit "uf" is invalid. +""", +"""\ +<p>Not a docinfo.</p> +<dl class="field-indent-200uf field-list simple"> +<dt>This<span class="colon">:</span></dt> +<dd><p>is a</p> +</dd> +<dt>simple<span class="colon">:</span></dt> +<dd><p>field list without custom indent, +because the unit "uf" is invalid.</p> +</dd> +</dl> +""", +], +["""\ +.. figure:: dummy.png + + The figure's caption. + + A legend. + + The legend's second paragraph. +""", +"""\ +<figure> +<img alt="dummy.png" src="dummy.png" /> +<figcaption> +<p>The figure's caption.</p> +<div class="legend"> +<p>A legend.</p> +<p>The legend's second paragraph.</p> +</div> +</figcaption> +</figure> +""", +], +["""\ +.. figure:: dummy.png + + The figure's caption, no legend. +""", +"""\ +<figure> +<img alt="dummy.png" src="dummy.png" /> +<figcaption> +<p>The figure's caption, no legend.</p> +</figcaption> +</figure> +""", +], +["""\ +.. figure:: dummy.png + + .. + + A legend without caption. +""", +"""\ +<figure> +<img alt="dummy.png" src="dummy.png" /> +<figcaption> +<div class="legend"> +<p>A legend without caption.</p> +</div> +</figcaption> +</figure> +""", +], +["""\ +.. figure:: dummy.png + +No caption nor legend. +""", +"""\ +<figure> +<img alt="dummy.png" src="dummy.png" /> +</figure> +<p>No caption nor legend.</p> +""", +], +[f"""\ +.. include:: {DATA_ROOT}/multiple-term-definition.xml + :parser: xml +""", +"""\ +<dl> +<dt>New in Docutils 0.22</dt> +<dd><p>A definition list item may contain several +terms with optional classifier(s).</p> +<p>However, there is currently no corresponding +reStructuredText syntax.</p> +</dd> +<dt>term 2a</dt> +<dt>term 2b</dt> +<dd><p>definition 2</p> +</dd> +<dt>term 3a<span class="classifier">classifier 3a</span><span class="classifier">classifier 3aa</span><dt>term 3b<span class="classifier">classifier 3b</span></dt> +<dd><p>definition 3</p> +</dd> +</dl> +""", +], +]) + + +totest['lazy_loading'] = ({'image_loading': 'lazy', + 'report_level': 4}, [ +["""\ +Lazy loading by default, overridden by :loading: option +("cannot embed" warning ignored). + +.. image:: dummy.png +.. image:: dummy.png + :loading: link +.. figure:: dummy.png +.. figure:: dummy.png + :loading: embed +""", +"""\ +<p>Lazy loading by default, overridden by :loading: option +("cannot embed" warning ignored).</p> +<img alt="dummy.png" loading="lazy" src="dummy.png" /> +<img alt="dummy.png" src="dummy.png" /> +<figure> +<img alt="dummy.png" loading="lazy" src="dummy.png" /> +</figure> +<figure> +<img alt="dummy.png" src="dummy.png" /> +</figure> +""", +], +]) + + +totest['root_prefix'] = ({'root_prefix': ROOT_PREFIX, + 'image_loading': 'embed', + 'warning_stream': '', + }, [ +["""\ +.. image:: /data/blue%20square.png + :scale: 100% +.. figure:: /data/blue%20square.png +""", +'<img alt="/data/blue%20square.png" src="data:image/png;base64,' +'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALElEQVR4nO3NMQ' +'EAMAjAsDFjvIhHFCbgSwU0kdXvsn96BwAAAAAAAAAAAIsNnEwBk52VRuMAAAAA' +'SUVORK5CYII="' +f' {SCALING_OUTPUT}/>\n{NO_PIL_SYSTEM_MESSAGE}' +'<figure>\n' +'<img alt="/data/blue%20square.png" src="data:image/png;base64,' +'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALElEQVR4nO3NMQ' +'EAMAjAsDFjvIhHFCbgSwU0kdXvsn96BwAAAAAAAAAAAIsNnEwBk52VRuMAAAAA' +'SUVORK5CYII=" />\n' +'</figure>\n', +], +]) + + +totest['no_backlinks'] = ({'footnote_backlinks': False}, [ + +["""\ +Two footnotes [#f1]_ [#f2]_ and two citations [once]_ [twice]_. + +The latter are referenced a second time [#f2]_ [twice]_. + +.. [#f1] referenced once +.. [#f2] referenced twice +.. [once] citation referenced once +.. [twice] citation referenced twice +""", +"""\ +<p>Two footnotes <a class="brackets" href="#f1" id="footnote-reference-1" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> <a class="brackets" href="#f2" id="footnote-reference-2" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> and two citations <a class="citation-reference" href="#once" id="citation-reference-1" role="doc-biblioref">[once]</a> <a class="citation-reference" href="#twice" id="citation-reference-2" role="doc-biblioref">[twice]</a>.</p> +<p>The latter are referenced a second time <a class="brackets" href="#f2" id="footnote-reference-3" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> <a class="citation-reference" href="#twice" id="citation-reference-3" role="doc-biblioref">[twice]</a>.</p> +<aside class="footnote-list brackets"> +<aside class="footnote brackets" id="f1" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> +<p>referenced once</p> +</aside> +<aside class="footnote brackets" id="f2" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></span> +<p>referenced twice</p> +</aside> +</aside> +<div role="list" class="citation-list"> +<div class="citation" id="once" role="doc-biblioentry"> +<span class="label"><span class="fn-bracket">[</span>once<span class="fn-bracket">]</span></span> +<p>citation referenced once</p> +</div> +<div class="citation" id="twice" role="doc-biblioentry"> +<span class="label"><span class="fn-bracket">[</span>twice<span class="fn-bracket">]</span></span> +<p>citation referenced twice</p> +</div> +</div> +""", +], +]) + + +totest['syntax_highlight'] = ({'syntax_highlight': 'short', + }, [ +["""\ +.. code:: shell + + cat <<EOF + Hello World + EOF +""", +"""\ +<pre class="code shell literal-block"><code>cat <span class="s"><<EOF +Hello World +EOF</span></code></pre> +""", +], +["""\ +.. role:: shell(code) + :language: shell + +:shell:`cat <<EOF Hello World EOF` +""", +"""\ +<p><code class="shell">cat <span class="s"><<EOF Hello World EOF</span></code></p> +""", +], +]) + + +totest['system_messages'] = ({'math_output': 'mathml', + 'warning_stream': '', + }, [ +["""\ +.. image:: https://dummy.png + :loading: embed +""", +"""\ +<img alt="https://dummy.png" src="https://dummy.png" /> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 \ +(<span class="docutils literal"><string></span>, line 1)</p> +<p>Cannot embed image "https://dummy.png": + Can only read local images.</p> +</aside> +""", +], +[f"""\ +.. image:: {DATA_ROOT.as_uri()}/circle-broken.svg + :loading: embed +""", +f"""\ +<svg xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 10 10"> + <circle cx="5" cy="5" r="4" fill="lightblue" x/> +</svg> + +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal"><string></span>, line 1)</p> +<p>Cannot parse SVG image "{DATA_ROOT.as_uri()}/circle-broken.svg": + not well-formed (invalid token): line 3, column 48</p> +</aside> +""" +], +[r"""Broken :math:`\sin \my`. +""", +"""\ +<p>Broken <span class="math problematic">\\sin \\my</span>.</p> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal"><string></span>, line 1)</p> +<p>Unknown LaTeX command "\\my".</p> +</aside> +"""], +]) + +totest['system_messages-PIL'] = ({'math_output': 'mathml', + 'warning_stream': '', + }, [ +["""\ +.. image:: dummy.png + :scale: 100% + :loading: embed +""", +f"""\ +<img alt="dummy.png" src="dummy.png" /> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 \ +(<span class="docutils literal"><string></span>, line 1)</p> +<p>Cannot scale image! + Could not get size from "dummy.png": + {DUMMY_PNG_NOT_FOUND}</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 \ +(<span class="docutils literal"><string></span>, line 1)</p> +<p>Cannot embed image "dummy.png": + [Errno 2] No such file or directory: 'dummy.png'</p> +</aside> +""", +], +["""\ +.. image:: dummy.mp4 + :scale: 100% +""", +f"""\ +<video src="dummy.mp4" title="dummy.mp4"> +<a href="dummy.mp4">dummy.mp4</a> +</video> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 \ +(<span class="docutils literal"><string></span>, line 1)</p> +<p>Cannot scale image! + Could not get size from "dummy.mp4":{REQUIRES_PIL} + PIL cannot read video images.</p> +</aside> +""", +], +["""\ +.. image:: https://dummy.png + :scale: 100% + :loading: embed +""", +f"""\ +<img alt="https://dummy.png" src="https://dummy.png" /> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 \ +(<span class="docutils literal"><string></span>, line 1)</p> +<p>Cannot scale image! + Could not get size from "https://dummy.png": + {ONLY_LOCAL}</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 \ +(<span class="docutils literal"><string></span>, line 1)</p> +<p>Cannot embed image "https://dummy.png": + Can only read local images.</p> +</aside> +""", +], +]) + +totest['no_system_messages'] = ({'math_output': 'mathml', + 'report_level': 4, + 'warning_stream': '', + }, [ +["""\ +.. image:: dummy.png + :scale: 100% + :loading: embed + +.. image:: dummy.mp4 + :scale: 100% +""", +"""\ +<img alt="dummy.png" src="dummy.png" /> +<video src="dummy.mp4" title="dummy.mp4"> +<a href="dummy.mp4">dummy.mp4</a> +</video> +""", +], +[f"""\ +.. image:: {DATA_ROOT.as_uri()}/circle-broken.svg + :loading: embed +""", +"""\ +<svg xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 10 10"> + <circle cx="5" cy="5" r="4" fill="lightblue" x/> +</svg> + +"""], +[r'Broken :math:`\sin \my`.', +'<p>Broken <tt class="math">\\sin \\my</tt>.</p>\n' +], +]) + + +if __name__ == '__main__': + unittest.main() Property changes on: trunk/docutils/test/test_writers/test_html5_polyglot.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Modified: trunk/docutils/test/test_writers/test_html5_polyglot_misc.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot_misc.py 2024-08-21 13:44:37 UTC (rev 9912) +++ trunk/docutils/test/test_writers/test_html5_polyglot_misc.py 2024-08-21 13:44:48 UTC (rev 9913) @@ -36,7 +36,7 @@ # error handler. settings_overrides = { 'output_encoding': 'latin1', - 'stylesheet': '', + 'stylesheet_path': '', '_disable_config': True} result = core.publish_string( 'EUR = \u20ac', writer='html5_polyglot', @@ -49,7 +49,6 @@ class MovingArgsTestCase(unittest.TestCase): mys = {'stylesheet_path': '', - # 'embed_stylesheet': False, '_disable_config': True, } @@ -99,8 +98,8 @@ mys = {'_disable_config': True} styles = core.publish_parts(self.data, writer='html5_polyglot', settings_overrides=mys)['stylesheet'] - self.assertIn('Minimal style sheet ' - 'for the HTML output of Docutils.', styles) + self.assertIn('Minimal style sheet for the HTML output of Docutils.', + styles) def test_default_stylesheet_linked(self): # default style sheet, linked @@ -141,7 +140,8 @@ styles = core.publish_parts(self.data, writer='html5_polyglot', settings_overrides=mys)['stylesheet'] if (TEST_ROOT / '../docutils/writers/html5_polyglot/').is_dir(): - self.assertIn('docutils/writers/html5_polyglot/minimal.css', styles) + self.assertIn('docutils/writers/html5_polyglot/minimal.css', + styles) self.assertIn(f'href="{ham_css}"', styles) def test_custom_stylesheet_dir_embedded(self): Modified: trunk/docutils/test/test_writers/test_html5_polyglot_parts.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot_parts.py 2024-08-21 13:44:37 UTC (rev 9912) +++ trunk/docutils/test/test_writers/test_html5_polyglot_parts.py 2024-08-21 13:44:48 UTC (rev 9913) @@ -5,15 +5,12 @@ # Copyright: This module has been placed in the public domain. """ -Test for fragment code in HTML writer. +Test `core.publish_parts()`__ with the HTML5 writer. -Note: the 'body' and 'whole' entries have been removed from the parts -dictionaries (redundant), along with 'meta' and 'stylesheet' entries with -standard values, and any entries with empty values. +__ https://docutils.sourceforge.io/docs/api/publisher.html#publish-parts """ from pathlib import Path -import re import sys import unittest @@ -24,182 +21,136 @@ import docutils import docutils.core -from docutils.parsers.rst.directives.images import PIL -from docutils.utils.code_analyzer import with_pygments +from docutils.writers import html5_polyglot -if with_pygments: - import pygments - _pv = re.match(r'^([0-9]+)\.([0-9]*)', pygments.__version__) - if (int(_pv[1]), int(_pv[2])) >= (2, 14): - # pygments output changed in version 2.14 - with_pygments = False - # TEST_ROOT is ./test/ from the docutils root TEST_ROOT = Path(__file__).parents[1] DATA_ROOT = TEST_ROOT / 'data' ROOT_PREFIX = (TEST_ROOT / 'functional/input').as_posix() -# Pillow/PIL is optional: -if PIL: - REQUIRES_PIL = '' - ONLY_LOCAL = 'Can only read local images.' - DUMMY_PNG_NOT_FOUND = "[Errno 2] No such file or directory: 'dummy.png'" - # Pillow reports the absolute path since version 10.3.0 (cf. [bugs: 485]) - if (tuple(int(i) for i in PIL.__version__.split('.')) >= (10, 3)): - DUMMY_PNG_NOT_FOUND = ("[Errno 2] No such file or directory: '%s'" - % Path('dummy.png').resolve()) - SCALING_OUTPUT = 'style="width: 32.0px; height: 32.0px;" ' - NO_PIL_SYSTEM_MESSAGE = '' -else: - REQUIRES_PIL = '\n Requires Python Imaging Library.' - ONLY_LOCAL = 'Requires Python Imaging Library.' - DUMMY_PNG_NOT_FOUND = 'Requires Python Imaging Library.' - SCALING_OUTPUT = '' - NO_PIL_SYSTEM_MESSAGE = ( - '<aside class="system-message">\n' - '<p class="system-message-title">System Message:' - ' WARNING/2 (<span class="docutils literal">' - '<string></span>, line 1)</p>\n' - '<p>Cannot scale image!\n' - ' Could not get size from "/data/blue%20square.png":\n' - ' Requires Python Imaging Library.</p>\n' - '</aside>\n') +# Parts returned by `publish_parts()` for the HTML5 writer by default: +# * empty input string +# * default configuration settings. +# See format_parts() below for the substitution of unresolved format markers. +default_parts = { + 'body': '{fragment}', + 'body_pre_docinfo': '', + 'body_prefix': '</head>\n<body>\n{header}<main>\n', + 'body_suffix': '</main>\n{footer}</body>\n</html>\n', + 'docinfo': '', + 'encoding': 'utf-8', + 'errors': 'xmlcharrefreplace', + 'footer': '', + 'fragment': '', + 'head': '{meta}<title>{metatitle}</title>\n', + 'head_prefix': + '<!DOCTYPE html>\n' + '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n' + '<head>\n', + 'header': '', + 'html_body': '{header}<main>\n{fragment}</main>\n{footer}', + 'html_head': '{meta}<title>{metatitle}</title>\n', + 'html_prolog': '<!DOCTYPE html>\n', + 'html_subtitle': '', + 'html_title': '', + 'meta': '<meta charset="%s" />\n' + f'<meta name="generator" content="Docutils {docutils.__version__}: https://docutils.sourceforge.io/" />\n' + '<meta name="viewport" content="width=device-width, initial-scale=1" />\n', + 'stylesheet': '', + 'subtitle': '', + 'title': '', + 'version': f'{docutils.__version__}', + 'whole': + '{head_prefix}\n' + '{head}\n' + '{stylesheet}\n' + '{body_prefix}\n' + '{body_pre_docinfo}\n' + '{docinfo}\n' + '{body}\n' + '{body_suffix}\n', + } + +def format_parts(parts): + # fill in part values that depend on other parts + # https://docutils.sourceforge.io/docs/api/publisher.html#html4-writer + + # metadata title: either the visible title or document['source'] + metatitle = parts['title'] or '<string>' + + # "html_head" leaves the encoding unresolved, as "%s": + parts['html_head'] = parts['html_head'].format(metatitle=metatitle, + **parts) + # now resolve encoding: + try: + parts['meta'] = parts['meta'] % parts['encoding'] + except TypeError: # charset-<meta> missing if encoding is 'unicode' + pass + parts['head'] = parts['head'].format(metatitle=metatitle, **parts) + parts['body_prefix'] = parts['body_prefix'].format(**parts) + parts['body'] = parts['body'].format(**parts) + parts['body_suffix'] = parts['body_suffix'].format(**parts) + parts['html_body'] = parts['html_body'].format(**parts) + # newlines are stripped when parts are used to expand the template file + parts['whole'] = parts['whole'].format(**{k: v.rstrip('\n') + for k, v in parts.items()}) + return parts + + class Html5WriterPublishPartsTestCase(unittest.TestCase): - """Test case for HTML writer via the publish_parts interface.""" + """Test HTML5 writer `publish_parts()` interface.""" maxDiff = None - def test_publish(self): - if not with_pygments: - del totest['syntax_highlight'] - writer = 'html5' + def test_publish_parts(self): for name, (settings_overrides, cases) in totest.items(): - for casenum, (case_input, case_expected) in enumerate(cases): - with self.subTest(id=f'totest[{name!r}][{casenum}]'): - parts = docutils.core.publish_parts( - source=case_input, - writer=writer, - settings_overrides={ - '_disable_config': True, - 'strict_visitor': True, - 'stylesheet_path': '', - 'section_self_link': True, - **settings_overrides, - } - ) - # if the formatted output is a just single fragment, - # compare the text directly for a nicer diff on failure - formatted = self.format_output(parts) - if len(formatted) == 1 and 'fragment' in formatted: - fragment = formatted['fragment'] - self.assertEqual(case_expected, fragment) - else: - self.assertEqual(case_expected, formatted) + for casenum, (case_input, expected_parts) in enumerate(cases): + _stgns = {'_disable_config': True, + 'strict_visitor': True, + 'stylesheet_path': '', + 'section_self_link': True, + **settings_overrides, + } + parts = docutils.core.publish_parts(source=case_input, + writer=html5_polyglot.Writer(), + settings_overrides=_stgns, + ) + expected = format_parts(default_parts | expected_parts) + for key in parts.keys(): + with self.subTest(id=f'totest[{name!r}][{casenum}][{key}]'): + self.assertEqual(f'{expected[key]}', + f'{parts[key]}') - standard_content_type_template = '<meta charset="%s" />\n' - standard_generator_template = ( - '<meta name="generator"' - f' content="Docutils {docutils.__version__}: ' - 'https://docutils.sourceforge.io/" />\n') - standard_viewport_value = ( - '<meta name="viewport"' - ' content="width=device-width, initial-scale=1" />\n') - standard_html_meta_value = (standard_content_type_template - + standard_generator_template - + standard_viewport_value) - standard_meta_value = standard_html_meta_value % 'utf-8' - standard_html_prolog = '<!DOCTYPE html>\n' - standard_html_body_template = '<main>\n%s</main>\n' - def format_output(self, parts): - """Minimize & standardize the output.""" - # remove redundant parts & uninteresting parts: - del parts['whole'] - assert parts['body'] == parts['fragment'] - del parts['body'] - del parts['body_pre_docinfo'] - del parts['body_prefix'] - del parts['body_suffix'] - del parts['head'] - del parts['head_prefix'] - del parts['encoding'] - del parts['errors'] - del parts['version'] - # remove standard portions: - parts['meta'] = parts['meta'].replace(self.standard_meta_value, '') - parts['html_head'] = parts['html_head'].replace( - self.standard_html_meta_value, '...') - parts['html_head'] = parts['html_head'].replace( - '...<title><string></title>\n', '') - parts['html_prolog'] = parts['html_prolog'].replace( - self.standard_html_prolog, '') - parts['html_body'] = parts['html_body'].replace( - self.standard_html_body_template % parts['fragment'], '') - # remove empty keys and return - return {k: v for k, v in parts.items() if v} - - totest = {} totest['standard'] = ({}, [ -["""\ -Simple String -""", -'<p>Simple String</p>\n', -], -["""\ -Simple String with *markup* -""", -'<p>Simple String with <em>markup</em></p>\n', -], -["""\ -Simple String with an even simpler ``inline literal`` -""", -'<p>Simple String with an even simpler <span class="docutils literal">inline literal</span></p>\n', -], -["""\ -A simple `anonymous reference`__ - -__ http://www.test.com/test_url -""", -'<p>A simple <a class="reference external" href="http://www.test.com/test_url">anonymous reference</a></p>\n', -], -["""\ -One paragraph. - -Two paragraphs. -""", -"""\ -<p>One paragraph.</p> -<p>Two paragraphs.</p> -""", -], -["""\ -A simple `named reference`_ with stuff in between the -reference and the target. - -.. _`named reference`: http://www.test.com/test_url -""", -"""\ -<p>A simple <a class="reference external" href="http://www.test.com/test_url">named reference</a> with stuff in between the -reference and the target.</p> -""", -], -["""\ -.. [CIT2022] A citation. -""", -"""\ -<div role="list" class="citation-list"> -<div class="citation" id="cit2022" role="doc-biblioentry"> -<span class="label"><span class="fn-bracket">[</span>CIT2022<span class="fn-bracket">]</span></span> -<p>A citation.</p> -</div> -</div> -""", -], -["""\ + ['', # empty input string + {} # results in default parts + ], + ['Simple String with *markup*', + {'fragment': '<p>Simple String with <em>markup</em></p>\n'} + ], + ['.. header:: custom document header\n\n' + 'A paragraph.', + {'header': '<header>\n<p>custom document header</p>\n</header>\n', + 'body_prefix': '</head>\n' + '<body>\n' + '<header>\n' + '<p>custom document header</p>\n</header>\n' + '<main>\n', + 'fragment': '<p>A paragraph.</p>\n', + } + ], + ['.. footer:: custom document footer\n\n' + 'A paragraph.', + {'footer': '<footer>\n<p>custom document footer</p>\n</footer>\n', + 'fragment': '<p>A paragraph.</p>\n', + } + ], + ["""\ +++++ Title +++++ @@ -219,7 +170,10 @@ And even more stuff """, -{'fragment': """\ + {'body_pre_docinfo': '<h1 class="title">Title</h1>\n' + '<p class="subtitle" id="subtitle">Subtitle</p>\n', + 'body_prefix': '</head>\n<body>\n<main id="title">\n', + 'fragment': """\ <p>Some stuff</p> <section id="section"> <h2>Section<a class="self-link" title="link to this section" href="#section"></a></h2> @@ -230,7 +184,7 @@ </section> </section> """, - 'html_body': """\ + 'html_body': """\ <main id="title"> <h1 class="title">Title</h1> <p class="subtitle" id="subtitle">Subtitle</p> @@ -245,13 +199,12 @@ </section> </main> """, - 'html_head': '...<title>Title</title>\n', - 'html_subtitle': '<p class="subtitle" id="subtitle">Subtitle</p>\n', - 'html_title': '<h1 class="title">Title</h1>\n', - 'subtitle': 'Subtitle', - 'title': 'Title' -}], -["""\ + 'html_subtitle': '<p class="subtitle" id="subtitle">Subtitle</p>\n', + 'html_title': '<h1 class="title">Title</h1>\n', + 'subtitle': 'Subtitle', + 'title': 'Title' + }], + ["""\ +++++ Title +++++ @@ -260,14 +213,16 @@ Some stuff """, -{'docinfo': """\ + {'body_pre_docinfo': '<h1 class="title">Title</h1>\n', + 'body_prefix': '</head>\n<body>\n<main id="title">\n', + 'docinfo': """\ <dl class="docinfo simple"> <dt class="author">Author<span class="colon">:</span></dt> <dd class="author"><p>me</p></dd> </dl> """, - 'fragment': '<p>Some stuff</p>\n', - 'html_body': """\ + 'fragment': '<p>Some stuff</p>\n', + 'html_body': """\ <main id="title"> <h1 class="title">Title</h1> <dl class="docinfo simple"> @@ -277,63 +232,14 @@ <p>Some stuff</p> </main> """, - 'html_head': """\ -...<meta name="author" content="me" /> -<title>Title</title> -""", - 'html_title': '<h1 class="title">Title</h1>\n', - 'meta': '<meta name="author" content="me" />\n', - 'title': 'Title' -}], -]) + 'html_title': '<h1 class="title">Title</h1>\n', + 'meta': default_parts['meta'] + '<meta name="author" content="me" />\n', + 'title': 'Title' + }], + ]) -totest['standard'] = ({'output_encoding': 'unicode'}, [ -["""\ -Simple String -""", -{'fragment': '<p>Simple String</p>\n', - 'meta': """\ -<meta name="generator" content="Docutils 0.22b.dev: https://docutils.sourceforge.io/" /> -<meta name="viewport" content="width=device-width, initial-scale=1" /> -""", -}], -]) - totest['no_title_promotion'] = ({'doctitle_xform': False}, [ -["""\ -Simple String -""", -'<p>Simple String</p>\n', -], -["""\ -Simple String with *markup* -""", -'<p>Simple String with <em>markup</em></p>\n', -], -["""\ -Simple String with an even simpler ``inline literal`` -""", -'<p>Simple String with an even simpler <span class="docutils literal">inline literal</span></p>\n', -], -["""\ -A simple `anonymous reference`__ - -__ http://www.test.com/test_url -""", -'<p>A simple <a class="reference external" href="http://www.test.com/test_url">anonymous reference</a></p>\n', -], -["""\ -A simple `named reference`_ with stuff in between the -reference and the target. - -.. _`named reference`: http://www.test.com/test_url -""", -"""\ -<p>A simple <a class="reference external" href="http://www.test.com/test_url">named reference</a> with stuff in between the -reference and the target.</p> -""", -], -["""\ + ["""\ +++++ Title +++++ @@ -353,7 +259,7 @@ And even more stuff """, -"""\ + {'fragment': """\ <section id="title"> <h2>Title<a class="self-link" title="link to this section" href="#title"></a></h2> <section id="not-a-subtitle"> @@ -369,486 +275,19 @@ </section> </section> </section> -""", -], -["""\ -* bullet -* list -""", -"""\ -<ul class="simple"> -<li><p>bullet</p></li> -<li><p>list</p></li> -</ul> -""", -], -["""\ -.. table:: - :align: right +"""}, + ], + ]) - +-----+-----+ - | 1 | 2 | - +-----+-----+ - | 3 | 4 | - +-----+-----+ -""", -"""\ -<table class="align-right"> -<tbody> -<tr><td><p>1</p></td> -<td><p>2</p></td> -</tr> -<tr><td><p>3</p></td> -<td><p>4</p></td> -</tr> -</tbody> -</table> -""", -], -["""\ -Not a docinfo. +totest['unknown-encoding'] = ({'output_encoding': 'unicode'}, [ + ['Simple String\n', + {'encoding': 'unicode', + 'fragment': '<p>Simple String</p>\n', + 'html_head': f'{default_parts["meta"]}<title>{{metatitle}}</title>\n', + 'meta': default_parts['meta'].removeprefix('<meta charset="%s" />\n'), + }], + ]) -:This: .. _target: - is -:a: -:simple: -:field: list -""", -"""\ -<p>Not a docinfo.</p> -<dl class="field-list simple"> -<dt>This<span class="colon">:</span></dt> -<dd><p id="target">is</p> -</dd> -<dt>a<span class="colon">:</span></dt> -<dd><p></p></dd> -<dt>simple<span class="colon">:</span></dt> -<dd><p></p></dd> -<dt>field<span class="colon">:</span></dt> -<dd><p>list</p> -</dd> -</dl> -""", -], -["""\ -Not a docinfo. - -:This is: a -:simple field list with loooong field: names -""", -"""\ -<p>Not a docinfo.</p> -<dl class="field-list simple"> -<dt>This is<span class="colon">:</span></dt> -<dd><p>a</p> -</dd> -<dt>simple field list with loooong field<span class="colon">:</span></dt> -<dd><p>names</p> -</dd> -</dl> -""", -], -["""\ -Not a docinfo. - -.. class:: field-indent-200 - -:This: is a -:simple: field list with custom indent. -""", -"""\ -<p>Not a docinfo.</p> -<dl class="field-list simple" style="--field-indent: 200px;"> -<dt>This<span class="colon">:</span></dt> -<dd><p>is a</p> -</dd> -<dt>simple<span class="colon">:</span></dt> -<dd><p>field list with custom indent.</p> -</dd> -</dl> -""", -], -["""\ -Not a docinfo. - -.. class:: field-indent-200uf - -:This: is a -:simple: field list without custom indent, - because the unit "uf" is invalid. -""", -"""\ -<p>Not a docinfo.</p> -<dl class="field-indent-200uf field-list simple"> -<dt>This<span class="colon">:</span></dt> -<dd><p>is a</p> -</dd> -<dt>simple<span class="colon">:</span></dt> -<dd><p>field list without custom indent, -because the unit "uf" is invalid.</p> -</dd> -</dl> -""", -], -["""\ -.. figure:: dummy.png - - The figure's caption. - - A legend. - - The legend's second paragraph. -""", -"""\ -<figure> -<img alt="dummy.png" src="dummy.png" /> -<figcaption> -<p>The figure's caption.</p> -<div class="legend"> -<p>A legend.</p> -<p>The legend's second paragraph.</p> -</div> -</figcaption> -</figure> -""", -], -["""\ -.. figure:: dummy.png - - The figure's caption, no legend. -""", -"""\ -<figure> -<img alt="dummy.png" src="dummy.png" /> -<figcaption> -<p>The figure's caption, no legend.</p> -</figcaption> -</figure> -""", -], -["""\ -.. figure:: dummy.png - - .. - - A legend without caption. -""", -"""\ -<figure> -<img alt="dummy.png" src="dummy.png" /> -<figcaption> -<div class="legend"> -<p>A legend without caption.</p> -</div> -</figcaption> -</figure> -""", -], -["""\ -.. figure:: dummy.png - -No caption nor legend. -""", -"""\ -<figure> -<img alt="dummy.png" src="dummy.png" /> -</figure> -<p>No caption nor legend.</p> -""", -], -[f"""\ -.. include:: {DATA_ROOT}/multiple-term-definition.xml - :parser: xml -""", -"""\ -<dl> -<dt>New in Docutils 0.22</dt> -<dd><p>A definition list item may contain several -terms with optional classifier(s).</p> -<p>However, there is currently no corresponding -reStructuredText syntax.</p> -</dd> -<dt>term 2a</dt> -<dt>term 2b</dt> -<dd><p>definition 2</p> -</dd> -<dt>term 3a<span class="classifier">classifier 3a</span><span class="classifier">classifier 3aa</span><dt>term 3b<span class="classifier">classifier 3b</span></dt> -<dd><p>definition 3</p> -</dd> -</dl> -""", -], -]) - - -totest['lazy_loading'] = ({'image_loading': 'lazy', - 'report_level': 4}, [ -["""\ -Lazy loading by default, overridden by :loading: option -("cannot embed" warning ignored). - -.. image:: dummy.png -.. image:: dummy.png - :loading: link -.. figure:: dummy.png -.. figure:: dummy.png - :loading: embed -""", -"""\ -<p>Lazy loading by default, overridden by :loading: option -("cannot embed" warning ignored).</p> -<img alt="dummy.png" loading="lazy" src="dummy.png" /> -<img alt="dummy.png" src="dummy.png" /> -<figure> -<img alt="dummy.png" loading="lazy" src="dummy.png" /> -</figure> -<figure> -<img alt="dummy.png" src="dummy.png" /> -</figure> -""", -], -]) - - -totest['root_prefix'] = ({'root_prefix': ROOT_PREFIX, - 'image_loading': 'embed', - 'warning_stream': '', - }, [ -["""\ -.. image:: /data/blue%20square.png - :scale: 100% -.. figure:: /data/blue%20square.png -""", -'<img alt="/data/blue%20square.png" src="data:image/png;base64,' -'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALElEQVR4nO3NMQ' -'EAMAjAsDFjvIhHFCbgSwU0kdXvsn96BwAAAAAAAAAAAIsNnEwBk52VRuMAAAAA' -'SUVORK5CYII="' -f' {SCALING_OUTPUT}/>\n{NO_PIL_SYSTEM_MESSAGE}' -'<figure>\n' -'<img alt="/data/blue%20square.png" src="data:image/png;base64,' -'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALElEQVR4nO3NMQ' -'EAMAjAsDFjvIhHFCbgSwU0kdXvsn96BwAAAAAAAAAAAIsNnEwBk52VRuMAAAAA' -'SUVORK5CYII=" />\n' -'</figure>\n', -], -]) - - -totest['no_backlinks'] = ({'footnote_backlinks': False}, [ - -["""\ -Two footnotes [#f1]_ [#f2]_ and two citations [once]_ [twice]_. - -The latter are referenced a second time [#f2]_ [twice]_. - -.. [#f1] referenced once -.. [#f2] referenced twice -.. [once] citation referenced once -.. [twice] citation referenced twice -""", -"""\ -<p>Two footnotes <a class="brackets" href="#f1" id="footnote-reference-1" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> <a class="brackets" href="#f2" id="footnote-reference-2" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> and two citations <a class="citation-reference" href="#once" id="citation-reference-1" role="doc-biblioref">[once]</a> <a class="citation-reference" href="#twice" id="citation-reference-2" role="doc-biblioref">[twice]</a>.</p> -<p>The latter are referenced a second time <a class="brackets" href="#f2" id="footnote-reference-3" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> <a class="citation-reference" href="#twice" id="citation-reference-3" role="doc-biblioref">[twice]</a>.</p> -<aside class="footnote-list brackets"> -<aside class="footnote brackets" id="f1" role="doc-footnote"> -<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> -<p>referenced once</p> -</aside> -<aside class="footnote brackets" id="f2" role="doc-footnote"> -<span class="label"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></span> -<p>referenced twice</p> -</aside> -</aside> -<div role="list" class="citation-list"> -<div class="citation" id="once" role="doc-biblioentry"> -<span class="label"><span class="fn-bracket">[</span>once<span class="fn-bracket">]</span></span> -<p>citation referenced once</p> -</div> -<div class="citation" id="twice" role="doc-biblioentry"> -<span class="label"><span class="fn-bracket">[</span>twice<span class="fn-bracket">]</span></span> -<p>citation referenced twice</p> -</div> -</div> -""", -], -]) - - -totest['syntax_highlight'] = ({'syntax_highlight': 'short', - }, [ -["""\ -.. code:: shell - - cat <<EOF - Hello World - EOF -""", -"""\ -<pre class="code shell literal-block"><code>cat <span class="s"><<EOF -Hello World -EOF</span></code></pre> -""", -], -["""\ -.. role:: shell(code) - :language: shell - -:shell:`cat <<EOF Hello World EOF` -""", -"""\ -<p><code class="shell">cat <span class="s"><<EOF Hello World EOF</span></code></p> -""", -], -]) - - -totest['system_messages'] = ({'math_output': 'mathml', - 'warning_stream': '', - }, [ -["""\ -.. image:: https://dummy.png - :loading: embed -""", -"""\ -<img alt="https://dummy.png" src="https://dummy.png" /> -<aside class="system-message"> -<p class="system-message-title">System Message: ERROR/3 \ -(<span class="docutils literal"><string></span>, line 1)</p> -<p>Cannot embed image "https://dummy.png": - Can only read local images.</p> -</aside> -""", -], -[f"""\ -.. image:: {DATA_ROOT.as_uri()}/circle-broken.svg - :loading: embed -""", -f"""\ -<svg xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 10 10"> - <circle cx="5" cy="5" r="4" fill="lightblue" x/> -</svg> - -<aside class="system-message"> -<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal"><string></span>, line 1)</p> -<p>Cannot parse SVG image "{DATA_ROOT.as_uri()}/circle-broken.svg": - not well-formed (invalid token): line 3, column 48</p> -</aside> -""" -], -[r"""Broken :math:`\sin \my`. -""", -"""\ -<p>Broken <span class="math problematic">\\sin \\my</span>.</p> -<aside class="system-message"> -<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal"><string></span>, line 1)</p> -<p>Unknown LaTeX command "\\my".</p> -</aside> -"""], -]) - -totest['system_messages-PIL'] = ({'math_output': 'mathml', - 'warning_stream': '', - }, [ -["""\ -.. image:: dummy.png - :scale: 100% - :loading: embed -""", -f"""\ -<img alt="dummy.png" src="dummy.png" /> -<aside class="system-message"> -<p class="system-message-title">System Message: WARNING/2 \ -(<span class="docutils literal"><string></span>, line 1)</p> -<p>Cannot scale image! - Could not get size from "dummy.png": - {DUMMY_PNG_NOT_FOUND}</p> -</aside> -<aside class="system-message"> -<p class="system-message-title">System Message: ERROR/3 \ -(<span class="docutils literal"><string></span>, line 1)</p> -<p>Cannot embed image "dummy.png": - [Errno 2] No such file or directory: 'dummy.png'</p> -</aside> -""", -], -["""\ -.. image:: dummy.mp4 - :scale: 100% -""", -f"""\ -<video src="dummy.mp4" title="dummy.mp4"> -<a href="dummy.mp4">dummy.mp4</a> -</video> -<aside class="system-message"> -<p class="system-message-title">System Message: WARNING/2 \ -(<span class="docutils literal"><string></span>, line 1)</p> -<p>Cannot scale image! - Could not get size from "dummy.mp4":{REQUIRES_PIL} - PIL cannot read video images.</p> -</aside> -""", -], -["""\ -.. image:: https://dummy.png - :scale: 100% - :loading: embed -""", -f"""\ -<img alt="https://dummy.png" src="https://dummy.png" /> -<aside class="system-message"> -<p class="system-message-title">System Message: WARNING/2 \ -(<span class="docutils literal"><string></span>, line 1)</p> -<p>Cannot scale image! - Could not get size from "https://dummy.png": - {ONLY_LOCAL}</p> -</aside> -<aside class="system-message"> -<p class="system-message-title">System Message: ERROR/3 \ -(<span class="docutils literal"><string></span>, line 1)</p> -<p>Cannot embed image "https://dummy.png": - Can only read local images.</p> -</aside> -""", -], -]) - -totest['no_system_messages'] = ({'math_output': 'mathml', - 'report_level': 4, - 'warning_stream': '', - }, [ -["""\ -.. image:: dummy.png - :scale: 100% - :loading: embed - -.. image:: dummy.mp4 - :scale: 100% -""", -"""\ -<img alt="dummy.png" src="dummy.png" /> -<video src="dummy.mp4" title="dummy.mp4"> -<a href="dummy.mp4">dummy.mp4</a> -</video> -""", -], -[f"""\ -.. image:: {DATA_ROOT.as_uri()}/circle-broken.svg - :loading: embed -""", -"""\ -<svg xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 10 10"> - <circle cx="5" cy="5" r="4" fill="lightblue" x/> -</svg> - -"""], -[r'Broken :math:`\sin \my`.', -'<p>Broken <tt class="math">\\sin \\my</tt>.</p>\n' -], -]) - - if __name__ == '__main__': unittest.main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-04 19:33:14
|
Revision: 9919 http://sourceforge.net/p/docutils/code/9919 Author: milde Date: 2024-09-04 19:33:12 +0000 (Wed, 04 Sep 2024) Log Message: ----------- New function `nodes.parse_measure()`. Relax `validate_measure()`. Allow "arbitrary" units: Check for a run of ASCII-letters or a percent sign. (The definition of "measure" in docutils.dtd and its description in doctree.txt do not include a restriction of the valid units.) Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/docutils/nodes.py trunk/docutils/docutils/parsers/rst/directives/__init__.py trunk/docutils/test/test_nodes.py trunk/docutils/test/test_parsers/test_docutils_xml/test_parse_element.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-04 06:16:29 UTC (rev 9918) +++ trunk/docutils/HISTORY.rst 2024-09-04 19:33:12 UTC (rev 9919) @@ -63,6 +63,7 @@ convert string representations to correct data type, normalize values, raise ValueError for invalid attribute names or values. + - New function `parse_measure()`. - Removed `Element.set_class()`. * docutils/parsers/docutils_xml.py Modified: trunk/docutils/docutils/nodes.py =================================================================== --- trunk/docutils/docutils/nodes.py 2024-09-04 06:16:29 UTC (rev 9918) +++ trunk/docutils/docutils/nodes.py 2024-09-04 19:33:12 UTC (rev 9919) @@ -3074,6 +3074,22 @@ return '"%s"' % value +def parse_measure(measure: str) -> tuple[float, str]: + """Parse a measure__, return value + optional unit. + + __ https://docutils.sourceforge.io/docs/ref/doctree.html#measure + + Provisional. + """ + match = re.fullmatch('(-?[0-9.]+) *([a-zA-Zµ]*|%?)', measure) + try: + value = float(match.group(1)) + unit = match.group(2) + except (AttributeError, ValueError): + raise ValueError(f'"{measure}" is no valid measure.') + return value, unit + + # Methods to validate `Element attribute`__ values. # Ensure the expected Python `data type`__, normalize, and check for @@ -3139,24 +3155,25 @@ return value -def validate_measure(value: str) -> str: +def validate_measure(measure: str) -> str: """ - Validate a length measure__ (number + recognized unit). + Validate a measure__ (number + optional unit). Return normalized `str`. - __ https://docutils.sourceforge.io/docs/ref/doctree.html#measure + See `parse_measure()` for a function returning a "number + unit" tuple. + The unit may be any run of letters or a percent sign. + Provisional. + + __ https://docutils.sourceforge.io/docs/ref/doctree.html#measure """ - units = 'em|ex|px|in|cm|mm|pt|pc|%' - if not re.fullmatch(f'[-0-9.]+ *({units}?)', value): - raise ValueError(f'"{value}" is no valid measure. ' - f'Valid units: {units.replace("|", " ")}.') - return value.replace(' ', '').strip() + value, unit = parse_measure(measure) + return f'{value:g}{unit}' def validate_NMTOKEN(value: str) -> str: """ - Validate a "name token": a `str` of letters, digits, and [-._]. + Validate a "name token": a `str` of ASCII letters, digits, and [-._]. Provisional. """ Modified: trunk/docutils/docutils/parsers/rst/directives/__init__.py =================================================================== --- trunk/docutils/docutils/parsers/rst/directives/__init__.py 2024-09-04 06:16:29 UTC (rev 9918) +++ trunk/docutils/docutils/parsers/rst/directives/__init__.py 2024-09-04 19:33:12 UTC (rev 9919) @@ -261,8 +261,8 @@ float(match.group(1)) except (AttributeError, ValueError): raise ValueError( - 'not a positive measure of one of the following units:\n%s' - % ' '.join('"%s"' % i for i in units)) + 'not a positive measure of one of the following units:\n"%s"' + % '" "'.join(units)) return match.group(1) + match.group(2) Modified: trunk/docutils/test/test_nodes.py =================================================================== --- trunk/docutils/test/test_nodes.py 2024-09-04 06:16:29 UTC (rev 9918) +++ trunk/docutils/test/test_nodes.py 2024-09-04 19:33:12 UTC (rev 9919) @@ -502,11 +502,10 @@ node.validate() def test_validate_wrong_attribute_value(self): - node = nodes.image(uri='test.png', width='20 inch') # invalid unit + node = nodes.image(uri='test.png', width='1in 3pt') with self.assertRaisesRegex(nodes.ValidationError, 'Element <image.*> invalid:\n' - '.*"width" has invalid value "20 inch".\n' - '.*Valid units: em ex '): + '.*"width" has invalid value "1in 3pt".'): node.validate() def test_validate_spurious_element(self): @@ -1114,7 +1113,25 @@ self.assertEqual(nodes.split_name_list(r'a\ n\ame two\\ n\\ames'), ['a name', 'two\\', r'n\ames']) + def test_parse_measure(self): + # measure is number + optional unit (letter(s) or percentage) + self.assertEqual(nodes.parse_measure('8ex'), (8, 'ex')) + self.assertEqual(nodes.parse_measure('2.5'), (2.5, '')) + self.assertEqual(nodes.parse_measure('-2s'), (-2, 's')) + self.assertEqual(nodes.parse_measure('2 µF'), (2, 'µF')) + self.assertEqual(nodes.parse_measure('10 EUR'), (10, 'EUR')) + self.assertEqual(nodes.parse_measure('.5 %'), (.5, '%')) + # scientific notation not supported + with self.assertRaisesRegex(ValueError, '"3e-4 mm" is no valid '): + nodes.parse_measure('3e-4 mm') + # unit must follow the number + with self.assertRaisesRegex(ValueError, '"EUR 23" is no valid '): + nodes.parse_measure('EUR 23') + # only single percent sign allowed + with self.assertRaisesRegex(ValueError, '"2%%" is no valid measure'): + nodes.parse_measure('2%%') + class AttributeTypeTests(unittest.TestCase): """Test validator functions for the supported `attribute data types`__ @@ -1154,17 +1171,19 @@ nodes.validate_identifier_list(s2) def test_validate_measure(self): - # number (may be decimal fraction) + optional CSS2 length unit + # number (may be decimal fraction) + optional unit self.assertEqual(nodes.validate_measure('8ex'), '8ex') + self.assertEqual(nodes.validate_measure('2'), '2') + # internal whitespace is removed self.assertEqual(nodes.validate_measure('3.5 %'), '3.5%') - self.assertEqual(nodes.validate_measure('2'), '2') - with self.assertRaisesRegex(ValueError, '"2km" is no valid measure. ' - 'Valid units: em ex '): - nodes.validate_measure('2km') - # negative numbers are currently not supported - # TODO: allow? the spec doesnot mention negative numbers. - # but a negative width or height of an image is odd. - # nodes.validate_measure('-2') + # padding whitespace is not valid + with self.assertRaisesRegex(ValueError, '"8ex " is no valid measure'): + nodes.validate_measure('8ex ') + # Negative numbers: + # * ``doctree.txt`` does not mention negative numbers, + # * in rST, negative numbers are not valid. + # Provisional: currently valid but may become invalid! + # self.assertEqual(nodes.validate_measure('-2'), '-2') def test_validate_NMTOKEN(self): # str with ASCII-letters, digits, hyphen, underscore, and full-stop. Modified: trunk/docutils/test/test_parsers/test_docutils_xml/test_parse_element.py =================================================================== --- trunk/docutils/test/test_parsers/test_docutils_xml/test_parse_element.py 2024-09-04 06:16:29 UTC (rev 9918) +++ trunk/docutils/test/test_parsers/test_docutils_xml/test_parse_element.py 2024-09-04 19:33:12 UTC (rev 9919) @@ -93,12 +93,10 @@ """ xml = ('<image breadth="3 cm" height="3 inch"/>') node = docutils_xml.parse_element(xml) - self.assertEqual(xml, str(node)) + self.assertEqual(xml.replace('3 inch', '3inch'), str(node)) with self.assertRaisesRegex(ValueError, 'Element <image breadth="3 cm".*invalid:\n' - '.*"breadth" not one of "ids",.*\n' - '.*"height" has invalid value "3 inch".\n' - '.*Valid units: em ex px in cm mm pt ' + '.*"breadth" not one of "ids", ' ): node.validate() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-04 19:33:33
|
Revision: 9920 http://sourceforge.net/p/docutils/code/9920 Author: milde Date: 2024-09-04 19:33:30 +0000 (Wed, 04 Sep 2024) Log Message: ----------- Refactor `HTMLTranslator.image_size()`. Use `nodes.parse_measure()` instead of ad-hoc parsing when scaling size values. Split "spaghetti code" into auxiliary method `read_size_with_PIL()`. Modified Paths: -------------- trunk/docutils/docutils/writers/_html_base.py trunk/docutils/test/test_writers/test_html5_polyglot.py trunk/docutils/test/test_writers/test_html5_polyglot_misc.py Modified: trunk/docutils/docutils/writers/_html_base.py =================================================================== --- trunk/docutils/docutils/writers/_html_base.py 2024-09-04 19:33:12 UTC (rev 9919) +++ trunk/docutils/docutils/writers/_html_base.py 2024-09-04 19:33:30 UTC (rev 9920) @@ -14,18 +14,23 @@ # # .. _2-Clause BSD license: https://opensource.org/licenses/BSD-2-Clause -"""common definitions for Docutils HTML writers""" +"""Common definitions for Docutils HTML writers.""" +from __future__ import annotations + +__docformat__ = 'reStructuredText' + import base64 import mimetypes import os import os.path -from pathlib import Path import re import urllib.parse import urllib.request import warnings import xml.etree.ElementTree as ET # TODO: lazy import in prepare_svg()? +from pathlib import Path +from typing import TYPE_CHECKING import docutils from docutils import frontend, languages, nodes, utils, writers @@ -36,6 +41,10 @@ unichar2tex, wrap_math_code, MathError) +if TYPE_CHECKING: + from numbers import Real + + class Writer(writers.Writer): supported = ('html', 'xhtml') # update in subclass @@ -404,58 +413,67 @@ text = str(text) return text.translate(self.special_characters) - def image_size(self, node): - # Determine the image size from the node arguments or the image file. - # Return a size declaration suitable as "style" argument value, - # e.g., ``'width: 4px; height: 2em;'``. - # TODO: consider feature-request #102? - size = [node.get('width', None), node.get('height', None)] - if 'scale' in node: - if 'width' not in node or 'height' not in node: - # try reading size from image file - reading_problems = [] - uri = node['uri'] - if not PIL: - reading_problems.append('Requires Python Imaging Library.') - if mimetypes.guess_type(uri)[0] in self.videotypes: - reading_problems.append('PIL cannot read video images.') - if not self.settings.file_insertion_enabled: - reading_problems.append('Reading external files disabled.') - if not reading_problems: - try: - imagepath = self.uri2imagepath(uri) - with PIL.Image.open(imagepath) as img: - imgsize = img.size - except (ValueError, OSError, UnicodeEncodeError) as err: - reading_problems.append(str(err)) - else: - self.settings.record_dependencies.add( - imagepath.replace('\\', '/')) - if reading_problems: - msg = ['Cannot scale image!', - f'Could not get size from "{uri}":', - *reading_problems] - self.messages.append(self.document.reporter.warning( - '\n '.join(msg), base_node=node)) - else: - for i in range(2): - size[i] = size[i] or '%dpx' % imgsize[i] - # scale provided/determined size values: - factor = float(node['scale']) / 100 - for i in range(2): - if size[i]: - match = re.match(r'([0-9.]+)(\S*)$', size[i]) - size[i] = '%s%s' % (factor * float(match.group(1)), - match.group(2)) - size_declarations = [] - for i, dimension in enumerate(('width', 'height')): - if size[i]: - # Interpret unitless values as pixels: - if re.match(r'^[0-9.]+$', size[i]): - size[i] += 'px' - size_declarations.append(f'{dimension}: {size[i]};') - return ' '.join(size_declarations) + def image_size(self, node: nodes.image) -> str: + """Determine the image size from node arguments or the image file. + Auxiliary method called from `self.visit_image()`. + + Provisional. + """ + # TODO: Use "width" and "hight" for unitless integers? + # [feature-requests:#102] + + # List with optional width and height measures ((value, unit)-tuples) + measures: list[tuple[Real, str] | None] = [None, None] + dimensions = ('width', 'height') + for i, dimension in enumerate(dimensions): + if dimension in node: + measures[i] = nodes.parse_measure(node[dimension]) + if None in measures and 'scale' in node: + # supplement with (unitless) values read from image file + imgsize = self.read_size_with_PIL(node) + if imgsize: + measures = [measure or (imgvalue, '') + for measure, imgvalue in zip(measures, imgsize)] + # scale values + factor = node.get('scale', 100) / 100 # scaling factor + if factor != 1: + measures = [(measure[0] * factor, measure[1]) + for measure in measures if measure] + # format as CSS declarations and return + return ' '.join(f'{dimension}: {measure[0]:g}{measure[1] or "px"};' + for dimension, measure in zip(dimensions, measures) + if measure) + + def read_size_with_PIL(self, node) -> tuple[int, int] | None: + # Try reading size from image file. + # Internal auxiliary method called from `self.image_size()`. + reading_problems = [] + uri = node['uri'] + if not PIL: + reading_problems.append('Requires Python Imaging Library.') + if mimetypes.guess_type(uri)[0] in self.videotypes: + reading_problems.append('PIL cannot read video images.') + if not self.settings.file_insertion_enabled: + reading_problems.append('Reading external files disabled.') + if not reading_problems: + try: + imagepath = self.uri2imagepath(uri) + with PIL.Image.open(imagepath) as img: + imgsize = img.size + except (ValueError, OSError, UnicodeEncodeError) as err: + reading_problems.append(str(err)) + else: + self.settings.record_dependencies.add(imagepath) + if reading_problems: + msg = ['Cannot scale image!', + f'Could not get size from "{uri}":', + *reading_problems] + self.messages.append(self.document.reporter.warning( + '\n '.join(msg), base_node=node)) + return None + return imgsize + def prepare_svg(self, node, imagedata, size_declaration): # Edit `imagedata` for embedding as SVG image. # Use ElementTree to add node attributes. @@ -607,7 +625,7 @@ child['classes'].append(class_) def uri2imagepath(self, uri): - """Get filesystem path corresponding to an URI. + """Get POSIX filesystem path corresponding to an URI. The image directive expects an image URI__. Some writers require the corresponding image path to read the image size from the file or to Modified: trunk/docutils/test/test_writers/test_html5_polyglot.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-09-04 19:33:12 UTC (rev 9919) +++ trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-09-04 19:33:30 UTC (rev 9920) @@ -46,7 +46,7 @@ if (tuple(int(i) for i in PIL.__version__.split('.')) >= (10, 3)): DUMMY_PNG_NOT_FOUND = ("[Errno 2] No such file or directory: '%s'" % Path('dummy.png').resolve()) - SCALING_OUTPUT = 'style="width: 32.0px; height: 32.0px;" ' + SCALING_OUTPUT = 'style="width: 32px; height: 32px;" ' NO_PIL_SYSTEM_MESSAGE = '' else: REQUIRES_PIL = '\n Requires Python Imaging Library.' Modified: trunk/docutils/test/test_writers/test_html5_polyglot_misc.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot_misc.py 2024-09-04 19:33:12 UTC (rev 9919) +++ trunk/docutils/test/test_writers/test_html5_polyglot_misc.py 2024-09-04 19:33:30 UTC (rev 9920) @@ -18,8 +18,8 @@ # so we import the local `docutils` package. sys.path.insert(0, str(Path(__file__).resolve().parents[2])) -from docutils import core -from docutils.writers import html5_polyglot +from docutils import core, frontend, nodes, utils +from docutils.writers import html5_polyglot, _html_base # TEST_ROOT is ./test/ from the docutils root TEST_ROOT = Path(__file__).parents[1] @@ -241,5 +241,21 @@ self.assertNotIn('MathJax', head) +class ImagesTestCase(unittest.TestCase): + """Test image handling routines.""" + + settings = frontend.get_default_settings(_html_base.Writer) + document = utils.new_document('test data', settings) + translator = _html_base.HTMLTranslator(document) + + def test_image_size(self): + image = nodes.image(height='3', width='4em') + self.assertEqual(self.translator.image_size(image), + 'width: 4em; height: 3px;') + image = nodes.image(height='3', width='4em', scale=50) + self.assertEqual(self.translator.image_size(image), + 'width: 2em; height: 1.5px;') + + if __name__ == '__main__': unittest.main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-04 19:33:42
|
Revision: 9921 http://sourceforge.net/p/docutils/code/9921 Author: milde Date: 2024-09-04 19:33:39 +0000 (Wed, 04 Sep 2024) Log Message: ----------- Revise `HTMLTranslator.prepare_svg()`. Change oder of method arguments (sort by importance). Use a dictionary to update the `<svg style="..."> declarations keeping exisisting declarations intact. Simplify conversion of "align" attribute. Add test cases. Modified Paths: -------------- trunk/docutils/docutils/writers/_html_base.py trunk/docutils/test/test_writers/test_html5_polyglot.py trunk/docutils/test/test_writers/test_html5_polyglot_misc.py Modified: trunk/docutils/docutils/writers/_html_base.py =================================================================== --- trunk/docutils/docutils/writers/_html_base.py 2024-09-04 19:33:30 UTC (rev 9920) +++ trunk/docutils/docutils/writers/_html_base.py 2024-09-04 19:33:39 UTC (rev 9921) @@ -28,7 +28,7 @@ import urllib.parse import urllib.request import warnings -import xml.etree.ElementTree as ET # TODO: lazy import in prepare_svg()? +import xml.etree.ElementTree as ET from pathlib import Path from typing import TYPE_CHECKING @@ -474,39 +474,36 @@ return None return imgsize - def prepare_svg(self, node, imagedata, size_declaration): - # Edit `imagedata` for embedding as SVG image. - # Use ElementTree to add node attributes. - # ET also removes comments and preamble code. + def prepare_svg(self, code: str, node: nodes.Element, atts: dict) -> str: + # Parse SVG source `code` (ignoring comments and preamble code), + # add relevant attributes from `node` and `atts` to the root element. # - # Internal: interface and behaviour may change without notice. - - # SVG namespace + # Internal auxiliary method called from `self.visit_image()`. svg_ns = {'': 'http://www.w3.org/2000/svg', - 'xlink': 'http://www.w3.org/1999/xlink'} + 'xlink': 'http://www.w3.org/1999/xlink'} # SVG namespace # don't add SVG namespace to all elements - ET.register_namespace('', svg_ns['']) - ET.register_namespace('xlink', svg_ns['xlink']) + for key, value in svg_ns.items(): + ET.register_namespace(key, value) + # Parse: try: - svg = ET.fromstring(imagedata) + svg = ET.fromstring(code) except ET.ParseError as err: self.messages.append(self.document.reporter.error( f'Cannot parse SVG image "{node["uri"]}":\n {err}', base_node=node)) - return imagedata - # apply image node attributes: - if size_declaration: # append to style, replacing width & height - declarations = [d.strip() for d in svg.get('style', '').split(';')] - declarations = [d for d in declarations - if d - and not d.startswith('width') - and not d.startswith('height')] - svg.set('style', '; '.join(declarations+[size_declaration])) - if node['classes'] or 'align' in node: + return code + # Apply image node attributes: + if 'style' in atts: + # update style declarations + style_att = f"{svg.get('style', '')}; {atts['style']}" + style_att = [d.partition(':') for d in style_att.split(';') + if d.strip()] + style_att = dict((k.strip(), v.strip()) for k, p, v in style_att) + style_att = ' '.join(f'{k}: {v};' for k, v in style_att.items()) + svg.set('style', style_att) + if 'classes' in atts or node['classes']: classes = svg.get('class', '').split() - classes += node.get('classes', []) - if 'align' in node: - classes.append(f'align-{node["align"]}') + classes += node['classes'] + atts.get('classes', []) svg.set('class', ' '.join(classes)) if 'alt' in node and svg.find('title', svg_ns) is None: svg_title = ET.Element('title') @@ -598,7 +595,7 @@ infix = ' /' else: infix = '' - return ''.join(prefix) + '<%s%s>' % (' '.join(parts), infix) + suffix + return f"{''.join(prefix)}<{' '.join(parts)}{infix}>{suffix}" def emptytag(self, node, tagname, suffix='\n', **attributes): """Construct and return an XML-compatible empty tag.""" @@ -1173,14 +1170,11 @@ mimetype = mimetypes.guess_type(uri)[0] element = '' # the HTML element (including potential children) atts = {} # attributes for the HTML tag - # alignment is handled by CSS rules - if 'align' in node: - atts['class'] = 'align-%s' % node['align'] - # set size with "style" attribute (more universal, accepts dimensions) size_declaration = self.image_size(node) if size_declaration: atts['style'] = size_declaration - + if 'align' in node: + atts['classes'] = [f"align-{node['align']}"] # ``:loading:`` option (embed, link, lazy), default from setting, # exception: only embed videos if told via directive option loading = 'link' if mimetype in self.videotypes else self.image_loading @@ -1201,8 +1195,7 @@ else: self.settings.record_dependencies.add(imagepath) if mimetype == 'image/svg+xml': - element = self.prepare_svg(node, imagedata, - size_declaration) + element = self.prepare_svg(imagedata, node, atts) else: data64 = base64.b64encode(imagedata).decode() uri = f'data:{mimetype};base64,{data64}' Modified: trunk/docutils/test/test_writers/test_html5_polyglot.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-09-04 19:33:30 UTC (rev 9920) +++ trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-09-04 19:33:39 UTC (rev 9921) @@ -2,9 +2,10 @@ # $Id$ # Author: reggie dugard <re...@us...> +# Maintainer: doc...@li... # Copyright: This module has been placed in the public domain. -"""Test HTML5 writer output ("fragment" part). +"""Test HTML5 writer output ("fragment"/"body" part). This is the document body (not HTML <body>). """ @@ -89,7 +90,7 @@ self.assertEqual(case_expected, parts['body']) -totest = {} +totest = {} # expected samples contain only the "body" part of the HMTL output totest['standard'] = ({}, [ ["""\ @@ -147,6 +148,18 @@ </div> """, ], +[f"""\ +.. image:: {DATA_ROOT.as_uri()}/circle.svg + :loading: embed + :width: 50% + :height: 30 + :align: left +""", +"""\ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10" style="width: 50%; height: 30px;" class="align-left"> + <circle cx="5" cy="5" r="4" fill="lightblue" /> +</svg> +"""], ]) Modified: trunk/docutils/test/test_writers/test_html5_polyglot_misc.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot_misc.py 2024-09-04 19:33:30 UTC (rev 9920) +++ trunk/docutils/test/test_writers/test_html5_polyglot_misc.py 2024-09-04 19:33:39 UTC (rev 9921) @@ -247,6 +247,19 @@ settings = frontend.get_default_settings(_html_base.Writer) document = utils.new_document('test data', settings) translator = _html_base.HTMLTranslator(document) + svg_sample = """\ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + style="background: blue; width: 5ex" viewBox="0 0 10 10"> + <circle cx="5" cy="5" r="4" fill="lightblue" /> + <!-- comments are ignored --> +</svg> +""" + expected = """\ +<svg xmlns="http://www.w3.org/2000/svg" style="background: blue; width: 4em; height: 32px;" viewBox="0 0 10 10" class="test me"> + <title>blue circle</title><circle cx="5" cy="5" r="4" fill="lightblue" /> + \n\ +</svg>""" def test_image_size(self): image = nodes.image(height='3', width='4em') @@ -256,6 +269,27 @@ self.assertEqual(self.translator.image_size(image), 'width: 2em; height: 1.5px;') + def test_prepare_svg(self): + # Internal method: the test is no guaranty for stability, + # interface and behaviour may change without notice. + image = nodes.image(height='32', width='4em', alt='blue circle', + align='left', classes=['test', 'me']) + atts = {'style': self.translator.image_size(image)} + rv = self.translator.prepare_svg(self.svg_sample, image, atts) + self.assertEqual(rv, self.expected) + def test_prepare_svg_syntax_variants(self): + # parsing "style" declarations must be robust: + svg_sample = '<svg style="width:3em"></svg>' + + atts = {'style': 'colon:in:value'} + rv = self.translator.prepare_svg(svg_sample, nodes.image(), atts) + self.assertEqual(rv, '<svg style="width: 3em; colon: in:value;" />') + + atts = {'style': 'no-colon;'} + rv = self.translator.prepare_svg(svg_sample, nodes.image(), atts) + self.assertEqual(rv, '<svg style="width: 3em; no-colon: ;" />') + + if __name__ == '__main__': unittest.main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-11 07:20:10
|
Revision: 9928 http://sourceforge.net/p/docutils/code/9928 Author: milde Date: 2024-09-11 07:20:07 +0000 (Wed, 11 Sep 2024) Log Message: ----------- HTML5: use "width" and "height" for unitless image size values. Fixes [feature-requests:#102] The HTML `<img>` element supports "width" and "height" attributes to specify the size or ratio of an image. Values are restricted to integers (size in pixels). In Docutils, "width" and "hight" attributes also support a set of CSS compatible units. Therefore, all size values were passed to HTML via the common attribute "style". Using HTML "width" and "hight" attributes for values without unit provides a means to specify an image's *aspect ratio* without overriding a size declaration in a CSS style sheet. This change is not backported to the "html4css1" writer to keep the output backwards compatible. The provisional method `HTMLTranslator.image_size()` now returns a dictionary of attribute values. Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/RELEASE-NOTES.rst trunk/docutils/docs/user/html.rst trunk/docutils/docutils/writers/_html_base.py trunk/docutils/test/functional/expected/rst_html5_tuftig.html trunk/docutils/test/functional/expected/standalone_rst_html5.html trunk/docutils/test/test_writers/test_html5_polyglot.py trunk/docutils/test/test_writers/test_html5_polyglot_misc.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-11 07:19:52 UTC (rev 9927) +++ trunk/docutils/HISTORY.rst 2024-09-11 07:20:07 UTC (rev 9928) @@ -145,6 +145,8 @@ * docutils/writers/_html_base.py - Make MathML the default math_output_. + - Revise image size handling methods, + use "width" and "height" attributes for unitless values. * docutils/writers/html4css1/__init__.py Modified: trunk/docutils/RELEASE-NOTES.rst =================================================================== --- trunk/docutils/RELEASE-NOTES.rst 2024-09-11 07:19:52 UTC (rev 9927) +++ trunk/docutils/RELEASE-NOTES.rst 2024-09-11 07:20:07 UTC (rev 9928) @@ -85,20 +85,6 @@ __ https://www.w3.org/TR/2014/REC-html5-20141028/grouping-content.html #the-blockquote-element - - Unitless image_ :width: and :hight: values and dimensions - read from the image due to a :scale: option will be written as - "width" and "hight" attributes instead of "style" rules to allow - specification of the aspect ratio to `prevent jank when loading - images`__ without overwriting an image size set in a CSS stylesheet - in Docutils 0.22 (cf. `feature-requests:102`__). - The current behaviour is kept for dimensions with units, so - users may specify, e.g. ``:width: 50px`` instead of ``:width: 50`` - to override CSS stylesheet rules. - - __ https://developer.mozilla.org/en-US/docs/Learn/Performance/Multimedia - #rendering_strategy_preventing_jank_when_loading_images - __ https://sourceforge.net/p/docutils/feature-requests/102/ - - Change the default value of the initial_header_level_ setting to None (<h2> if there is a document title, else <h1>) in Docutils 1.0. @@ -202,22 +188,30 @@ (See `command line interface`_ for the rationale.) Output changes - "manpage" writer: + LaTeX: + Don't wrap references with custom reference-label_ in a ``\hyperref`` + command. The "hyperref" package generates hyperlinks for labels by + default, so there is no change in the PDF (except for "ref*"). + + .. _reference-label: docs/user/config.html#reference-label + + HTML5: + Unitless image_ size measures__ are written as <img> "width" and + "hight" values instead of "style" rules. The current behaviour + is kept for values with units, so users may specify, e.g. ``:width: + 50px`` instead of ``:width: 50`` to override CSS stylesheet rules. + + __ docs/ref/doctree.html#measure + + manpage: Don't UPPERCASE section headings. - "null" writer: - output changed from None to the empty string. + null: + The "null" writer output changed from None to the empty string. `publish_string()` now returns a `bytes` or `str` instance for all writers (as documented). - "latex" writer: - Don't wrap references with custom reference-label_ in a ``\hyperref`` - command. The "hyperref" package generates hyperlinks for labels by - default, so there is no change in the PDF (except for "ref*"). - - .. _reference-label: docs/user/config.html#reference-label - New objects `parsers.docutils_xml` parser for `Docutils XML`_ (e.g., the output of the "xml" writer). Modified: trunk/docutils/docs/user/html.rst =================================================================== --- trunk/docutils/docs/user/html.rst 2024-09-11 07:19:52 UTC (rev 9927) +++ trunk/docutils/docs/user/html.rst 2024-09-11 07:20:07 UTC (rev 9928) @@ -52,6 +52,13 @@ better legibility. Adaption of the layout is possible with `custom style sheets`_. [#safetext]_ +Image_ size values with unit are converted to "style" rules, +values without unit are rounded to the nearest integer and +written as "width" and "height" attributes instead. +This allows the specification of the image's aspect ratio +(to `prevent jank when loading images`__) without overwriting +size declarations in a CSS stylesheet. + .. [#safetext] The validity of raw HTML and custom stylesheets must be ensured by the author. @@ -69,6 +76,9 @@ .. _custom style sheets: ../howto/html-stylesheets.html .. _viewable with any browser: http://www.anybrowser.org/campaign .. _Benefits of polyglot XHTML5: http://xmlplease.com/xhtml/xhtml5polyglot/ +.. _image: ../ref/rst/directives.html#image +__ https://developer.mozilla.org/en-US/docs/Learn/Performance/Multimedia + #rendering_strategy_preventing_jank_when_loading_images html4css1 Modified: trunk/docutils/docutils/writers/_html_base.py =================================================================== --- trunk/docutils/docutils/writers/_html_base.py 2024-09-11 07:19:52 UTC (rev 9927) +++ trunk/docutils/docutils/writers/_html_base.py 2024-09-11 07:20:07 UTC (rev 9928) @@ -413,7 +413,7 @@ text = str(text) return text.translate(self.special_characters) - def image_size(self, node: nodes.image) -> str: + def image_size(self, node: nodes.image) -> dict[str, str]: """Determine the image size from node arguments or the image file. Auxiliary method called from `self.visit_image()`. @@ -420,9 +420,6 @@ Provisional. """ - # TODO: Use "width" and "hight" for unitless integers? - # [feature-requests:#102] - # List with optional width and height measures ((value, unit)-tuples) measures: list[tuple[Real, str] | None] = [None, None] dimensions = ('width', 'height') @@ -440,10 +437,22 @@ if factor != 1: measures = [(measure[0] * factor, measure[1]) for measure in measures if measure] - # format as CSS declarations and return - return ' '.join(f'{dimension}: {measure[0]:g}{measure[1] or "px"};' - for dimension, measure in zip(dimensions, measures) - if measure) + # format as <img> attributes, + # use "width" and "hight" for unitless values and "style" else, + # e.g., height': '32' 'style': 'width: 4 em;'}``: + size_atts = {} # attributes "width", "height", or "style" + declarations = [] # declarations for the "style" attribute + for dimension, measure in zip(dimensions, measures): + if measure is None: + continue + value, unit = measure + if unit: + declarations.append(f'{dimension}: {value:g}{unit};') + else: + size_atts[dimension] = f'{round(value)}' + if declarations: + size_atts['style'] = ' '.join(declarations) + return size_atts def read_size_with_PIL(self, node) -> tuple[int, int] | None: # Try reading size from image file. @@ -501,6 +510,9 @@ style_att = dict((k.strip(), v.strip()) for k, p, v in style_att) style_att = ' '.join(f'{k}: {v};' for k, v in style_att.items()) svg.set('style', style_att) + for dimension in ('width', 'height'): + if dimension in atts: + svg.set(dimension, atts[dimension]) if 'classes' in atts or node['classes']: classes = svg.get('class', '').split() classes += node['classes'] + atts.get('classes', []) @@ -1169,10 +1181,9 @@ alt = node.get('alt', uri) mimetype = mimetypes.guess_type(uri)[0] element = '' # the HTML element (including potential children) - atts = {} # attributes for the HTML tag - size_declaration = self.image_size(node) - if size_declaration: - atts['style'] = size_declaration + # attributes for the HTML tag: + atts = self.image_size(node) + # alignment is handled by CSS rules if 'align' in node: atts['classes'] = [f"align-{node['align']}"] # ``:loading:`` option (embed, link, lazy), default from setting, Modified: trunk/docutils/test/functional/expected/rst_html5_tuftig.html =================================================================== --- trunk/docutils/test/functional/expected/rst_html5_tuftig.html 2024-09-11 07:19:52 UTC (rev 9927) +++ trunk/docutils/test/functional/expected/rst_html5_tuftig.html 2024-09-11 07:20:07 UTC (rev 9928) @@ -137,7 +137,7 @@ </section> </main> <footer> -<p><a class="reference external image-reference" href="http://www.w3.org/TR/html5/"><img alt="Conforms to HTML 5" src="http://www.w3.org/html/logo/badge/html5-badge-h-css3-semantics.png" style="width: 88px; height: 31px;" /></a> <a class="reference external image-reference" href="http://validator.w3.org/check?uri=referer"><img alt="Check validity!" src="https://www.w3.org/Icons/ValidatorSuite/vs-blue-190.png" style="width: 88px; height: 31px;" /></a> <a class="reference external image-reference" href="http://jigsaw.w3.org/css-validator/check/referer"><img alt="Valid CSS 2.1!" src="http://jigsaw.w3.org/css-validator/images/vcss" style="width: 88px; height: 31px;" /></a></p> +<p><a class="reference external image-reference" href="http://www.w3.org/TR/html5/"><img alt="Conforms to HTML 5" height="31" src="http://www.w3.org/html/logo/badge/html5-badge-h-css3-semantics.png" width="88" /></a> <a class="reference external image-reference" href="http://validator.w3.org/check?uri=referer"><img alt="Check validity!" height="31" src="https://www.w3.org/Icons/ValidatorSuite/vs-blue-190.png" width="88" /></a> <a class="reference external image-reference" href="http://jigsaw.w3.org/css-validator/check/referer"><img alt="Valid CSS 2.1!" height="31" src="http://jigsaw.w3.org/css-validator/images/vcss" width="88" /></a></p> </footer> </body> </html> Modified: trunk/docutils/test/functional/expected/standalone_rst_html5.html =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_html5.html 2024-09-11 07:19:52 UTC (rev 9927) +++ trunk/docutils/test/functional/expected/standalone_rst_html5.html 2024-09-11 07:20:07 UTC (rev 9928) @@ -614,7 +614,7 @@ media, figures might float to a different position if this helps the page layout.</p> <figure class="figclass1 figclass2"> -<img alt="reStructuredText, the markup syntax" class="class1 class2" src="../../../docs/user/rst/images/title.png" style="width: 258px;" /> +<img alt="reStructuredText, the markup syntax" class="class1 class2" src="../../../docs/user/rst/images/title.png" width="258" /> <figcaption> <p>Plaintext markup syntax and parser system.</p> <div class="legend"> @@ -1302,7 +1302,7 @@ <li><img alt="blue square" class="align-right" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALElEQVR4nO3NMQEAMAjAsDFjvIhHFCbgSwU0kdXvsn96BwAAAAAAAAAAAIsNnEwBk52VRuMAAAAASUVORK5CYII=" /> <p>Embed images or defer fetching images with the <a class="reference external" href="https://docutils.sourceforge.io/docs/user/config.html#image-loading">image-loading</a> <a class="brackets" href="#footnote-9" id="footnote-reference-22" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> configuration setting or the "loading" option of the "image" directive.</p> -<img alt="../../../docs/user/rst/images/biohazard.png" class="align-right" loading="lazy" src="../../../docs/user/rst/images/biohazard.png" style="width: 16px; height: 16px;" /> +<img alt="../../../docs/user/rst/images/biohazard.png" class="align-right" height="16" loading="lazy" src="../../../docs/user/rst/images/biohazard.png" width="16" /> <p>Especially with "lazy" loading, it is strongly recommended to specify both width and height of the image to prevent content layout shifts or use the "scale" option to let the writer insert the size @@ -1930,7 +1930,7 @@ </main> <footer> <p>Document footer</p> -<p><a class="reference external image-reference" href="http://www.w3.org/TR/html5/"><img alt="Conforms to HTML 5" src="http://www.w3.org/html/logo/badge/html5-badge-h-css3-semantics.png" style="width: 88px; height: 31px;" /></a> <a class="reference external image-reference" href="http://validator.w3.org/check?uri=referer"><img alt="Check validity!" src="https://www.w3.org/Icons/ValidatorSuite/vs-blue-190.png" style="width: 88px; height: 31px;" /></a> <a class="reference external image-reference" href="http://jigsaw.w3.org/css-validator/check/referer"><img alt="Valid CSS 2.1!" src="http://jigsaw.w3.org/css-validator/images/vcss" style="width: 88px; height: 31px;" /></a></p> +<p><a class="reference external image-reference" href="http://www.w3.org/TR/html5/"><img alt="Conforms to HTML 5" height="31" src="http://www.w3.org/html/logo/badge/html5-badge-h-css3-semantics.png" width="88" /></a> <a class="reference external image-reference" href="http://validator.w3.org/check?uri=referer"><img alt="Check validity!" height="31" src="https://www.w3.org/Icons/ValidatorSuite/vs-blue-190.png" width="88" /></a> <a class="reference external image-reference" href="http://jigsaw.w3.org/css-validator/check/referer"><img alt="Valid CSS 2.1!" height="31" src="http://jigsaw.w3.org/css-validator/images/vcss" width="88" /></a></p> </footer> </body> </html> Modified: trunk/docutils/test/test_writers/test_html5_polyglot.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-09-11 07:19:52 UTC (rev 9927) +++ trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-09-11 07:20:07 UTC (rev 9928) @@ -47,13 +47,15 @@ if (tuple(int(i) for i in PIL.__version__.split('.')) >= (10, 3)): DUMMY_PNG_NOT_FOUND = ("[Errno 2] No such file or directory: '%s'" % Path('dummy.png').resolve()) - SCALING_OUTPUT = 'style="width: 32px; height: 32px;" ' + HEIGHT_ATTR = 'height="32" ' + WIDTH_ATTR = 'width="32" ' NO_PIL_SYSTEM_MESSAGE = '' else: REQUIRES_PIL = '\n Requires Python Imaging Library.' ONLY_LOCAL = 'Requires Python Imaging Library.' DUMMY_PNG_NOT_FOUND = 'Requires Python Imaging Library.' - SCALING_OUTPUT = '' + HEIGHT_ATTR = '' + WIDTH_ATTR = '' NO_PIL_SYSTEM_MESSAGE = ( '<aside class="system-message">\n' '<p class="system-message-title">System Message:' @@ -156,7 +158,7 @@ :align: left """, """\ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10" style="width: 50%; height: 30px;" class="align-left"> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10" style="width: 50%;" height="30" class="align-left"> <circle cx="5" cy="5" r="4" fill="lightblue" /> </svg> """], @@ -451,11 +453,11 @@ :scale: 100% .. figure:: /data/blue%20square.png """, -'<img alt="/data/blue%20square.png" src="data:image/png;base64,' +f'<img alt="/data/blue%20square.png" {HEIGHT_ATTR}src="data:image/png;base64,' 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALElEQVR4nO3NMQ' 'EAMAjAsDFjvIhHFCbgSwU0kdXvsn96BwAAAAAAAAAAAIsNnEwBk52VRuMAAAAA' 'SUVORK5CYII="' -f' {SCALING_OUTPUT}/>\n{NO_PIL_SYSTEM_MESSAGE}' +f' {WIDTH_ATTR}/>\n{NO_PIL_SYSTEM_MESSAGE}' '<figure>\n' '<img alt="/data/blue%20square.png" src="data:image/png;base64,' 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALElEQVR4nO3NMQ' Modified: trunk/docutils/test/test_writers/test_html5_polyglot_misc.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot_misc.py 2024-09-11 07:19:52 UTC (rev 9927) +++ trunk/docutils/test/test_writers/test_html5_polyglot_misc.py 2024-09-11 07:20:07 UTC (rev 9928) @@ -243,7 +243,7 @@ class ImagesTestCase(unittest.TestCase): """Test image handling routines.""" - + maxDiff = None settings = frontend.get_default_settings(_html_base.Writer) document = utils.new_document('test data', settings) translator = _html_base.HTMLTranslator(document) @@ -250,24 +250,28 @@ svg_sample = """\ <?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" - style="background: blue; width: 5ex" viewBox="0 0 10 10"> + style="background: blue; width: 5ex; height: 3ex" viewBox="0 0 10 10"> <circle cx="5" cy="5" r="4" fill="lightblue" /> <!-- comments are ignored --> </svg> """ expected = """\ -<svg xmlns="http://www.w3.org/2000/svg" style="background: blue; width: 4em; height: 32px;" viewBox="0 0 10 10" class="test me"> +<svg xmlns="http://www.w3.org/2000/svg" style="background: blue; width: 4em; height: 3ex;" viewBox="0 0 10 10" height="32" class="test me"> <title>blue circle</title><circle cx="5" cy="5" r="4" fill="lightblue" /> \n\ </svg>""" def test_image_size(self): - image = nodes.image(height='3', width='4em') + # HTML attributes "width" and "height" take only integer values: + # -> height value is passed as "height" attribute, + # value with unit is passed via "style". + image = nodes.image(width='4em', height='3', scale=200) self.assertEqual(self.translator.image_size(image), - 'width: 4em; height: 3px;') - image = nodes.image(height='3', width='4em', scale=50) + {'height': '6', 'style': 'width: 8em;'}) + # "style" declaration also used for unitless non-interger value + image = nodes.image(width='4em', height='3', scale=50) self.assertEqual(self.translator.image_size(image), - 'width: 2em; height: 1.5px;') + {'style': 'width: 2em;', 'height': '2'}) def test_prepare_svg(self): # Internal method: the test is no guaranty for stability, @@ -274,7 +278,7 @@ # interface and behaviour may change without notice. image = nodes.image(height='32', width='4em', alt='blue circle', align='left', classes=['test', 'me']) - atts = {'style': self.translator.image_size(image)} + atts = self.translator.image_size(image) rv = self.translator.prepare_svg(self.svg_sample, image, atts) self.assertEqual(rv, self.expected) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-13 08:13:06
|
Revision: 9930 http://sourceforge.net/p/docutils/code/9930 Author: milde Date: 2024-09-13 08:13:03 +0000 (Fri, 13 Sep 2024) Log Message: ----------- Use "unknown_reference_resolver" for LaTeX writer option "use-bibtex". The "latex" writer provides the (provisional) setting "use_bibtex" to defer the resolution of citation references to the backend (LaTeX/BibTeX/LaTeX). Use the `unknown_reference_resolvers` hook of the `TransformSpec` to mark citation references as resolved if BibTeX is used. Advantages: * replaces hard-coded special-case in `transforms.references.DanglingReferencesVisitor` introduced in [r9312], * provides a usage example, * tests the hook with the Docutils test suite without additional overhead. Update docstrings and comments. Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/docutils/__init__.py trunk/docutils/docutils/transforms/__init__.py trunk/docutils/docutils/transforms/references.py trunk/docutils/docutils/writers/latex2e/__init__.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-12 12:57:48 UTC (rev 9929) +++ trunk/docutils/HISTORY.rst 2024-09-13 08:13:03 UTC (rev 9930) @@ -158,6 +158,8 @@ (ignored since at least 2012). - Don't wrap references with custom reference-label_ in a ``\hyperref`` command. + - Provide an "unknown_references_resolver" (cf. `docutils/TransformSpec`) + for citation references resolved with BibTeX (cf. `use_bibtex`_ setting). .. _reference-label: docs/user/config.html#reference-label @@ -3856,9 +3858,9 @@ * docutils/transforms/__init__.py: - Added ``Transformer`` class and completed transform reform. - - Added unknown_reference_resolvers list for each transformer. This list holds - the list of functions provided by each component of the transformer that - help resolve references. + - Added unknown_reference_resolvers list for each transformer. + This list holds the list of functions provided by each component + of the transformer that help resolve references. * docutils/transforms/frontmatter.py: Modified: trunk/docutils/docutils/__init__.py =================================================================== --- trunk/docutils/docutils/__init__.py 2024-09-12 12:57:48 UTC (rev 9929) +++ trunk/docutils/docutils/__init__.py 2024-09-13 08:13:03 UTC (rev 9930) @@ -282,8 +282,11 @@ default_transforms: ClassVar[tuple[()]] = () unknown_reference_resolvers: Sequence[_UnknownReferenceResolver] = () - """List of functions to try to resolve unknown references. + """List of hook functions which assist in resolving references. + Override in subclasses to implement component-specific resolving of + unknown references. + Unknown references have a 'refname' attribute which doesn't correspond to any target in the document. Called when the transforms in `docutils.transforms.references` are unable to find a correct target. @@ -291,7 +294,7 @@ The list should contain functions which will try to resolve unknown references, with the following signature:: - def reference_resolver(node): + def reference_resolver(node: nodes.Element) -> bool: '''Returns boolean: true if resolved, false if not.''' If the function is able to resolve the reference, it should also remove @@ -301,13 +304,20 @@ node.resolved = True Each function must have a "priority" attribute which will affect the order - the unknown_reference_resolvers are run:: + the unknown_reference_resolvers are run + cf. ../docs/api/transforms.html#transform-priority-range-categories :: - reference_resolver.priority = 100 + reference_resolver.priority = 500 - This hook is provided for 3rd party extensions. - Example use case: the `MoinMoin - ReStructured Text Parser` - https://github.com/moinwiki/moin + Examples: + `writers.latex2e.Writer` defines a resolver to mark citation references + as resolved by BibTeX if the "use_bibtex" configuration setting is set. + + The `MoinMoin ReStructured Text Parser`__ provides a resolver for + "WikiWiki links" (currently only in the outdated 1.9 version). + + __ https://github.com/moinwiki/moin-1.9/blob/1.9.11/MoinMoin/parser/ + text_rst.py """ Modified: trunk/docutils/docutils/transforms/__init__.py =================================================================== --- trunk/docutils/docutils/transforms/__init__.py 2024-09-12 12:57:48 UTC (rev 9929) +++ trunk/docutils/docutils/transforms/__init__.py 2024-09-13 08:13:03 UTC (rev 9930) @@ -144,7 +144,7 @@ def populate_from_components(self, components) -> None: """ - Store each component's default transforms and reference resolvers + Store each component's default transforms and reference resolvers. Transforms are stored with default priorities for later sorting. "Unknown reference resolvers" are sorted and stored. @@ -161,7 +161,7 @@ resolvers.extend(component.unknown_reference_resolvers) self.sorted = False # sort transform list in self.apply_transforms() - # Sort and add helper functions to help resolve unknown references. + # Sort and add hook functions helping to resolve unknown references. def keyfun(f): return f.priority resolvers.sort(key=keyfun) Modified: trunk/docutils/docutils/transforms/references.py =================================================================== --- trunk/docutils/docutils/transforms/references.py 2024-09-12 12:57:48 UTC (rev 9929) +++ trunk/docutils/docutils/transforms/references.py 2024-09-13 08:13:03 UTC (rev 9930) @@ -888,37 +888,33 @@ return refname = node['refname'] id = self.document.nameids.get(refname) - if id is None: - for resolver_function in self.unknown_reference_resolvers: - if resolver_function(node): - break - else: - if (getattr(self.document.settings, 'use_bibtex', False) - and isinstance(node, nodes.citation_reference)): - # targets added from BibTeX database by LaTeX - node.resolved = True - return - if refname in self.document.nameids: - msg = self.document.reporter.error( - 'Duplicate target name, cannot be used as a unique ' - 'reference: "%s".' % (node['refname']), base_node=node) - else: - msg = self.document.reporter.error( - f'Unknown target name: "{node["refname"]}".', - base_node=node) - msgid = self.document.set_id(msg) - prb = nodes.problematic( - node.rawsource, node.rawsource, refid=msgid) - try: - prbid = node['ids'][0] - except IndexError: - prbid = self.document.set_id(prb) - msg.add_backref(prbid) - node.replace_self(prb) - else: + if id is not None: + # target found, set refid del node['refname'] node['refid'] = id self.document.ids[id].note_referenced_by(id=id) node.resolved = True + return + # Apply component-specific resolving functions (cf. TransformSpec): + for resolver_function in self.unknown_reference_resolvers: + if resolver_function(node): + return + # Report unresolved references: + if refname in self.document.nameids: + msg = self.document.reporter.error( + 'Duplicate target name, cannot be used as a unique ' + 'reference: "%s".' % (node['refname']), base_node=node) + else: + msg = self.document.reporter.error( + f'Unknown target name: "{node["refname"]}".', + base_node=node) + msgid = self.document.set_id(msg) + prb = nodes.problematic(node.rawsource, node.rawsource, refid=msgid) + try: + prbid = node['ids'][0] + except IndexError: + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + node.replace_self(prb) visit_footnote_reference = visit_citation_reference = visit_reference Modified: trunk/docutils/docutils/writers/latex2e/__init__.py =================================================================== --- trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-12 12:57:48 UTC (rev 9929) +++ trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-13 08:13:03 UTC (rev 9930) @@ -253,7 +253,23 @@ def __init__(self) -> None: writers.Writer.__init__(self) self.translator_class = LaTeXTranslator + self.unknown_reference_resolvers = [self.bibtex_reference_resolver] + self.bibtex_reference_resolver.priority = 400 + @staticmethod + def bibtex_reference_resolver(node: nodes.Element) -> bool: + """Mark citation references as resolved if BibTeX is used. + + Cf. `TransformSpec.unknown_reference_resolvers`. + """ + if (isinstance(node, nodes.citation_reference) + and node.document.settings.use_bibtex): + del node['refname'] + node.resolved = True + return True + else: + return False + def get_transforms(self): # Override parent method to add latex-specific transforms return super().get_transforms() + [ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-15 11:13:45
|
Revision: 9931 http://sourceforge.net/p/docutils/code/9931 Author: milde Date: 2024-09-15 11:13:43 +0000 (Sun, 15 Sep 2024) Log Message: ----------- HTML writers: Add "px" to unitless table "width" values. The table "width" attribute is of type "length", with optional unit. The writers must ensure there is a unit when converting a length to a HTML "style" attribute rule. For HTML writers, the default length unit is "px". Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/docutils/writers/_html_base.py trunk/docutils/docutils/writers/html4css1/__init__.py trunk/docutils/docutils/writers/html5_polyglot/__init__.py trunk/docutils/test/test_writers/test_html4css1.py trunk/docutils/test/test_writers/test_html5_polyglot.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-13 08:13:03 UTC (rev 9930) +++ trunk/docutils/HISTORY.rst 2024-09-15 11:13:43 UTC (rev 9931) @@ -147,10 +147,12 @@ - Make MathML the default math_output_. - Revise image size handling methods, use "width" and "height" attributes for unitless values. + - Add "px" to unitless table "width" values. * docutils/writers/html4css1/__init__.py - Keep default math_output_ value "HTML math.css". + - Add "px" to unitless table "width" values. * docutils/writers/latex2e/__init__.py Modified: trunk/docutils/docutils/writers/_html_base.py =================================================================== --- trunk/docutils/docutils/writers/_html_base.py 2024-09-13 08:13:03 UTC (rev 9930) +++ trunk/docutils/docutils/writers/_html_base.py 2024-09-15 11:13:43 UTC (rev 9931) @@ -1693,7 +1693,10 @@ if 'align' in node: atts['classes'].append('align-%s' % node['align']) if 'width' in node: - atts['style'] = 'width: %s;' % node['width'] + width = node['width'] + if width[-1:] in '0123456789.': # unitless value + width += 'px' # add default length unit + atts['style'] = f'width: {width};' tag = self.starttag(node, 'table', **atts) self.body.append(tag) Modified: trunk/docutils/docutils/writers/html4css1/__init__.py =================================================================== --- trunk/docutils/docutils/writers/html4css1/__init__.py 2024-09-13 08:13:03 UTC (rev 9930) +++ trunk/docutils/docutils/writers/html4css1/__init__.py 2024-09-15 11:13:43 UTC (rev 9931) @@ -866,7 +866,10 @@ if 'align' in node: classes.append('align-%s' % node['align']) if 'width' in node: - atts['style'] = 'width: %s' % node['width'] + width = node['width'] + if width[-1:] in '0123456789.': # unitless value + width += 'px' # add default length unit + atts['style'] = f'width: {width}' self.body.append( self.starttag(node, 'table', CLASS=' '.join(classes), **atts)) Modified: trunk/docutils/docutils/writers/html5_polyglot/__init__.py =================================================================== --- trunk/docutils/docutils/writers/html5_polyglot/__init__.py 2024-09-13 08:13:03 UTC (rev 9930) +++ trunk/docutils/docutils/writers/html5_polyglot/__init__.py 2024-09-15 11:13:43 UTC (rev 9931) @@ -200,7 +200,7 @@ # use new HTML5 <figure> and <figcaption> elements def visit_figure(self, node) -> None: atts = {} - if node.get('width'): + if 'width' in node: atts['style'] = f"width: {node['width']}" if node.get('align'): atts['class'] = f"align-{node['align']}" Modified: trunk/docutils/test/test_writers/test_html4css1.py =================================================================== --- trunk/docutils/test/test_writers/test_html4css1.py 2024-09-13 08:13:03 UTC (rev 9930) +++ trunk/docutils/test/test_writers/test_html4css1.py 2024-09-15 11:13:43 UTC (rev 9931) @@ -183,6 +183,7 @@ ["""\ .. table:: :align: right + :width: 320 +-----+-----+ | 1 | 2 | @@ -191,7 +192,7 @@ +-----+-----+ """, """\ -<table border="1" class="docutils align-right"> +<table border="1" class="docutils align-right" style="width: 320px"> <colgroup> <col width="50%" /> <col width="50%" /> Modified: trunk/docutils/test/test_writers/test_html5_polyglot.py =================================================================== --- trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-09-13 08:13:03 UTC (rev 9930) +++ trunk/docutils/test/test_writers/test_html5_polyglot.py 2024-09-15 11:13:43 UTC (rev 9931) @@ -218,6 +218,7 @@ ["""\ .. table:: :align: right + :width: 320 +-----+-----+ | 1 | 2 | @@ -226,7 +227,7 @@ +-----+-----+ """, """\ -<table class="align-right"> +<table class="align-right" style="width: 320px;"> <tbody> <tr><td><p>1</p></td> <td><p>2</p></td> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-19 10:20:46
|
Revision: 9932 http://sourceforge.net/p/docutils/code/9932 Author: milde Date: 2024-09-19 10:20:44 +0000 (Thu, 19 Sep 2024) Log Message: ----------- Revise/fix handling of length specifications. Don't use the generic number-formatter "g" to drop trailing zeroes in `nodes.validate_measure()` to avoid writing large values in scientific format (which is not supported in reStructuredText). Instead, `nodes.parse_measure()` returns an `int` if possible so that converting to `str` does not add a trailing zero in the first place. Refactor `writers._html_base.HTMLTranslator.image_size()`. (Using the "g"-formatter in the HTML writer is no problem, as the scientific format is valid in CSS and "style" attribute values.) Simplify `writers.latex2e.LaTeXTranslator.to_latex_length()`: Use `nodes.parse_measure()`. Move XeTeX-specific code to the "XeTeX" writer. Drop trailing zeroes. (Using "g" with percentage values is considered safe, as a "width" value larger than 10 000 000 % leads to output problems anyway.) Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/RELEASE-NOTES.rst trunk/docutils/docutils/nodes.py trunk/docutils/docutils/writers/_html_base.py trunk/docutils/docutils/writers/latex2e/__init__.py trunk/docutils/docutils/writers/xetex/__init__.py trunk/docutils/test/functional/expected/latex_cornercases.tex trunk/docutils/test/functional/expected/latex_memoir.tex trunk/docutils/test/functional/expected/standalone_rst_latex.tex trunk/docutils/test/functional/expected/standalone_rst_xetex.tex Added Paths: ----------- trunk/docutils/test/test_writers/test_xetex_misc.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/HISTORY.rst 2024-09-19 10:20:44 UTC (rev 9932) @@ -156,8 +156,10 @@ * docutils/writers/latex2e/__init__.py - - Remove optional argument `pxunit` of `LaTeXTranslator.to_latex_length()` - (ignored since at least 2012). + - `LaTeXTranslator.to_latex_length()`: + remove optional argument `pxunit` (ignored since at least 2012), + drop trailing zeroes from length values, + move XeTeX-specific code to the "xetex" writer. - Don't wrap references with custom reference-label_ in a ``\hyperref`` command. - Provide an "unknown_references_resolver" (cf. `docutils/TransformSpec`) @@ -179,7 +181,7 @@ - `null.Writer.translate()` sets `self.output` to the empty string. -* tools/rst2odt_prepstyles.py +* tools/rst2odt.py - Use `core.publish_file()` instead of `core.publish_file_to_binary()`. Modified: trunk/docutils/RELEASE-NOTES.rst =================================================================== --- trunk/docutils/RELEASE-NOTES.rst 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/RELEASE-NOTES.rst 2024-09-19 10:20:44 UTC (rev 9932) @@ -102,6 +102,11 @@ - Remove ``use_verbatim_when_possible`` setting (use literal_block_env_: verbatim) in Docutils 2.0. + - The `default length unit`__ will change from "bp" (DTP point) + to "px" (pixel unit) in Docutils 1.0. + + __ docs/user/latex.html#length-units + Misc ---- Modified: trunk/docutils/docutils/nodes.py =================================================================== --- trunk/docutils/docutils/nodes.py 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/docutils/nodes.py 2024-09-19 10:20:44 UTC (rev 9932) @@ -37,6 +37,7 @@ # import docutils.transforms # -> conditional import in document.__init__() if TYPE_CHECKING: + import numbers from collections.abc import (Callable, Iterable, Iterator, Mapping, Sequence) from types import ModuleType @@ -3074,7 +3075,7 @@ return '"%s"' % value -def parse_measure(measure: str) -> tuple[float, str]: +def parse_measure(measure: str) -> tuple[numbers.Rational, str]: """Parse a measure__, return value + optional unit. __ https://docutils.sourceforge.io/docs/ref/doctree.html#measure @@ -3083,7 +3084,10 @@ """ match = re.fullmatch('(-?[0-9.]+) *([a-zA-Zµ]*|%?)', measure) try: - value = float(match.group(1)) + try: + value = int(match.group(1)) + except ValueError: + value = float(match.group(1)) unit = match.group(2) except (AttributeError, ValueError): raise ValueError(f'"{measure}" is no valid measure.') @@ -3168,7 +3172,7 @@ __ https://docutils.sourceforge.io/docs/ref/doctree.html#measure """ value, unit = parse_measure(measure) - return f'{value:g}{unit}' + return f'{value}{unit}' def validate_NMTOKEN(value: str) -> str: Modified: trunk/docutils/docutils/writers/_html_base.py =================================================================== --- trunk/docutils/docutils/writers/_html_base.py 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/docutils/writers/_html_base.py 2024-09-19 10:20:44 UTC (rev 9932) @@ -40,9 +40,8 @@ from docutils.utils.math import (latex2mathml, math2html, tex2mathml_extern, unichar2tex, wrap_math_code, MathError) - if TYPE_CHECKING: - from numbers import Real + from docutils.transforms import Transform class Writer(writers.Writer): @@ -157,7 +156,7 @@ 'html_prolog', 'html_head', 'html_title', 'html_subtitle', 'html_body') - def get_transforms(self): + def get_transforms(self) -> list[type[Transform]]: return super().get_transforms() + [writer_aux.Admonitions] def translate(self) -> None: @@ -167,11 +166,10 @@ setattr(self, attr, getattr(visitor, attr)) self.output = self.apply_template() - def apply_template(self): + def apply_template(self) -> str: template_path = Path(self.document.settings.template) template = template_path.read_text(encoding='utf-8') - subs = self.interpolation_dict() - return template % subs + return template % self.interpolation_dict() def interpolation_dict(self): subs = {} @@ -416,36 +414,31 @@ def image_size(self, node: nodes.image) -> dict[str, str]: """Determine the image size from node arguments or the image file. + Return as dictionary of <img> attributes, + e.g., ``{height': '32', 'style': 'width: 4 em;'}``. + Auxiliary method called from `self.visit_image()`. - Provisional. """ - # List with optional width and height measures ((value, unit)-tuples) - measures: list[tuple[Real, str] | None] = [None, None] dimensions = ('width', 'height') - for i, dimension in enumerate(dimensions): + measures = {} # (value, unit)-tuples) for width and height + for dimension in dimensions: if dimension in node: - measures[i] = nodes.parse_measure(node[dimension]) - if None in measures and 'scale' in node: + measures[dimension] = nodes.parse_measure(node[dimension]) + if 'scale' in node and len(measures) < 2: # supplement with (unitless) values read from image file imgsize = self.read_size_with_PIL(node) if imgsize: - measures = [measure or (imgvalue, '') - for measure, imgvalue in zip(measures, imgsize)] - # scale values - factor = node.get('scale', 100) / 100 # scaling factor - if factor != 1: - measures = [(measure[0] * factor, measure[1]) - for measure in measures if measure] - # format as <img> attributes, - # use "width" and "hight" for unitless values and "style" else, - # e.g., height': '32' 'style': 'width: 4 em;'}``: - size_atts = {} # attributes "width", "height", or "style" + for dimension, value in zip(dimensions, imgsize): + if dimension not in measures: + measures[dimension] = (value, '') + # Scale and format as <img> attributes, + # use "width" and "hight" for unitless values and "style" else: + scaling_factor = node.get('scale', 100) / 100 + size_atts = {} declarations = [] # declarations for the "style" attribute - for dimension, measure in zip(dimensions, measures): - if measure is None: - continue - value, unit = measure + for dimension, (value, unit) in measures.items(): + value *= scaling_factor if unit: declarations.append(f'{dimension}: {value:g}{unit};') else: Modified: trunk/docutils/docutils/writers/latex2e/__init__.py =================================================================== --- trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-19 10:20:44 UTC (rev 9932) @@ -2390,27 +2390,17 @@ self.requirements['~header'] = ''.join(self.out) self.pop_output_collector() - def to_latex_length(self, length_str): - """Convert `length_str` with rst length to LaTeX length + def to_latex_length(self, length_str: str) -> str: + """Convert "measure" `length_str` to LaTeX length specification. + + Note: the default length unit will change from "bp" + (Postscript point) to "px" in Docutils 1.0. """ - match = re.match(r'(\d*\.?\d*)\s*(\S*)', length_str) - if not match: - return length_str - value, unit = match.groups()[:2] - # no unit or "DTP" points (called 'bp' in TeX): - if unit in ('', 'pt'): - length_str = '%sbp' % value - # percentage: relate to current line width - elif unit == '%': - length_str = '%.3f\\linewidth' % (float(value)/100.0) - elif self.is_xetex and unit == 'px': - # XeTeX does not know the length unit px. - # Use \pdfpxdimen, the macro to set the value of 1 px in pdftex. - # This way, configuring works the same for pdftex and xetex. - if not self.fallback_stylesheet: - self.fallbacks['_providelength'] = PreambleCmds.providelength - self.fallbacks['px'] = '\n\\DUprovidelength{\\pdfpxdimen}{1bp}\n' - length_str = r'%s\pdfpxdimen' % value + value, unit = nodes.parse_measure(length_str) + if unit in ('', 'pt'): # no unit or "Postscript points" + return f'{value}bp' # LaTeX uses symbol "bp" + if unit == '%': # percentage: relate to current line width + return f'{value/100:g}\\linewidth' return length_str def visit_image(self, node) -> None: Modified: trunk/docutils/docutils/writers/xetex/__init__.py =================================================================== --- trunk/docutils/docutils/writers/xetex/__init__.py 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/docutils/writers/xetex/__init__.py 2024-09-19 10:20:44 UTC (rev 9932) @@ -24,6 +24,7 @@ from docutils import frontend from docutils.writers import latex2e +from docutils.writers.latex2e import PreambleCmds class Writer(latex2e.Writer): @@ -145,3 +146,18 @@ else: self.requirements['_inputenc'] = (r'\XeTeXinputencoding %s ' % self.latex_encoding) + + def to_latex_length(self, length_str: str) -> str: + """Convert "measure" `length_str` to LaTeX length specification. + + XeTeX does not know the length unit px. + Use ``\\pdfpxdimen``, the macro holding the value of 1 px in pdfTeX. + This way, configuring works the same for pdftex and xetex. + """ + length_str = super().to_latex_length(length_str) + if length_str.endswith('px'): + if not self.fallback_stylesheet: + self.fallbacks['_providelength'] = PreambleCmds.providelength + self.fallbacks['px'] = '\n\\DUprovidelength{\\pdfpxdimen}{1bp}\n' + return length_str.replace('px', '\\pdfpxdimen') + return length_str Modified: trunk/docutils/test/functional/expected/latex_cornercases.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_cornercases.tex 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/test/functional/expected/latex_cornercases.tex 2024-09-19 10:20:44 UTC (rev 9932) @@ -305,11 +305,11 @@ Image with 20\% width: -\includegraphics[width=0.200\linewidth]{../../../docs/user/rst/images/title.png} +\includegraphics[width=0.2\linewidth]{../../../docs/user/rst/images/title.png} Image with 100\% width: -\includegraphics[width=1.000\linewidth]{../../../docs/user/rst/images/title.png} +\includegraphics[width=1\linewidth]{../../../docs/user/rst/images/title.png} \section{Tables% @@ -548,7 +548,7 @@ The \DUroletitlereference{width} option overrides \textquotedbl{}auto\textquotedbl{} \DUroletitlereference{widths} as standard LaTeX tables don't have a global width setting: -\setlength{\DUtablewidth}{\dimexpr0.600\linewidth-5\arrayrulewidth\relax}% +\setlength{\DUtablewidth}{\dimexpr0.6\linewidth-5\arrayrulewidth\relax}% \begin{longtable}{|p{\DUcolumnwidth{0.400}}|p{\DUcolumnwidth{0.200}}|p{\DUcolumnwidth{0.200}}|p{\DUcolumnwidth{0.200}}|} \caption{This table has \DUroletitlereference{widths} \textquotedbl{}auto\textquotedbl{} (ignored) and \DUroletitlereference{width} 60\%.}\\ \hline Modified: trunk/docutils/test/functional/expected/latex_memoir.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_memoir.tex 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/test/functional/expected/latex_memoir.tex 2024-09-19 10:20:44 UTC (rev 9932) @@ -816,7 +816,7 @@ An image directive (also clickable -{}- a hyperlink reference): -\hyperref[directives]{\includegraphics[width=0.700\linewidth]{../../../docs/user/rst/images/title.png}} +\hyperref[directives]{\includegraphics[width=0.7\linewidth]{../../../docs/user/rst/images/title.png}} Image with multiple IDs: @@ -858,7 +858,7 @@ Relative units allow adaption of the image to the screen or paper size. An image occupying 50\% of the line width: -\includegraphics[width=0.500\linewidth]{../../../docs/user/rst/images/title.png} +\includegraphics[width=0.5\linewidth]{../../../docs/user/rst/images/title.png} A \emph{figure} is an image with a caption and/or a legend. With page-based output media, figures might float to a different position if this helps the page @@ -1670,7 +1670,7 @@ Here's a list table exercising all features: \begin{DUclass}{test} -\setlength{\DUtablewidth}{0.950\linewidth}% +\setlength{\DUtablewidth}{0.95\linewidth}% \begin{longtable}{|p{0.133\DUtablewidth}|p{0.110\DUtablewidth}|p{0.249\DUtablewidth}|} \caption{list table with integral header}\\ \hline @@ -1832,7 +1832,7 @@ \begin{description} \item[{Math-Accents:}] \leavevmode -\setlength{\DUtablewidth}{1.000\linewidth}% +\setlength{\DUtablewidth}{1\linewidth}% \begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}} $\acute{a}$ \texttt{\textbackslash{}acute\{a\}} Modified: trunk/docutils/test/functional/expected/standalone_rst_latex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2024-09-19 10:20:44 UTC (rev 9932) @@ -817,7 +817,7 @@ An image directive (also clickable – a hyperlink reference): -\hyperref[directives]{\includegraphics[width=0.700\linewidth]{../../../docs/user/rst/images/title.png}} +\hyperref[directives]{\includegraphics[width=0.7\linewidth]{../../../docs/user/rst/images/title.png}} Image with multiple IDs: @@ -859,7 +859,7 @@ Relative units allow adaption of the image to the screen or paper size. An image occupying 50\% of the line width: -\includegraphics[width=0.500\linewidth]{../../../docs/user/rst/images/title.png} +\includegraphics[width=0.5\linewidth]{../../../docs/user/rst/images/title.png} A \emph{figure} is an image with a caption and/or a legend. With page-based output media, figures might float to a different position if this helps the page @@ -1692,7 +1692,7 @@ Here’s a list table exercising all features: \begin{DUclass}{test} -\setlength{\DUtablewidth}{0.950\linewidth}% +\setlength{\DUtablewidth}{0.95\linewidth}% \begin{longtable}{|p{0.133\DUtablewidth}|p{0.110\DUtablewidth}|p{0.249\DUtablewidth}|} \caption{list table with integral header}\\ \hline @@ -1854,7 +1854,7 @@ \begin{description} \item[{Math-Accents:}] \leavevmode -\setlength{\DUtablewidth}{1.000\linewidth}% +\setlength{\DUtablewidth}{1\linewidth}% \begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}} $\acute{a}$ \texttt{\textbackslash{}acute\{a\}} Modified: trunk/docutils/test/functional/expected/standalone_rst_xetex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-15 11:13:43 UTC (rev 9931) +++ trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-19 10:20:44 UTC (rev 9932) @@ -852,7 +852,7 @@ An image directive (also clickable – a hyperlink reference): -\hyperref[directives]{\includegraphics[width=0.700\linewidth]{../../../docs/user/rst/images/title.png}} +\hyperref[directives]{\includegraphics[width=0.7\linewidth]{../../../docs/user/rst/images/title.png}} Image with multiple IDs: @@ -894,7 +894,7 @@ Relative units allow adaption of the image to the screen or paper size. An image occupying 50\% of the line width: -\includegraphics[width=0.500\linewidth]{../../../docs/user/rst/images/title.png} +\includegraphics[width=0.5\linewidth]{../../../docs/user/rst/images/title.png} A \emph{figure} is an image with a caption and/or a legend. With page-based output media, figures might float to a different position if this helps the page @@ -1731,7 +1731,7 @@ Here’s a list table exercising all features: \begin{DUclass}{test} -\setlength{\DUtablewidth}{0.950\linewidth}% +\setlength{\DUtablewidth}{0.95\linewidth}% \begin{longtable}{|p{0.133\DUtablewidth}|p{0.110\DUtablewidth}|p{0.249\DUtablewidth}|} \caption{list table with integral header}\\ \hline @@ -1893,7 +1893,7 @@ \begin{description} \item[{Math-Accents:}] \leavevmode -\setlength{\DUtablewidth}{1.000\linewidth}% +\setlength{\DUtablewidth}{1\linewidth}% \begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}} $\acute{a}$ \texttt{\textbackslash{}acute\{a\}} Added: trunk/docutils/test/test_writers/test_xetex_misc.py =================================================================== --- trunk/docutils/test/test_writers/test_xetex_misc.py (rev 0) +++ trunk/docutils/test/test_writers/test_xetex_misc.py 2024-09-19 10:20:44 UTC (rev 9932) @@ -0,0 +1,78 @@ +#! /usr/bin/env python3 +# $Id$ +# Author: Günter Milde +# Maintainer: doc...@li... +# :Copyright: 2024 Günter Milde, +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: https://opensource.org/licenses/BSD-2-Clause + +""" +Miscellaneous XeTeX/LuaTeX writer tests. +""" + +from pathlib import Path +import sys +import unittest + + +if __name__ == '__main__': + # prepend the "docutils root" to the Python library path + # so we import the local `docutils` package. + sys.path.insert(0, str(Path(__file__).resolve().parents[2])) + +from docutils import core +from docutils.writers import xetex + +# TEST_ROOT is ./test/ from the docutils root +TEST_ROOT = Path(__file__).parents[1] +DATA_ROOT = TEST_ROOT / 'data' + +px_sample = """\ +.. image:: foo.pdf + :width: 250 px + :height: 50pt +""" + +px_body = r""" +\includegraphics[height=50bp,width=250\pdfpxdimen]{foo.pdf} +""" + +px_fallback = r""" +% Provide a length variable and set default, if it is new +\providecommand*{\DUprovidelength}[2]{ + \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{} +} + +\DUprovidelength{\pdfpxdimen}{1bp} + + +""" + + +class PublishTestCase(unittest.TestCase): + maxDiff = None + + settings = {'_disable_config': True, + # avoid latex writer future warnings: + 'use_latex_citations': False, + 'legacy_column_widths': False, + } + + def test_px_workaround(self): + """Check the workaround for length unit 'px' missing in XeTeX. + """ + parts = core.publish_parts(px_sample, + writer=xetex.Writer(), + settings_overrides=self.settings) + self.assertEqual(px_body, parts['body']) + self.assertEqual(px_fallback, parts['fallbacks']) + + +if __name__ == '__main__': + unittest.main() Property changes on: trunk/docutils/test/test_writers/test_xetex_misc.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-20 06:31:01
|
Revision: 9933 http://sourceforge.net/p/docutils/code/9933 Author: milde Date: 2024-09-20 06:30:59 +0000 (Fri, 20 Sep 2024) Log Message: ----------- Revise/fix handling of length specification in the ODT writer. Use "px" as fallback unit for unitless image size attributes. Fix conversion factor of "pc" (pica) to "cm". Fix conversion of image width in "%" if the height is specified. Adjust fallback DPI value (currently not used) to match CSS units. Document that PIL/Pillow is always required if images are inserted without specifying width and height, also if "scale" is not used. Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/docs/user/odt.rst trunk/docutils/docutils/writers/odf_odt/__init__.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-19 10:20:44 UTC (rev 9932) +++ trunk/docutils/HISTORY.rst 2024-09-20 06:30:59 UTC (rev 9933) @@ -181,6 +181,13 @@ - `null.Writer.translate()` sets `self.output` to the empty string. +* docutils/writers/odf_odt/__init__.py + + - Use "px" as fallback unit for unitless image size attributes. + - Fix conversion factor of "pc" (pica) to "cm". + - Fix conversion of image width in "%" if the height is specified. + - Adjust fallback DPI value (currently not used) to match CSS units. + * tools/rst2odt.py - Use `core.publish_file()` instead of `core.publish_file_to_binary()`. Modified: trunk/docutils/docs/user/odt.rst =================================================================== --- trunk/docutils/docs/user/odt.rst 2024-09-19 10:20:44 UTC (rev 9932) +++ trunk/docutils/docs/user/odt.rst 2024-09-20 06:30:59 UTC (rev 9933) @@ -39,8 +39,8 @@ highlighting of code in literal blocks. See section `Syntax highlighting`_. -- Optional -- `Python Imaging Library`_ (PIL) is required if on an - image or figure directive, you specify ``scale`` but not ``width`` +- Optional -- `Python Imaging Library`_ (PIL/Pillow_) is required if + you use the image or figure directive but don't specify ``width`` and ``height``. See section `Images and figures`_. @@ -975,23 +975,21 @@ Images and figures ------------------ -If on the image or the figure directive you provide the scale option -but do not provide the width and height options, then ``odtwriter`` -will attempt to determine the size of the image using the `Python -Imaging Library`_ (PIL). If ``odtwriter`` cannot find and import +The ODT Writer only supports fixed `length units`_ ("cm", "mm", "in", +"pc", "pt", "px) for the size attributes "width", and "height". +The fallback unit (used for attribute values without unit) is "px". + +If on the image or the figure directive you do not provide the width +and height options, then ``odtwriter`` will attempt to determine the +size of the image using the Python Imaging Library (PIL/Pillow_). +If ``odtwriter`` cannot find and import the Python Imaging Library, it will raise an exception. If this ocurrs, you can fix it by doing one of the following: - Install the Python Imaging Library or -- Remove the ``scale`` option or - - Add both the ``width`` and the ``height`` options. -So, the rule is: if on any image or figure, you specify scale but -not both width and height, you must install the `Python Imaging -Library`_ library. - For more information about PIL, see: `Python Imaging Library`_. @@ -1188,6 +1186,8 @@ tools.html#rst2odt .. _reStructuredText: ../ref/rst/restructuredtext.html +.. _length units: + ../ref/rst/restructuredtext.html#length-units .. _`OpenDocument Text`: https://en.wikipedia.org/wiki/OpenDocument .. _LibreOffice: @@ -1196,3 +1196,4 @@ https://pygments.org/ .. _`Python Imaging Library`: https://en.wikipedia.org/wiki/Python_Imaging_Library +.. _`Pillow`: https://pypi.org/project/pillow/ Modified: trunk/docutils/docutils/writers/odf_odt/__init__.py =================================================================== --- trunk/docutils/docutils/writers/odf_odt/__init__.py 2024-09-19 10:20:44 UTC (rev 9932) +++ trunk/docutils/docutils/writers/odf_odt/__init__.py 2024-09-20 06:30:59 UTC (rev 9933) @@ -2207,6 +2207,7 @@ 'Invalid %s for image: "%s". ' 'Error: "%s".' % ( attr, node.attributes[attr], exp)) + size, unit = 0.5, 'cm' # fallback to avoid consequential error return size, unit def convert_to_cm(self, size): @@ -2223,13 +2224,15 @@ elif size.endswith('pt'): size = float(size[:-2]) * 0.035 # convert pt to cm elif size.endswith('pc'): - size = float(size[:-2]) * 2.371 # convert pc to cm + size = float(size[:-2]) * 0.423 # convert pc to cm elif size.endswith('mm'): size = float(size[:-2]) * 0.1 # convert mm to cm elif size.endswith('cm'): size = float(size[:-2]) + elif size[-1:] in '0123456789.': # no unit, use px + size = float(size) * 0.026 # convert px to cm else: - raise ValueError('unknown unit type') + raise ValueError('unit not supported with ODT') unit = 'cm' return size, unit @@ -2250,8 +2253,12 @@ scale = self.get_image_scale(node) width, width_unit = self.get_image_width_height(node, 'width') height, _ = self.get_image_width_height(node, 'height') - dpi = (72, 72) - if PIL is not None and source in self.image_dict: + dpi = (96, 96) # image resolution in pixel per inch + if width is None or height is None: + if PIL is None: + raise RuntimeError( + 'image size not fully specified and PIL not installed') + # TODO: catch error and warn (similar to unsupported units). filename, destination = self.image_dict[source] with PIL.Image.open(filename, 'r') as img: img_size = img.size @@ -2261,26 +2268,19 @@ iter(dpi) except TypeError: dpi = (dpi, dpi) - else: - img_size = None - if width is None or height is None: - if img_size is None: - raise RuntimeError( - 'image size not fully specified and PIL not installed') - if width is None: - width = img_size[0] - width = float(width) * 0.026 # convert px to cm + # TODO: use dpi when converting px to cm + if width is None: + width = img_size[0] * 0.026 # convert px to cm + if height is None and width_unit != '%': + height = img_size[1] * 0.026 # convert px to cm + if width_unit == '%': + factor = width + line_width = self.get_page_width() + width = factor * line_width if height is None: - height = img_size[1] - height = float(height) * 0.026 # convert px to cm - if width_unit == '%': - factor = width - image_width = img_size[0] - image_width = float(image_width) * 0.026 # convert px to cm - image_height = img_size[1] - image_height = float(image_height) * 0.026 # convert px to cm - line_width = self.get_page_width() - width = factor * line_width + # scale proportionally + image_width = img_size[0] * 0.026 # convert px to cm + image_height = img_size[1] * 0.026 # convert px to cm factor = (factor * line_width) / image_width height = factor * image_height width *= scale This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-20 08:32:44
|
Revision: 9936 http://sourceforge.net/p/docutils/code/9936 Author: milde Date: 2024-09-20 08:32:41 +0000 (Fri, 20 Sep 2024) Log Message: ----------- Use `nodes.parse_measure()` in rST directive option conversion. Simplify `parsers.rst.directives.get_measure()` by using `nodes.parse_measure()`. Sort the list of supported length units in the order used in the rST specification (based on the CSS specification). Update and extend the lenght value handling tests. Clarify and test behaviour: * case of length units is preserved (in contrast to CSS) * the restriction of supported units is a rST feature while the Docutils Doctree allows any run of ASCII letters + {U+03BC} or a percent sign as units on attributes with value type "measure". Modified Paths: -------------- trunk/docutils/docutils/parsers/rst/directives/__init__.py trunk/docutils/test/test_nodes.py trunk/docutils/test/test_parsers/test_docutils_xml/test_parse_element.py trunk/docutils/test/test_parsers/test_rst/test_directives/test_images.py Modified: trunk/docutils/docutils/parsers/rst/directives/__init__.py =================================================================== --- trunk/docutils/docutils/parsers/rst/directives/__init__.py 2024-09-20 08:32:28 UTC (rev 9935) +++ trunk/docutils/docutils/parsers/rst/directives/__init__.py 2024-09-20 08:32:41 UTC (rev 9936) @@ -244,26 +244,24 @@ return nonnegative_int(argument) -length_units = ['em', 'ex', 'px', 'in', 'cm', 'mm', 'pt', 'pc'] +length_units = ['em', 'ex', 'in', 'cm', 'mm', 'pt', 'pc', 'px'] def get_measure(argument, units): """ - Check for a positive argument of one of the units and return a - normalized string of the form "<value><unit>" (without space in - between). - (Directive option conversion function.) + Check for a positive argument of one of the `units`. + Return a normalized string of the form "<value><unit>" + (without space inbetween). + To be called from directive option conversion functions. """ - match = re.match(r'^([0-9.]+) *(%s)$' % '|'.join(units), argument) - try: - float(match.group(1)) - except (AttributeError, ValueError): + value, unit = nodes.parse_measure(argument) + if value < 0 or unit not in units: raise ValueError( - 'not a positive measure of one of the following units:\n"%s"' - % '" "'.join(units)) - return match.group(1) + match.group(2) + 'not a positive number or measure of one of the following units:\n' + + ', '.join(u for u in units if u)) + return f'{value}{unit}' def length_or_unitless(argument: str) -> str: @@ -289,12 +287,11 @@ """ try: return get_measure(argument, length_units + ['%']) - except ValueError: + except ValueError as error: try: return get_measure(argument, ['']) + default except ValueError: - # raise ValueError with list of valid units: - return get_measure(argument, length_units + ['%']) + raise error def class_option(argument: str) -> list[str]: Modified: trunk/docutils/test/test_nodes.py =================================================================== --- trunk/docutils/test/test_nodes.py 2024-09-20 08:32:28 UTC (rev 9935) +++ trunk/docutils/test/test_nodes.py 2024-09-20 08:32:41 UTC (rev 9936) @@ -1172,10 +1172,21 @@ def test_validate_measure(self): # number (may be decimal fraction) + optional unit - self.assertEqual(nodes.validate_measure('8ex'), '8ex') + # internal whitespace is removed + self.assertEqual(nodes.validate_measure('8 ex'), '8ex') self.assertEqual(nodes.validate_measure('2'), '2') - # internal whitespace is removed + # unit is "%" or a run of ASCII letters plus "µ"; case is preserved self.assertEqual(nodes.validate_measure('3.5 %'), '3.5%') + self.assertEqual(nodes.validate_measure('300 µm'), '300µm') + self.assertEqual(nodes.validate_measure('4 kHz'), '4kHz') + # other characters and whitespace are not allowed in a unit identifier + with self.assertRaisesRegex(ValueError, 'no valid measure'): + nodes.validate_measure('3 micro-farads') + with self.assertRaisesRegex(ValueError, 'no valid measure'): + nodes.validate_measure('3 micro farads') + # a number is required + with self.assertRaisesRegex(ValueError, '"ex" is no valid measure'): + nodes.validate_measure('ex') # padding whitespace is not valid with self.assertRaisesRegex(ValueError, '"8ex " is no valid measure'): nodes.validate_measure('8ex ') Modified: trunk/docutils/test/test_parsers/test_docutils_xml/test_parse_element.py =================================================================== --- trunk/docutils/test/test_parsers/test_docutils_xml/test_parse_element.py 2024-09-20 08:32:28 UTC (rev 9935) +++ trunk/docutils/test/test_parsers/test_docutils_xml/test_parse_element.py 2024-09-20 08:32:41 UTC (rev 9936) @@ -82,9 +82,10 @@ def test_element_with_attributes(self): xml = ('<image align="left" alt="a barking dog" height="3ex"' - ' loading="embed" scale="3" uri="dog.jpg" width="4cm"/>') + ' loading="embed" scale="3" uri="dog.jpg" width="4.50 cm"/>') node = docutils_xml.parse_element(xml) - self.assertEqual(xml, str(node)) + # attribute values are normalized: + self.assertEqual(xml.replace('4.50 cm', '4.5cm'), str(node)) def test_element_with_invalid_attributes(self): """Silently accept invalid attribute names and values. @@ -91,13 +92,15 @@ Validation reports problems. """ - xml = ('<image breadth="3 cm" height="3 inch"/>') + xml = ('<image breadth="3 cm" height="three inch"/>') node = docutils_xml.parse_element(xml) - self.assertEqual(xml.replace('3 inch', '3inch'), str(node)) - with self.assertRaisesRegex(ValueError, - 'Element <image breadth="3 cm".*invalid:\n' - '.*"breadth" not one of "ids", ' - ): + self.assertEqual(xml, str(node)) + with self.assertRaisesRegex( + ValueError, + 'Element <image .*> invalid:\n' + ' Attribute "breadth" not one of "ids", .*, "loading".\n' + ' Attribute "height" has invalid value "three inch".\n' + ' "three inch" is no valid measure.'): node.validate() @@ -116,8 +119,8 @@ 'names': []} def test_alt(self): # CDATA (str) - xml = ('<image alt="a barking dog" align="left" height="3ex"' - ' loading="embed" scale="3" uri="dog.jpg" width="4cm"/>') + xml = ('<image alt="a barking dog" align="left" height="3 ex"' + ' loading="embed" scale="3" uri="dog.jpg" width="4 cm"/>') expected = {'alt': 'a barking dog', 'align': 'left', 'height': '3ex', Modified: trunk/docutils/test/test_parsers/test_rst/test_directives/test_images.py =================================================================== --- trunk/docutils/test/test_parsers/test_rst/test_directives/test_images.py 2024-09-20 08:32:28 UTC (rev 9935) +++ trunk/docutils/test/test_parsers/test_rst/test_directives/test_images.py 2024-09-20 08:32:41 UTC (rev 9936) @@ -23,6 +23,8 @@ class ParserTestCase(unittest.TestCase): + maxDiff = None + def test_parser(self): parser = Parser() settings = get_default_settings(Parser) @@ -170,14 +172,34 @@ <document source="test data"> <image height="100em" uri="picture.png" width="200px"> """], +# as in CSS3, units are case-insensitive (new in Docutils 0.22) ["""\ .. image:: picture.png + :width: 50 mm + :height: 100 em +""", +"""\ +<document source="test data"> + <image height="100em" uri="picture.png" width="50mm"> +"""], +# TODO: support CSS3 units (cf. [feature-requests:#57] +["""\ +.. image:: picture.png :width: 50% - :height: 10mm + :height: 10vh """, """\ <document source="test data"> - <image height="10mm" uri="picture.png" width="50%"> + <system_message level="3" line="1" source="test data" type="ERROR"> + <paragraph> + Error in "image" directive: + invalid option value: (option: "height"; value: '10vh') + not a positive number or measure of one of the following units: + em, ex, in, cm, mm, pt, pc, px. + <literal_block xml:space="preserve"> + .. image:: picture.png + :width: 50% + :height: 10vh """], ["""\ .. image:: picture.png @@ -190,8 +212,8 @@ <paragraph> Error in "image" directive: invalid option value: (option: "height"; value: \'40%\') - not a positive measure of one of the following units: - "em" "ex" "px" "in" "cm" "mm" "pt" "pc" "". + not a positive number or measure of one of the following units: + em, ex, in, cm, mm, pt, pc, px. <literal_block xml:space="preserve"> .. image:: picture.png :width: 50% @@ -207,8 +229,8 @@ <paragraph> Error in "image" directive: invalid option value: (option: "width"; value: \'20mc\') - not a positive measure of one of the following units: - "em" "ex" "px" "in" "cm" "mm" "pt" "pc" "%". + not a positive number or measure of one of the following units: + em, ex, in, cm, mm, pt, pc, px, %. <literal_block xml:space="preserve"> .. image:: picture.png :width: 20mc This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-23 22:36:41
|
Revision: 9937 http://sourceforge.net/p/docutils/code/9937 Author: milde Date: 2024-09-23 22:36:38 +0000 (Mon, 23 Sep 2024) Log Message: ----------- LaTeX writer: stop requiring "ifthen.sty", fix Babel warning. Replace use of ``\ifthenelse`` from "ifthen.sty" with the eTeX primitive ``\ifdefined``. Mark the main language when loading "babel" to prevent a warning about another language being processed last. This happens when there is more than one language in the document as we put the main language also in the document options (for other packages to see). Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/RELEASE-NOTES.rst trunk/docutils/docs/user/latex.rst trunk/docutils/docutils/writers/latex2e/__init__.py trunk/docutils/docutils/writers/latex2e/docutils.sty trunk/docutils/test/functional/expected/cyrillic.tex trunk/docutils/test/functional/expected/latex_babel.tex trunk/docutils/test/functional/expected/latex_cornercases.tex trunk/docutils/test/functional/expected/latex_docinfo.tex trunk/docutils/test/functional/expected/latex_leavevmode.tex trunk/docutils/test/functional/expected/latex_literal_block.tex trunk/docutils/test/functional/expected/latex_literal_block_fancyvrb.tex trunk/docutils/test/functional/expected/latex_literal_block_listings.tex trunk/docutils/test/functional/expected/latex_literal_block_verbatim.tex trunk/docutils/test/functional/expected/latex_literal_block_verbatimtab.tex trunk/docutils/test/functional/expected/latex_memoir.tex trunk/docutils/test/functional/expected/standalone_rst_latex.tex trunk/docutils/test/functional/expected/standalone_rst_xetex.tex trunk/docutils/test/functional/expected/xetex-cyrillic.tex trunk/docutils/test/test_writers/test_latex2e.py trunk/docutils/test/test_writers/test_xetex_misc.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/HISTORY.rst 2024-09-23 22:36:38 UTC (rev 9937) @@ -162,6 +162,9 @@ move XeTeX-specific code to the "xetex" writer. - Don't wrap references with custom reference-label_ in a ``\hyperref`` command. + - Stop requiring "ifthen.sty". Replace use of ``\ifthenelse{\isundefined...`` + with the eTeX primitive ``\ifdefined``. + - Mark the main language when loading "babel". - Provide an "unknown_references_resolver" (cf. `docutils/TransformSpec`) for citation references resolved with BibTeX (cf. `use_bibtex`_ setting). Modified: trunk/docutils/RELEASE-NOTES.rst =================================================================== --- trunk/docutils/RELEASE-NOTES.rst 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/RELEASE-NOTES.rst 2024-09-23 22:36:38 UTC (rev 9937) @@ -198,6 +198,9 @@ command. The "hyperref" package generates hyperlinks for labels by default, so there is no change in the PDF (except for "ref*"). + Stop requiring "ifthen.sty". Replace use of + ``\ifthenelse{\isundefined...`` with the eTeX primitive ``\ifdefined``. + .. _reference-label: docs/user/config.html#reference-label HTML5: Modified: trunk/docutils/docs/user/latex.rst =================================================================== --- trunk/docutils/docs/user/latex.rst 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/docs/user/latex.rst 2024-09-23 22:36:38 UTC (rev 9937) @@ -379,7 +379,7 @@ Some customizations require commands at places other than the insertion point of stylesheets or depend on the deletion/replacement of parts of the document. This can be done via a custom template. See the `publisher -documentation`_ for a description of the document parts available in a +documentation`_ for a description of the `document parts`_ available in a template file. Option: @@ -396,8 +396,11 @@ --template=titlepage.tex .. _publisher documentation: ../api/publisher.html +.. _document parts: + ../api/publisher.html#parts-provided-by-the-xe-latex-writers .. _template: config.html#template-latex-writers + Raw LaTeX ````````` Modified: trunk/docutils/docutils/writers/latex2e/__init__.py =================================================================== --- trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-23 22:36:38 UTC (rev 9937) @@ -435,7 +435,10 @@ def __call__(self): """Return the babel call with correct options and settings""" languages = sorted(self.otherlanguages.keys()) - languages.append(self.language or 'english') + if languages: + languages.append(f'main={self.language or "english"}') + else: + languages.append(self.language or 'english') self.setup = [r'\usepackage[%s]{babel}' % ','.join(languages)] # Deactivate "active characters" shorthands = [] @@ -456,7 +459,7 @@ self.setup.extend([r'\makeatletter', r' \addto\extrasbasque{\bbl@deactivate{~}}', r'\makeatother']) - if (languages[-1] == 'english' + if (languages[-1] == 'main=english' and 'french' in self.otherlanguages.keys()): self.setup += ['% Prevent side-effects if French hyphenation ' 'patterns are not loaded:', @@ -520,11 +523,12 @@ \floatplacement{figure}{H} % place figures here definitely""" PreambleCmds.linking = r"""%% hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[%s]{hyperref} \usepackage{bookmark} \urlstyle{same} %% normal text font (alternatives: tt, rm, sf) -}{}""" +\fi""" PreambleCmds.minitoc = r"""%% local table of contents \usepackage{minitoc}""" @@ -1254,7 +1258,6 @@ (self.documentoptions, settings.documentclass)] self.requirements = SortableDict() # made a list in depart_document() - self.requirements['__static'] = r'\usepackage{ifthen}' self.latex_preamble = [settings.latex_preamble] self.fallbacks = SortableDict() # made a list in depart_document() self.pdfsetup = [] # PDF properties (hyperref package) Modified: trunk/docutils/docutils/writers/latex2e/docutils.sty =================================================================== --- trunk/docutils/docutils/writers/latex2e/docutils.sty 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/docutils/writers/latex2e/docutils.sty 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,6 +1,6 @@ %% docutils.sty: macros for Docutils LaTeX output. %% -%% Copyright © 2020 Günter Milde +%% Copyright © 2020, 2024 Günter Milde %% Released under the terms of the `2-Clause BSD license`, in short: %% %% Copying and distribution of this file, with or without modification, @@ -8,7 +8,12 @@ %% notice and this notice are preserved. %% This file is offered as-is, without any warranty. +% docutils.sty +% ************ +% +% .. contents:: % .. include:: README.md +% :parser: commonmark % % Implementation % ============== @@ -17,7 +22,7 @@ \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{docutils} - [2021/05/18 macros for Docutils LaTeX output] + [2024-09-23 macros for Docutils LaTeX output] % Helpers % ------- @@ -27,19 +32,23 @@ % class handling for environments (block-level elements) % \begin{DUclass}{spam} tries \DUCLASSspam and % \end{DUclass}{spam} tries \endDUCLASSspam -\ifx\DUclass\undefined % poor man's "provideenvironment" - \newenvironment{DUclass}[1]% - {% "#1" does not work in end-part of environment. - \def\DocutilsClassFunctionName{DUCLASS#1} +\ifdefined\DUclass +\else % poor man's "provideenvironment" + \newenvironment{DUclass}[1]% + {% "#1" does not work in end-part of environment. + \def\DocutilsClassFunctionName{DUCLASS#1} \csname \DocutilsClassFunctionName \endcsname}% - {\csname end\DocutilsClassFunctionName \endcsname}% + {\csname end\DocutilsClassFunctionName \endcsname}% \fi % providelength:: % Provide a length variable and set default, if it is new -\providecommand*{\DUprovidelength}[2]{ - \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{} +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1 + \else + \newlength{#1}\setlength{#1}{#2}% + \fi } @@ -46,7 +55,7 @@ % Configuration defaults % ---------------------- % -% See `Docutils LaTeX Writer`_ for details. +% See `Generating LaTeX with Docutils`_ for details. % % abstract:: @@ -61,7 +70,7 @@ \renewenvironment{quote}{\begin{center}}{\end{center}}% } -% TODO: add \em to set dedication text in italics? +% .. TODO: add \em to set dedication text in italics? % % docinfo:: @@ -88,28 +97,30 @@ % admonition:: % admonition environment (specially marked topic) -\ifx\DUadmonition\undefined % poor man's "provideenvironment" - \newbox{\DUadmonitionbox} - \newenvironment{DUadmonition}% - {\begin{center} - \begin{lrbox}{\DUadmonitionbox} - \begin{minipage}{0.9\linewidth} - }% - { \end{minipage} - \end{lrbox} - \fbox{\usebox{\DUadmonitionbox}} - \end{center} - } +\ifdefined\DUadmonition +\else % poor man's "provideenvironment" + \newbox{\DUadmonitionbox} + \newenvironment{DUadmonition}% + {\begin{center} + \begin{lrbox}{\DUadmonitionbox} + \begin{minipage}{0.9\linewidth} + }% + { \end{minipage} + \end{lrbox} + \fbox{\usebox{\DUadmonitionbox}} + \end{center} + } \fi % fieldlist:: % field list environment (for separate configuration of `field lists`) -\ifthenelse{\isundefined{\DUfieldlist}}{ +\ifdefined\DUfieldlist +\else \newenvironment{DUfieldlist}% {\quote\description} {\enddescription\endquote} -}{} +\fi % footnotes:: @@ -141,15 +152,17 @@ % legend:: % legend environment (in figures and formal tables) -\ifthenelse{\isundefined{\DUlegend}}{ +\ifdefined\DUlegend +\else \newenvironment{DUlegend}{\small}{} -}{} +\fi % lineblock:: % line block environment \DUprovidelength{\DUlineblockindent}{2.5em} -\ifthenelse{\isundefined{\DUlineblock}}{ +\ifdefined\DUlineblock +\else \newenvironment{DUlineblock}[1]{% \list{}{\setlength{\partopsep}{\parskip} \addtolength{\partopsep}{\baselineskip} @@ -160,7 +173,7 @@ \raggedright } {\endlist} -}{} +\fi % optionlist:: @@ -167,7 +180,8 @@ % list of command line options \providecommand*{\DUoptionlistlabel}[1]{\bfseries #1 \hfill} \DUprovidelength{\DUoptionlistindent}{3cm} -\ifthenelse{\isundefined{\DUoptionlist}}{ +\ifdefined\DUoptionlist +\else \newenvironment{DUoptionlist}{% \list{}{\setlength{\labelwidth}{\DUoptionlistindent} \setlength{\rightmargin}{1cm} @@ -177,7 +191,7 @@ \renewcommand{\makelabel}{\DUoptionlistlabel}} } {\endlist} -}{} +\fi % rubric:: @@ -221,3 +235,9 @@ \hspace*{\fill}\hrulefill\hspace*{\fill} \vskip 0.5\baselineskip } + + +% .. References: +% +% .. _Generating LaTeX with Docutils: +% https://docutils.sourceforge.io/docs/user/latex.html Modified: trunk/docutils/test/functional/expected/cyrillic.tex =================================================================== --- trunk/docutils/test/functional/expected/cyrillic.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/cyrillic.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,9 +1,8 @@ \documentclass[a4paper,russian]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1,T2A]{fontenc} -\usepackage[english,russian]{babel} +\usepackage[english,main=russian]{babel} \setcounter{secnumdepth}{0} %%% Custom LaTeX preamble @@ -18,11 +17,12 @@ %%% Fallback definitions for Docutils-specific commands % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi \hypersetup{ pdflang={ru}, } Modified: trunk/docutils/test/functional/expected/latex_babel.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_babel.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_babel.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,9 +1,8 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} -\usepackage[basque,esperanto,estonian,galician,ngerman,english]{babel} +\usepackage[basque,esperanto,estonian,galician,ngerman,main=english]{babel} \AtBeginDocument{\shorthandoff{.<>}} \deactivatetilden % restore ~ in Galician \makeatletter @@ -24,11 +23,12 @@ %%% Fallback definitions for Docutils-specific commands % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi %%% Body \begin{document} Modified: trunk/docutils/test/functional/expected/latex_cornercases.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_cornercases.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_cornercases.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,7 +1,6 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} \DeclareUnicodeCharacter{21D4}{\ensuremath{\Leftrightarrow}} \DeclareUnicodeCharacter{2660}{\ensuremath{\spadesuit}} @@ -33,42 +32,49 @@ % class handling for environments (block-level elements) % \begin{DUclass}{spam} tries \DUCLASSspam and % \end{DUclass}{spam} tries \endDUCLASSspam -\ifx\DUclass\undefined % poor man's "provideenvironment" - \newenvironment{DUclass}[1]% - {% "#1" does not work in end-part of environment. - \def\DocutilsClassFunctionName{DUCLASS#1} +\ifdefined\DUclass +\else % poor man's "provideenvironment" + \newenvironment{DUclass}[1]% + {% "#1" does not work in end-part of environment. + \def\DocutilsClassFunctionName{DUCLASS#1} \csname \DocutilsClassFunctionName \endcsname}% - {\csname end\DocutilsClassFunctionName \endcsname}% + {\csname end\DocutilsClassFunctionName \endcsname}% \fi % Provide a length variable and set default, if it is new -\providecommand*{\DUprovidelength}[2]{ - \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{} +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1 + \else + \newlength{#1}\setlength{#1}{#2}% + \fi } % admonition environment (specially marked topic) -\ifx\DUadmonition\undefined % poor man's "provideenvironment" - \newbox{\DUadmonitionbox} - \newenvironment{DUadmonition}% - {\begin{center} - \begin{lrbox}{\DUadmonitionbox} - \begin{minipage}{0.9\linewidth} - }% - { \end{minipage} - \end{lrbox} - \fbox{\usebox{\DUadmonitionbox}} - \end{center} - } +\ifdefined\DUadmonition +\else % poor man's "provideenvironment" + \newbox{\DUadmonitionbox} + \newenvironment{DUadmonition}% + {\begin{center} + \begin{lrbox}{\DUadmonitionbox} + \begin{minipage}{0.9\linewidth} + }% + { \end{minipage} + \end{lrbox} + \fbox{\usebox{\DUadmonitionbox}} + \end{center} + } \fi % legend environment (in figures and formal tables) -\ifthenelse{\isundefined{\DUlegend}}{ +\ifdefined\DUlegend +\else \newenvironment{DUlegend}{\small}{} -}{} +\fi % line block environment \DUprovidelength{\DUlineblockindent}{2.5em} -\ifthenelse{\isundefined{\DUlineblock}}{ +\ifdefined\DUlineblock +\else \newenvironment{DUlineblock}[1]{% \list{}{\setlength{\partopsep}{\parskip} \addtolength{\partopsep}{\baselineskip} @@ -79,12 +85,13 @@ \raggedright } {\endlist} -}{} +\fi % list of command line options \providecommand*{\DUoptionlistlabel}[1]{\bfseries #1 \hfill} \DUprovidelength{\DUoptionlistindent}{3cm} -\ifthenelse{\isundefined{\DUoptionlist}}{ +\ifdefined\DUoptionlist +\else \newenvironment{DUoptionlist}{% \list{}{\setlength{\labelwidth}{\DUoptionlistindent} \setlength{\rightmargin}{1cm} @@ -94,7 +101,7 @@ \renewcommand{\makelabel}{\DUoptionlistlabel}} } {\endlist} -}{} +\fi % title for topics, admonitions, unsupported section levels, and sidebar \providecommand*{\DUtitle}[1]{% @@ -110,11 +117,12 @@ } % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi \hypersetup{ pdftitle={Additional Tests for the LaTeX Writer}, } Modified: trunk/docutils/test/functional/expected/latex_docinfo.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_docinfo.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_docinfo.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,7 +1,6 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} %%% Custom LaTeX preamble @@ -15,11 +14,12 @@ %%% Fallback definitions for Docutils-specific commands % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi \hypersetup{ pdfauthor={Foo Fred;Bar Barney} } Modified: trunk/docutils/test/functional/expected/latex_leavevmode.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_leavevmode.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_leavevmode.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,7 +1,6 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} \usepackage{alltt} \usepackage{amsmath} @@ -27,17 +26,21 @@ % class handling for environments (block-level elements) % \begin{DUclass}{spam} tries \DUCLASSspam and % \end{DUclass}{spam} tries \endDUCLASSspam -\ifx\DUclass\undefined % poor man's "provideenvironment" - \newenvironment{DUclass}[1]% - {% "#1" does not work in end-part of environment. - \def\DocutilsClassFunctionName{DUCLASS#1} +\ifdefined\DUclass +\else % poor man's "provideenvironment" + \newenvironment{DUclass}[1]% + {% "#1" does not work in end-part of environment. + \def\DocutilsClassFunctionName{DUCLASS#1} \csname \DocutilsClassFunctionName \endcsname}% - {\csname end\DocutilsClassFunctionName \endcsname}% + {\csname end\DocutilsClassFunctionName \endcsname}% \fi % Provide a length variable and set default, if it is new -\providecommand*{\DUprovidelength}[2]{ - \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{} +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1 + \else + \newlength{#1}\setlength{#1}{#2}% + \fi } \providecommand*{\DUCLASSabstract}{ @@ -45,18 +48,19 @@ } % admonition environment (specially marked topic) -\ifx\DUadmonition\undefined % poor man's "provideenvironment" - \newbox{\DUadmonitionbox} - \newenvironment{DUadmonition}% - {\begin{center} - \begin{lrbox}{\DUadmonitionbox} - \begin{minipage}{0.9\linewidth} - }% - { \end{minipage} - \end{lrbox} - \fbox{\usebox{\DUadmonitionbox}} - \end{center} - } +\ifdefined\DUadmonition +\else % poor man's "provideenvironment" + \newbox{\DUadmonitionbox} + \newenvironment{DUadmonition}% + {\begin{center} + \begin{lrbox}{\DUadmonitionbox} + \begin{minipage}{0.9\linewidth} + }% + { \end{minipage} + \end{lrbox} + \fbox{\usebox{\DUadmonitionbox}} + \end{center} + } \fi % width of docinfo table @@ -63,11 +67,12 @@ \DUprovidelength{\DUdocinfowidth}{0.9\linewidth} % field list environment (for separate configuration of `field lists`) -\ifthenelse{\isundefined{\DUfieldlist}}{ +\ifdefined\DUfieldlist +\else \newenvironment{DUfieldlist}% {\quote\description} {\enddescription\endquote} -}{} +\fi % numerical or symbol footnotes with hyperlinks and backlinks \providecommand*{\DUfootnotemark}[3]{% @@ -94,7 +99,8 @@ % line block environment \DUprovidelength{\DUlineblockindent}{2.5em} -\ifthenelse{\isundefined{\DUlineblock}}{ +\ifdefined\DUlineblock +\else \newenvironment{DUlineblock}[1]{% \list{}{\setlength{\partopsep}{\parskip} \addtolength{\partopsep}{\baselineskip} @@ -105,12 +111,13 @@ \raggedright } {\endlist} -}{} +\fi % list of command line options \providecommand*{\DUoptionlistlabel}[1]{\bfseries #1 \hfill} \DUprovidelength{\DUoptionlistindent}{3cm} -\ifthenelse{\isundefined{\DUoptionlist}}{ +\ifdefined\DUoptionlist +\else \newenvironment{DUoptionlist}{% \list{}{\setlength{\labelwidth}{\DUoptionlistindent} \setlength{\rightmargin}{1cm} @@ -120,7 +127,7 @@ \renewcommand{\makelabel}{\DUoptionlistlabel}} } {\endlist} -}{} +\fi % informal heading \providecommand*{\DUrubric}[1]{\subsubsection*{\emph{#1}}} @@ -133,11 +140,12 @@ \providecommand*{\DUroletitlereference}[1]{\textsl{#1}} % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi \hypersetup{ pdftitle={Styling of Elements in Definition- or Field-List}, pdfauthor={Hänsel;Gretel} Modified: trunk/docutils/test/functional/expected/latex_literal_block.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_literal_block.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,7 +1,6 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} \usepackage{alltt} \usepackage{amsmath} @@ -27,11 +26,12 @@ \settowidth{\ttemwidth}{\ttfamily M} % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi %%% Body \begin{document} Modified: trunk/docutils/test/functional/expected/latex_literal_block_fancyvrb.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block_fancyvrb.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_literal_block_fancyvrb.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,7 +1,6 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} \usepackage{amsmath} \usepackage{color} @@ -27,11 +26,12 @@ \settowidth{\ttemwidth}{\ttfamily M} % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi %%% Body \begin{document} Modified: trunk/docutils/test/functional/expected/latex_literal_block_listings.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block_listings.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_literal_block_listings.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,7 +1,6 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} \usepackage{amsmath} \usepackage{color} @@ -33,11 +32,12 @@ \settowidth{\ttemwidth}{\ttfamily M} % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi %%% Body \begin{document} Modified: trunk/docutils/test/functional/expected/latex_literal_block_verbatim.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block_verbatim.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_literal_block_verbatim.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,7 +1,6 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} \usepackage{amsmath} \usepackage{color} @@ -26,11 +25,12 @@ \settowidth{\ttemwidth}{\ttfamily M} % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi %%% Body \begin{document} Modified: trunk/docutils/test/functional/expected/latex_literal_block_verbatimtab.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block_verbatimtab.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_literal_block_verbatimtab.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,7 +1,6 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} \usepackage{amsmath} \usepackage{color} @@ -27,11 +26,12 @@ \settowidth{\ttemwidth}{\ttfamily M} % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi %%% Body \begin{document} Modified: trunk/docutils/test/functional/expected/latex_memoir.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_memoir.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/latex_memoir.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,11 +1,10 @@ % generated by Docutils <https://docutils.sourceforge.io/> \documentclass[a4paper]{memoir} -\usepackage{ifthen} \usepackage[T1]{fontenc} \usepackage{alltt} \usepackage{amsmath} -\usepackage[british,french,ngerman,english]{babel} +\usepackage[british,french,ngerman,main=english]{babel} % Prevent side-effects if French hyphenation patterns are not loaded: \frenchbsetup{StandardLayout} \AtBeginDocument{\selectlanguage{english}\noextrasfrench} @@ -34,17 +33,21 @@ % class handling for environments (block-level elements) % \begin{DUclass}{spam} tries \DUCLASSspam and % \end{DUclass}{spam} tries \endDUCLASSspam -\ifx\DUclass\undefined % poor man's "provideenvironment" - \newenvironment{DUclass}[1]% - {% "#1" does not work in end-part of environment. - \def\DocutilsClassFunctionName{DUCLASS#1} +\ifdefined\DUclass +\else % poor man's "provideenvironment" + \newenvironment{DUclass}[1]% + {% "#1" does not work in end-part of environment. + \def\DocutilsClassFunctionName{DUCLASS#1} \csname \DocutilsClassFunctionName \endcsname}% - {\csname end\DocutilsClassFunctionName \endcsname}% + {\csname end\DocutilsClassFunctionName \endcsname}% \fi % Provide a length variable and set default, if it is new -\providecommand*{\DUprovidelength}[2]{ - \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{} +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1 + \else + \newlength{#1}\setlength{#1}{#2}% + \fi } % abstract title @@ -78,11 +81,12 @@ \providecommand*{\DUtitleerror}[1]{\DUtitle{\color{red}#1}} % field list environment (for separate configuration of `field lists`) -\ifthenelse{\isundefined{\DUfieldlist}}{ +\ifdefined\DUfieldlist +\else \newenvironment{DUfieldlist}% {\quote\description} {\enddescription\endquote} -}{} +\fi % numerical or symbol footnotes with hyperlinks and backlinks \providecommand*{\DUfootnotemark}[3]{% @@ -108,13 +112,15 @@ } % legend environment (in figures and formal tables) -\ifthenelse{\isundefined{\DUlegend}}{ +\ifdefined\DUlegend +\else \newenvironment{DUlegend}{\small}{} -}{} +\fi % line block environment \DUprovidelength{\DUlineblockindent}{2.5em} -\ifthenelse{\isundefined{\DUlineblock}}{ +\ifdefined\DUlineblock +\else \newenvironment{DUlineblock}[1]{% \list{}{\setlength{\partopsep}{\parskip} \addtolength{\partopsep}{\baselineskip} @@ -125,12 +131,13 @@ \raggedright } {\endlist} -}{} +\fi % list of command line options \providecommand*{\DUoptionlistlabel}[1]{\bfseries #1 \hfill} \DUprovidelength{\DUoptionlistindent}{3cm} -\ifthenelse{\isundefined{\DUoptionlist}}{ +\ifdefined\DUoptionlist +\else \newenvironment{DUoptionlist}{% \list{}{\setlength{\labelwidth}{\DUoptionlistindent} \setlength{\rightmargin}{1cm} @@ -140,7 +147,7 @@ \renewcommand{\makelabel}{\DUoptionlistlabel}} } {\endlist} -}{} +\fi % informal heading \providecommand*{\DUrubric}[1]{\subsubsection*{\emph{#1}}} @@ -174,11 +181,12 @@ \vskip 0.5\baselineskip } % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi \hypersetup{ pdftitle={reStructuredText Test Document}, pdfkeywords={reStructuredText, test, parser}, Modified: trunk/docutils/test/functional/expected/standalone_rst_latex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -1,11 +1,10 @@ \documentclass[a4paper]{article} % generated by Docutils <https://docutils.sourceforge.io/> \usepackage{cmap} % fix search and cut-and-paste in Acrobat -\usepackage{ifthen} \usepackage[T1]{fontenc} \usepackage{alltt} \usepackage{amsmath} -\usepackage[british,french,ngerman,english]{babel} +\usepackage[british,french,ngerman,main=english]{babel} % Prevent side-effects if French hyphenation patterns are not loaded: \frenchbsetup{StandardLayout} \AtBeginDocument{\selectlanguage{english}\noextrasfrench} @@ -34,17 +33,21 @@ % class handling for environments (block-level elements) % \begin{DUclass}{spam} tries \DUCLASSspam and % \end{DUclass}{spam} tries \endDUCLASSspam -\ifx\DUclass\undefined % poor man's "provideenvironment" - \newenvironment{DUclass}[1]% - {% "#1" does not work in end-part of environment. - \def\DocutilsClassFunctionName{DUCLASS#1} +\ifdefined\DUclass +\else % poor man's "provideenvironment" + \newenvironment{DUclass}[1]% + {% "#1" does not work in end-part of environment. + \def\DocutilsClassFunctionName{DUCLASS#1} \csname \DocutilsClassFunctionName \endcsname}% - {\csname end\DocutilsClassFunctionName \endcsname}% + {\csname end\DocutilsClassFunctionName \endcsname}% \fi % Provide a length variable and set default, if it is new -\providecommand*{\DUprovidelength}[2]{ - \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{} +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1 + \else + \newlength{#1}\setlength{#1}{#2}% + \fi } \providecommand*{\DUCLASSabstract}{ @@ -52,18 +55,19 @@ } % admonition environment (specially marked topic) -\ifx\DUadmonition\undefined % poor man's "provideenvironment" - \newbox{\DUadmonitionbox} - \newenvironment{DUadmonition}% - {\begin{center} - \begin{lrbox}{\DUadmonitionbox} - \begin{minipage}{0.9\linewidth} - }% - { \end{minipage} - \end{lrbox} - \fbox{\usebox{\DUadmonitionbox}} - \end{center} - } +\ifdefined\DUadmonition +\else % poor man's "provideenvironment" + \newbox{\DUadmonitionbox} + \newenvironment{DUadmonition}% + {\begin{center} + \begin{lrbox}{\DUadmonitionbox} + \begin{minipage}{0.9\linewidth} + }% + { \end{minipage} + \end{lrbox} + \fbox{\usebox{\DUadmonitionbox}} + \end{center} + } \fi % special topic for dedications @@ -81,11 +85,12 @@ \providecommand*{\DUCLASSerror}{\color{red}} % field list environment (for separate configuration of `field lists`) -\ifthenelse{\isundefined{\DUfieldlist}}{ +\ifdefined\DUfieldlist +\else \newenvironment{DUfieldlist}% {\quote\description} {\enddescription\endquote} -}{} +\fi % numerical or symbol footnotes with hyperlinks and backlinks \providecommand*{\DUfootnotemark}[3]{% @@ -111,13 +116,15 @@ } % legend environment (in figures and formal tables) -\ifthenelse{\isundefined{\DUlegend}}{ +\ifdefined\DUlegend +\else \newenvironment{DUlegend}{\small}{} -}{} +\fi % line block environment \DUprovidelength{\DUlineblockindent}{2.5em} -\ifthenelse{\isundefined{\DUlineblock}}{ +\ifdefined\DUlineblock +\else \newenvironment{DUlineblock}[1]{% \list{}{\setlength{\partopsep}{\parskip} \addtolength{\partopsep}{\baselineskip} @@ -128,12 +135,13 @@ \raggedright } {\endlist} -}{} +\fi % list of command line options \providecommand*{\DUoptionlistlabel}[1]{\bfseries #1 \hfill} \DUprovidelength{\DUoptionlistindent}{3cm} -\ifthenelse{\isundefined{\DUoptionlist}}{ +\ifdefined\DUoptionlist +\else \newenvironment{DUoptionlist}{% \list{}{\setlength{\labelwidth}{\DUoptionlistindent} \setlength{\rightmargin}{1cm} @@ -143,7 +151,7 @@ \renewcommand{\makelabel}{\DUoptionlistlabel}} } {\endlist} -}{} +\fi % informal heading \providecommand*{\DUrubric}[1]{\subsubsection*{\emph{#1}}} @@ -172,11 +180,12 @@ } % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi \hypersetup{ pdftitle={reStructuredText Test Document}, pdfkeywords={reStructuredText, test, parser}, Modified: trunk/docutils/test/functional/expected/standalone_rst_xetex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -8,7 +8,6 @@ \DeclareTextCommand{\textquotedbl}{\UnicodeEncodingName}{% {\addfontfeatures{RawFeature=-tlig,Mapping=}\char34}}% \fi -\usepackage{ifthen} \usepackage{alltt} \usepackage{amsmath} \usepackage{polyglossia} @@ -48,11 +47,12 @@ {\end{list}}% } % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi \hypersetup{ pdftitle={reStructuredText Test Document}, pdfkeywords={reStructuredText, test, parser}, Modified: trunk/docutils/test/functional/expected/xetex-cyrillic.tex =================================================================== --- trunk/docutils/test/functional/expected/xetex-cyrillic.tex 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/functional/expected/xetex-cyrillic.tex 2024-09-23 22:36:38 UTC (rev 9937) @@ -8,7 +8,6 @@ \DeclareTextCommand{\textquotedbl}{\UnicodeEncodingName}{% {\addfontfeatures{RawFeature=-tlig,Mapping=}\char34}}% \fi -\usepackage{ifthen} \usepackage{polyglossia} \setdefaultlanguage{russian} \setotherlanguages{english} @@ -24,11 +23,12 @@ %%% Fallback definitions for Docutils-specific commands % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi \hypersetup{ pdflang={ru}, } Modified: trunk/docutils/test/test_writers/test_latex2e.py =================================================================== --- trunk/docutils/test/test_writers/test_latex2e.py 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/test_writers/test_latex2e.py 2024-09-23 22:36:38 UTC (rev 9937) @@ -124,8 +124,7 @@ parts = { 'head_prefix': r"""\documentclass[a4paper]{article} """, -'requirements': r"""\usepackage{ifthen} -\usepackage[T1]{fontenc} +'requirements': r"""\usepackage[T1]{fontenc} """, 'latex_preamble': r"""% PDF Standard Fonts \usepackage{mathptmx} % Times @@ -156,11 +155,12 @@ """, 'pdfsetup': r""" % hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ +\ifdefined\hypersetup +\else \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} \usepackage{bookmark} \urlstyle{same} % normal text font (alternatives: tt, rm, sf) -}{} +\fi """, 'titledata': ''} @@ -227,9 +227,8 @@ samples_default['spanish_quote'] = [ [".. role:: language-es\n\nUnd damit :language-es:`basta`!", head_template.substitute(dict(parts, -requirements=r"""\usepackage{ifthen} -\usepackage[T1]{fontenc} -\usepackage[spanish,english]{babel} +requirements=r"""\usepackage[T1]{fontenc} +\usepackage[spanish,main=english]{babel} \AtBeginDocument{\shorthandoff{.<>}} """)) + r""" Und damit \foreignlanguage{spanish}{basta}! @@ -269,12 +268,13 @@ % class handling for environments (block-level elements) % \begin{DUclass}{spam} tries \DUCLASSspam and % \end{DUclass}{spam} tries \endDUCLASSspam -\ifx\DUclass\undefined % poor man's "provideenvironment" - \newenvironment{DUclass}[1]% - {% "#1" does not work in end-part of environment. - \def\DocutilsClassFunctionName{DUCLASS#1} +\ifdefined\DUclass +\else % poor man's "provideenvironment" + \newenvironment{DUclass}[1]% + {% "#1" does not work in end-part of environment. + \def\DocutilsClassFunctionName{DUCLASS#1} \csname \DocutilsClassFunctionName \endcsname}% - {\csname end\DocutilsClassFunctionName \endcsname}% + {\csname end\DocutilsClassFunctionName \endcsname}% \fi % title for topics, admonitions, unsupported section levels, and sidebar @@ -989,12 +989,13 @@ % class handling for environments (block-level elements) % \begin{DUclass}{spam} tries \DUCLASSspam and % \end{DUclass}{spam} tries \endDUCLASSspam -\ifx\DUclass\undefined % poor man's "provideenvironment" - \newenvironment{DUclass}[1]% - {% "#1" does not work in end-part of environment. - \def\DocutilsClassFunctionName{DUCLASS#1} +\ifdefined\DUclass +\else % poor man's "provideenvironment" + \newenvironment{DUclass}[1]% + {% "#1" does not work in end-part of environment. + \def\DocutilsClassFunctionName{DUCLASS#1} \csname \DocutilsClassFunctionName \endcsname}% - {\csname end\DocutilsClassFunctionName \endcsname}% + {\csname end\DocutilsClassFunctionName \endcsname}% \fi """ ) @@ -1101,12 +1102,13 @@ % class handling for environments (block-level elements) % \begin{DUclass}{spam} tries \DUCLASSspam and % \end{DUclass}{spam} tries \endDUCLASSspam -\ifx\DUclass\undefined % poor man's "provideenvironment" - \newenvironment{DUclass}[1]% - {% "#1" does not work in end-part of environment. - \def\DocutilsClassFunctionName{DUCLASS#1} +\ifdefined\DUclass +\else % poor man's "provideenvironment" + \newenvironment{DUclass}[1]% + {% "#1" does not work in end-part of environment. + \def\DocutilsClassFunctionName{DUCLASS#1} \csname \DocutilsClassFunctionName \endcsname}% - {\csname end\DocutilsClassFunctionName \endcsname}% + {\csname end\DocutilsClassFunctionName \endcsname}% \fi """) ) + r""" Modified: trunk/docutils/test/test_writers/test_xetex_misc.py =================================================================== --- trunk/docutils/test/test_writers/test_xetex_misc.py 2024-09-20 08:32:41 UTC (rev 9936) +++ trunk/docutils/test/test_writers/test_xetex_misc.py 2024-09-23 22:36:38 UTC (rev 9937) @@ -45,8 +45,11 @@ px_fallback = r""" % Provide a length variable and set default, if it is new -\providecommand*{\DUprovidelength}[2]{ - \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{} +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1 + \else + \newlength{#1}\setlength{#1}{#2}% + \fi } \DUprovidelength{\pdfpxdimen}{1bp} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-28 21:23:34
|
Revision: 9941 http://sourceforge.net/p/docutils/code/9941 Author: milde Date: 2024-09-28 21:23:32 +0000 (Sat, 28 Sep 2024) Log Message: ----------- Minor documentation fixes. Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/RELEASE-NOTES.rst trunk/docutils/docs/ref/rst/restructuredtext.rst Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-26 14:09:49 UTC (rev 9940) +++ trunk/docutils/HISTORY.rst 2024-09-28 21:23:32 UTC (rev 9941) @@ -22,8 +22,8 @@ - We have started to add type hints to Docutils. This will be a complex programme of work, and as such for the time being these type hints are 'provisional', - and should not be relied upon by consumers of Docutils. - (feature-request #87) + and should not be relied upon by consumers of Docutils + (feature-request #87). - Add tox.ini to pyproject.toml to be in sdist (bug #486). - Fix license issue (bug #487). @@ -61,7 +61,7 @@ Provisional. - New "attribute validating functions" convert string representations to correct data type, - normalize values, + normalize values, and raise ValueError for invalid attribute names or values. - New function `parse_measure()`. - Removed `Element.set_class()`. @@ -70,14 +70,15 @@ - New parser for Docutils XML sources. Provisional. +* docutils/parsers/recommonmark_wrapper.py + + - New method `Parser.finish_parse()` to clean up (before validating). + * docutils/parsers/rst/languages/ - Removed mistranslations of the "admonition" directive name. -* docutils/parsers/recommonmark_wrapper.py - - New method `Parser.finish_parse()` to clean up (before validating). - * docutils/parsers/rst/directives/misc.py - Pass the included file's path to the parser when the Modified: trunk/docutils/RELEASE-NOTES.rst =================================================================== --- trunk/docutils/RELEASE-NOTES.rst 2024-09-26 14:09:49 UTC (rev 9940) +++ trunk/docutils/RELEASE-NOTES.rst 2024-09-28 21:23:32 UTC (rev 9941) @@ -107,11 +107,11 @@ __ docs/user/latex.html#length-units -Misc ----- +Removals +-------- * Remove `io.BinaryFileOutput` and `core.publish_cmdline_to_binary()` - in Docutils 0.24. + in Docutils 0.24. * Remove `parsers.rst.directives.CSVTable.HeaderDialect` in Docutils 1.0. @@ -131,7 +131,7 @@ * Remove the "rawsource" argument from `nodes.Text.__init__()` in Docutils 2.0. -* Remove the deprecated attributes `nodes.Element.known_attributes`, +* Remove attributes `nodes.Element.known_attributes`, `nodes.Element.basic_attributes`, and `nodes.Element.local_attributes`, in Docutils 2.0. @@ -146,6 +146,9 @@ functions in Docutils 2.0. Since Docutils 0.22, you may use "reader", "parser", and "writer" arguments for component names as well as instances. +Misc +---- + * Revise the `String I/O`__ interface used by the `publish_string()` and `publish_from_doctree()` publisher convenience functions. (In Python 3, name and behaviour no longer match.) Modified: trunk/docutils/docs/ref/rst/restructuredtext.rst =================================================================== --- trunk/docutils/docs/ref/rst/restructuredtext.rst 2024-09-26 14:09:49 UTC (rev 9940) +++ trunk/docutils/docs/ref/rst/restructuredtext.rst 2024-09-28 21:23:32 UTC (rev 9941) @@ -3083,6 +3083,11 @@ manuals (`directive option`_ values of type "length__" or "percentage__"). In the `document tree`_, they are stored in attributes of type `measure`_. +It is up to the processing system to provide a fallback/workaround +or raise an error if the output format does not support a unit +(or values without unit). +For the behaviour of the Docutils writers, see the `writer documentation`_. + .. _directive option: `directive options`_ __ directives.html#length __ directives.html#percentage @@ -3103,20 +3108,14 @@ ---- --------------------------------------------------------- cm centimeters 1 cm = 10 mm mm millimeters 1 mm = 1/1000 m -in inches 1 in = 2.54 cm = 96 px +in inches 1 in = 25.4 mm = 96 px pc picas 1 pc = 1/6 in = 12 pt pt points 1 pt = 1/72 in px pixels 1 px = 3/4 pt = 1/96 in [#]_ ==== ======================= ================================ -The following are all valid length values: -"1.5em", "20 mm", ".5 in", "42". +The following are all valid length values: "1.5em", "20 mm", ".5 in", "42". -It is up to the processing system to provide a fallback/workaround or -raise an error if the output format does not support a unit or -values without unit. For the behaviour of the Docutils writers, -see the `writer documentation`_. - .. [#] a subset of `length units in CSS3`_ .. [#] In LaTeX, the default definition is 1 px = 1 pt = 1/72 in (cf. section `Length units <../../user/latex.html#length-units>`__ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-29 09:31:19
|
Revision: 9942 http://sourceforge.net/p/docutils/code/9942 Author: milde Date: 2024-09-29 09:31:17 +0000 (Sun, 29 Sep 2024) Log Message: ----------- LaTeX writers update. Deprecate `writers.latex2e.SortableDict`. Remove `writers.latex2e.Table.get_caption` (obsolete). Test and fix local ToC without global ToC. Package "minitoc" needs a ``\faketableofcontents`` in this case so that a ".toc" file is generated. Move the conditional insertion code in `depart_document()` before the conversion of `self.requirements` from a dict to a list, so that the test works again as intended. Modified Paths: -------------- trunk/docutils/RELEASE-NOTES.rst trunk/docutils/docutils/writers/latex2e/__init__.py trunk/docutils/docutils/writers/latex2e/xelatex.tex trunk/docutils/test/functional/expected/standalone_rst_xetex.tex trunk/docutils/test/functional/expected/xetex-cyrillic.tex trunk/docutils/test/test_writers/test_latex2e.py trunk/docutils/test/test_writers/test_latex2e_misc.py Modified: trunk/docutils/RELEASE-NOTES.rst =================================================================== --- trunk/docutils/RELEASE-NOTES.rst 2024-09-28 21:23:32 UTC (rev 9941) +++ trunk/docutils/RELEASE-NOTES.rst 2024-09-29 09:31:17 UTC (rev 9942) @@ -113,6 +113,8 @@ * Remove `io.BinaryFileOutput` and `core.publish_cmdline_to_binary()` in Docutils 0.24. +* Remove `writers.latex2e.SortableDict` in Docutils 0.24. + * Remove `parsers.rst.directives.CSVTable.HeaderDialect` in Docutils 1.0. @@ -365,6 +367,8 @@ Python 2 compatibility hacks `docutils.utils.Reporter.set_conditions()` obsolete + `writers.latex2e.Table.get_caption` + obsolete * New files: Modified: trunk/docutils/docutils/writers/latex2e/__init__.py =================================================================== --- trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-28 21:23:32 UTC (rev 9941) +++ trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-29 09:31:17 UTC (rev 9942) @@ -490,9 +490,15 @@ class SortableDict(dict): """Dictionary with additional sorting methods - Tip: use key starting with with '_' for sorting before small letters - and with '~' for sorting after small letters. + Deprecated. Will be removed in Docutils 0.24. """ + + def __init__(self, *args, **kwargs): + warnings.warn('`writers.latex2e.SortableDict` is obsolete' + ' and will be removed in Docutils 0.24.', + DeprecationWarning, stacklevel=2) + super().__init__(*args, **kwargs) + def sortedkeys(self): """Return sorted list of keys""" return sorted(self.keys()) @@ -1025,19 +1031,6 @@ except IndexError: return 'l' - def get_caption(self) -> str: - """Deprecated. Will be removed in Docutils 0.22.""" - warnings.warn('`writers.latex2e.Table.get_caption()` is obsolete' - ' and will be removed in Docutils 0.22.', - DeprecationWarning, stacklevel=2) - - if not self.caption: - return '' - caption = ''.join(self.caption) - if 1 == self._translator.thead_depth(): - return r'\caption{%s}\\' '\n' % caption - return r'\caption[]{%s (... continued)}\\' '\n' % caption - def need_recurse(self): if self._latex_type == 'longtable': return 1 == self._translator.thead_depth() @@ -1257,9 +1250,9 @@ self.head_prefix = [r'\documentclass[%s]{%s}' % (self.documentoptions, settings.documentclass)] - self.requirements = SortableDict() # made a list in depart_document() + self.requirements = {} # converted to a list in depart_document() self.latex_preamble = [settings.latex_preamble] - self.fallbacks = SortableDict() # made a list in depart_document() + self.fallbacks = {} # converted to a list in depart_document() self.pdfsetup = [] # PDF properties (hyperref package) self.title = [] self.subtitle = [] @@ -2023,10 +2016,6 @@ if (self.babel.otherlanguages or self.babel.language not in ('', 'english')): self.requirements['babel'] = self.babel() - # * conditional requirements (before style sheet) - self.requirements = self.requirements.sortedvalues() - # * coditional fallback definitions (after style sheet) - self.fallbacks = self.fallbacks.sortedvalues() # * PDF properties self.pdfsetup.append(PreambleCmds.linking % self.hyperref_options) if self.pdfauthor: @@ -2044,6 +2033,12 @@ # * make sure to generate a toc file if needed for local contents: if 'minitoc' in self.requirements and not self.has_latex_toc: self.out.append('\n\\faketableofcontents % for local ToCs\n') + # * conditional requirements (before style sheet) + self.requirements = [self.requirements[key] + for key in sorted(self.requirements.keys())] + # * coditional fallback definitions (after style sheet) + self.fallbacks = [self.fallbacks[key] + for key in sorted(self.fallbacks.keys())] def make_title(self) -> None: # Auxiliary function called by `self.depart_document()`. Modified: trunk/docutils/docutils/writers/latex2e/xelatex.tex =================================================================== --- trunk/docutils/docutils/writers/latex2e/xelatex.tex 2024-09-28 21:23:32 UTC (rev 9941) +++ trunk/docutils/docutils/writers/latex2e/xelatex.tex 2024-09-29 09:31:17 UTC (rev 9942) @@ -2,7 +2,7 @@ % rubber: set program xelatex \usepackage{fontspec} % \defaultfontfeatures{Scale=MatchLowercase} -% straight double quotes (defined T1 but missing in TU): +% straight double quotes (defined in T1 but missing in TU): \ifdefined \UnicodeEncodingName \DeclareTextCommand{\textquotedbl}{\UnicodeEncodingName}{% {\addfontfeatures{RawFeature=-tlig,Mapping=}\char34}}% Modified: trunk/docutils/test/functional/expected/standalone_rst_xetex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-28 21:23:32 UTC (rev 9941) +++ trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-29 09:31:17 UTC (rev 9942) @@ -3,7 +3,7 @@ % rubber: set program xelatex \usepackage{fontspec} % \defaultfontfeatures{Scale=MatchLowercase} -% straight double quotes (defined T1 but missing in TU): +% straight double quotes (defined in T1 but missing in TU): \ifdefined \UnicodeEncodingName \DeclareTextCommand{\textquotedbl}{\UnicodeEncodingName}{% {\addfontfeatures{RawFeature=-tlig,Mapping=}\char34}}% Modified: trunk/docutils/test/functional/expected/xetex-cyrillic.tex =================================================================== --- trunk/docutils/test/functional/expected/xetex-cyrillic.tex 2024-09-28 21:23:32 UTC (rev 9941) +++ trunk/docutils/test/functional/expected/xetex-cyrillic.tex 2024-09-29 09:31:17 UTC (rev 9942) @@ -3,7 +3,7 @@ % rubber: set program xelatex \usepackage{fontspec} % \defaultfontfeatures{Scale=MatchLowercase} -% straight double quotes (defined T1 but missing in TU): +% straight double quotes (defined in T1 but missing in TU): \ifdefined \UnicodeEncodingName \DeclareTextCommand{\textquotedbl}{\UnicodeEncodingName}{% {\addfontfeatures{RawFeature=-tlig,Mapping=}\char34}}% Modified: trunk/docutils/test/test_writers/test_latex2e.py =================================================================== --- trunk/docutils/test/test_writers/test_latex2e.py 2024-09-28 21:23:32 UTC (rev 9941) +++ trunk/docutils/test/test_writers/test_latex2e.py 2024-09-29 09:31:17 UTC (rev 9942) @@ -177,6 +177,14 @@ dict(parts, requirements=parts['requirements'] + '\\usepackage{graphicx}\n')) +head_minitoc = head_template.substitute( + dict(parts, requirements=parts['requirements'] + + '%% local table of contents\n' + '\\usepackage{minitoc}\n' + '\\dosecttoc\n' + '\\mtcsetdepth{secttoc}{5}\n' + '\\setcounter{secnumdepth}{0}\n')) + head_textcomp = head_template.substitute( dict(parts, requirements=parts['requirements'] + '\\usepackage{textcomp} % text symbol macros\n')) @@ -249,6 +257,40 @@ """], ] +samples_default['minitoc'] = [ +# local toc reqires the minitoc package +# and either \tableofcontents or \faketableofcontents +["""\ +section with local ToC +====================== + +.. contents:: + :local: + +section not in local toc +======================== +""", +head_minitoc + r""" + +\section{section with local ToC% + \label{section-with-local-toc}% +} + +\phantomsection\label{contents} +\mtcsettitle{secttoc}{} +\secttoc + + +\section{section not in local toc% + \label{section-not-in-local-toc}% +} + +\faketableofcontents % for local ToCs + +\end{document} +"""], +] + samples_docutils_toc['table_of_contents'] = [ ["""\ .. contents:: Table of Contents Modified: trunk/docutils/test/test_writers/test_latex2e_misc.py =================================================================== --- trunk/docutils/test/test_writers/test_latex2e_misc.py 2024-09-28 21:23:32 UTC (rev 9941) +++ trunk/docutils/test/test_writers/test_latex2e_misc.py 2024-09-29 09:31:17 UTC (rev 9942) @@ -143,6 +143,10 @@ core.publish_string('warnings test', writer=latex2e.Writer(), settings_overrides=settings) + def test_deprecation_warnings(self): + with self.assertWarnsRegex(DeprecationWarning, 'will be removed'): + latex2e.SortableDict(deprecated=True) + if __name__ == '__main__': unittest.main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-09-29 09:31:44
|
Revision: 9943 http://sourceforge.net/p/docutils/code/9943 Author: milde Date: 2024-09-29 09:31:39 +0000 (Sun, 29 Sep 2024) Log Message: ----------- Support CSS3 `length units`_. Add "ch", "rem", "vw", "vh", "vmin", "vmax", and "Q" to the length units supported by reStructuredText. Note that some output formats don't support all units. HTML: CSS3 units are supported by all contemporary browsers. XML, pseudoxml: Docutils Document Tree elements validate "any run of letters or a percent sign" as a measure's unit. LaTeX: the writer emulates non-native units with custom length macros. ODT: the writer only supports fixed length units (by converting to "cm"). Support for the unit "Q" is added. man: the writer ignores length specifications. Fixes feature-request #57. Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/RELEASE-NOTES.rst trunk/docutils/docs/ref/doctree.rst trunk/docutils/docs/ref/rst/restructuredtext.rst trunk/docutils/docutils/parsers/rst/directives/__init__.py trunk/docutils/docutils/writers/latex2e/__init__.py trunk/docutils/docutils/writers/latex2e/docutils.sty trunk/docutils/docutils/writers/odf_odt/__init__.py trunk/docutils/docutils/writers/xetex/__init__.py trunk/docutils/test/functional/expected/latex_literal_block.tex trunk/docutils/test/functional/expected/latex_literal_block_fancyvrb.tex trunk/docutils/test/functional/expected/latex_literal_block_listings.tex trunk/docutils/test/functional/expected/latex_literal_block_verbatim.tex trunk/docutils/test/functional/expected/latex_literal_block_verbatimtab.tex trunk/docutils/test/functional/expected/standalone_rst_xetex.tex trunk/docutils/test/test_parsers/test_rst/test_directives/test_images.py trunk/docutils/test/test_writers/test_xetex_misc.py Added Paths: ----------- trunk/docutils/test/functional/expected/length_units_html5.html trunk/docutils/test/functional/expected/length_units_latex.tex trunk/docutils/test/functional/expected/length_units_xetex.tex trunk/docutils/test/functional/input/length_units.rst trunk/docutils/test/functional/tests/length_units_html5.py trunk/docutils/test/functional/tests/length_units_latex.py trunk/docutils/test/functional/tests/length_units_xetex.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/HISTORY.rst 2024-09-29 09:31:39 UTC (rev 9943) @@ -78,7 +78,10 @@ - Removed mistranslations of the "admonition" directive name. +* docutils/parsers/rst/directives/__init__.py + - Support CSS3 `length units`_. Fixes feature-request #57. + * docutils/parsers/rst/directives/misc.py - Pass the included file's path to the parser when the @@ -161,10 +164,9 @@ remove optional argument `pxunit` (ignored since at least 2012), drop trailing zeroes from length values, move XeTeX-specific code to the "xetex" writer. + Handle CSS3 `length units`_. - Don't wrap references with custom reference-label_ in a ``\hyperref`` command. - - Stop requiring "ifthen.sty". Replace use of ``\ifthenelse{\isundefined...`` - with the eTeX primitive ``\ifdefined``. - Mark the main language when loading "babel". - Provide an "unknown_references_resolver" (cf. `docutils/TransformSpec`) for citation references resolved with BibTeX (cf. `use_bibtex`_ setting). @@ -171,6 +173,12 @@ .. _reference-label: docs/user/config.html#reference-label +* docutils/writers/latex2e/docutils.sty + + - Replace use of ``\ifthenelse{\isundefined...`` (from "ifthen.sty") + with the eTeX primitive ``\ifdefined``. + - Add macros to emulate CSS3 `length units`_ unknown to LaTeX. + * docutils/writers/manpage.py - Remove code for unused emdash bullets. @@ -200,7 +208,9 @@ - Removed. Use `docutils.writers.odf_odt.prepstyles`. +.. _length units: docs/ref/rst/restructuredtext.html#length-units + Release 0.21.2 (2024-04-23) =========================== Modified: trunk/docutils/RELEASE-NOTES.rst =================================================================== --- trunk/docutils/RELEASE-NOTES.rst 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/RELEASE-NOTES.rst 2024-09-29 09:31:39 UTC (rev 9943) @@ -115,6 +115,10 @@ * Remove `writers.latex2e.SortableDict` in Docutils 0.24. +* Remove `parsers.rst.directives.length_units` in Docutils 0.24. + Use `parsers.rst.directives.CSS3_LENGTH_UNITS`. Mind that this + is a tuple, not a list. + * Remove `parsers.rst.directives.CSVTable.HeaderDialect` in Docutils 1.0. @@ -182,6 +186,14 @@ Release 0.22b.dev (unpublished) =============================== +reStructuredText: + Support `CSS3 units`_. This adds "ch", "rem", "vw", "vh", "vmin", + "vmax", and "Q" to the `supported length units`__. + Note that some output formats don't support all units. + + .. _CSS3 units: https://www.w3.org/TR/css-values-3/#lengths + __ docs/ref/rst/restructuredtext.html#length-units + Document Tree / Docutils DTD - Allow multiple <term> elements in a `\<definition_list_item>`__ (third-party writers may need adaption). Modified: trunk/docutils/docs/ref/doctree.rst =================================================================== --- trunk/docutils/docs/ref/doctree.rst 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/docs/ref/doctree.rst 2024-09-29 09:31:39 UTC (rev 9943) @@ -4001,7 +4001,7 @@ _`%measure` | A number which may be immediately followed by a unit or percent sign. - ReStructuredText supports `CSS2 length units`_. + ReStructuredText supports `CSS3 length units`_. Handling of values without unit depends on the writer/output format (see the writer specific documentation in the `user documentation`__ for details). Resolves to CDATA_. @@ -5317,7 +5317,7 @@ .. _bibliographic fields: rst/restructuredtext.html#bibliographic-fields .. _block quote: rst/restructuredtext.html#block-quotes .. _bullet list: rst/restructuredtext.html#bullet-lists -.. _CSS2 length units: rst/restructuredtext.html#length-units +.. _CSS3 length units: rst/restructuredtext.html#length-units .. _citations: rst/restructuredtext.html#citations .. _definition list: rst/restructuredtext.html#definition-lists .. _directive: rst/restructuredtext.html#directives Modified: trunk/docutils/docs/ref/rst/restructuredtext.rst =================================================================== --- trunk/docutils/docs/ref/rst/restructuredtext.rst 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/docs/ref/rst/restructuredtext.rst 2024-09-29 09:31:39 UTC (rev 9943) @@ -3096,27 +3096,42 @@ Length Units ------------ -The reStructuredText parser supports the `length units in CSS2`_. [#]_ +The reStructuredText parser supports the `length units in CSS3`_. [#]_ Unit identifiers are case-sensitive (in contrast to CSS): .. class:: align-center -==== ======================= ================================ +==== ======================= ================================== em the element's font size ----- --------------------------------------------------------- +---- ----------------------------------------------------------- ex x-height of the element's font ----- --------------------------------------------------------- +---- ----------------------------------------------------------- +ch width of the “0” (ZERO, U+0030) glyph in the element’s font +---- ----------------------------------------------------------- +rem font size of the root element +---- ----------------------------------------------------------- +vw 1% of the viewport (or paper) width +---- ----------------------------------------------------------- +vh 1% of the viewport (or paper) height +---- ----------------------------------------------------------- +vmin 1% of the viewport’s smaller dimension +---- ----------------------------------------------------------- +vmax 1% of the viewport’s larger dimension +---- ----------------------------------------------------------- cm centimeters 1 cm = 10 mm mm millimeters 1 mm = 1/1000 m +Q quarter-millimeters 1 Q = 1/4 mm [#]_ in inches 1 in = 25.4 mm = 96 px pc picas 1 pc = 1/6 in = 12 pt pt points 1 pt = 1/72 in px pixels 1 px = 3/4 pt = 1/96 in [#]_ -==== ======================= ================================ +==== ======================= ================================== The following are all valid length values: "1.5em", "20 mm", ".5 in", "42". -.. [#] a subset of `length units in CSS3`_ +.. [#] Up to Docutils 0.21, support was restricted to the + `length units in CSS2`_. +.. [#] The unit "Q" is common in Japanese typesetting. .. [#] In LaTeX, the default definition is 1 px = 1 pt = 1/72 in (cf. section `Length units <../../user/latex.html#length-units>`__ in the LaTeX writer documentation). @@ -3123,8 +3138,7 @@ .. _length units in CSS2: https://www.w3.org/TR/CSS2/syndata.html#length-units -.. _length units in CSS3: - https://www.w3.org/TR/css-values-3/#lengths +.. _length units in CSS3: https://www.w3.org/TR/css-values-3/#lengths .. _XSL units: https://www.w3.org/TR/xsl/#d0e5752 Modified: trunk/docutils/docutils/parsers/rst/directives/__init__.py =================================================================== --- trunk/docutils/docutils/parsers/rst/directives/__init__.py 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/docutils/parsers/rst/directives/__init__.py 2024-09-29 09:31:39 UTC (rev 9943) @@ -244,9 +244,19 @@ return nonnegative_int(argument) -length_units = ['em', 'ex', 'in', 'cm', 'mm', 'pt', 'pc', 'px'] +CSS3_LENGTH_UNITS = ('em', 'ex', 'ch', 'rem', 'vw', 'vh', 'vmin', 'vmax', + 'cm', 'mm', 'Q', 'in', 'pt', 'pc', 'px') +"""Length units that are supported by the reStructuredText parser. +Corresponds to the `length units in CSS3`__. +__ https://www.w3.org/TR/css-values-3/#lengths +""" + +length_units = [*CSS3_LENGTH_UNITS] +"""Deprecated, will be removed in Docutils 0.24 or equivalent.""" + + def get_measure(argument, units): """ Check for a positive argument of one of the `units`. @@ -265,7 +275,7 @@ def length_or_unitless(argument: str) -> str: - return get_measure(argument, length_units + ['']) + return get_measure(argument, CSS3_LENGTH_UNITS + ('',)) def length_or_percentage_or_unitless(argument, default=''): @@ -286,7 +296,7 @@ '3px' """ try: - return get_measure(argument, length_units + ['%']) + return get_measure(argument, CSS3_LENGTH_UNITS + ('%',)) except ValueError as error: try: return get_measure(argument, ['']) + default Modified: trunk/docutils/docutils/writers/latex2e/__init__.py =================================================================== --- trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-29 09:31:39 UTC (rev 9943) @@ -523,6 +523,16 @@ # Requirements and Setup +# Not in docutils.sty because of the overhead for every font change: +PreambleCmds.ch = r""" +\ifdefined\DUchdimen % lengh unit "ch": width of a zero char +\else + \newlength{\DUchdimen} + \AtBeginDocument{\settowidth\DUchdimen{0}} % set after font setup, + % update with font changes (requires LaTeX > 2021-06-01, see lthooks-doc.pdf) + \AddToHook{cmd/selectfont/after}{\settowidth\DUchdimen{0}} +\fi""" + PreambleCmds.color = r"""\usepackage{color}""" PreambleCmds.float = r"""\usepackage{float} % extended float configuration @@ -1347,8 +1357,8 @@ self.fallback_stylesheet = False else: # require a minimal version: - self.fallbacks['docutils.sty'] = ( - r'\usepackage{docutils}[2020/08/28]') + self.fallbacks['_docutils.sty'] = ( + r'\usepackage{docutils}[2024-09-24]') self.stylesheet = [self.stylesheet_call(path) for path in stylesheet_list] @@ -2388,7 +2398,7 @@ self.requirements['~header'] = ''.join(self.out) self.pop_output_collector() - def to_latex_length(self, length_str: str) -> str: + def to_latex_length(self, length_str, node=None) -> str: """Convert "measure" `length_str` to LaTeX length specification. Note: the default length unit will change from "bp" @@ -2395,11 +2405,31 @@ (Postscript point) to "px" in Docutils 1.0. """ value, unit = nodes.parse_measure(length_str) + if unit in ('em', 'ex', 'cm', 'mm', 'in', 'pc', 'px', + 'bp', 'cc', 'dd', 'sp', 'mu'): # TeX unit == CSS unit + return length_str if unit in ('', 'pt'): # no unit or "Postscript points" return f'{value}bp' # LaTeX uses symbol "bp" + if unit == 'Q': + return f'{value/4}mm' if unit == '%': # percentage: relate to current line width return f'{value/100:g}\\linewidth' - return length_str + if unit == 'vw': # viewport width: relate to page width + return f'{value/100:g}\\paperwidth' + if unit == 'vh': # viewport height: relate to page height + return f'{value/100:g}\\paperheight' + # emulate with macro modelled on pdfLaTeX's \pdfpxdimen + if not hasattr(PreambleCmds, unit): + self.warn(f'Unit "{unit}" not supported by LaTeX.\n' + f' Define lenght "\\DU{unit}dimen" in preamble,' + ' raw LaTeX, or custom stylesheet.', + base_node=node) + elif unit == 'ch': + self.fallbacks['ch'] = PreambleCmds.ch + elif not self.fallback_stylesheet: + self.fallbacks['_providelength'] = PreambleCmds.providelength + self.fallbacks[unit] = getattr(PreambleCmds, unit) + return f'{value}\\DU{unit}dimen' def visit_image(self, node) -> None: self.requirements['graphicx'] = self.graphicx_package @@ -2436,13 +2466,12 @@ pass # TODO: warn? if 'height' in attrs: include_graphics_options.append( - 'height=%s' % self.to_latex_length(attrs['height'])) + f"height={self.to_latex_length(attrs['height'], node)}") if 'scale' in attrs: - include_graphics_options.append( - 'scale=%g' % (attrs['scale'] / 100.0)) + include_graphics_options.append(f"scale={attrs['scale']/100:g}") if 'width' in attrs: include_graphics_options.append( - 'width=%s' % self.to_latex_length(attrs['width'])) + f"width={self.to_latex_length(attrs['width'], node)}") if not (self.is_inline(node) or isinstance(node.parent, (nodes.figure, nodes.compound))): pre.append('\n') @@ -3006,7 +3035,7 @@ content = self.out self.pop_output_collector() try: - width = self.to_latex_length(node['width']) + width = self.to_latex_length(node['width'], node) except KeyError: width = r'\linewidth' # Insert hyperlabel and anchor before the table Modified: trunk/docutils/docutils/writers/latex2e/docutils.sty =================================================================== --- trunk/docutils/docutils/writers/latex2e/docutils.sty 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/docutils/writers/latex2e/docutils.sty 2024-09-29 09:31:39 UTC (rev 9943) @@ -22,7 +22,7 @@ \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{docutils} - [2024-09-23 macros for Docutils LaTeX output] + [2024-09-24 macros for Docutils LaTeX output] % Helpers % ------- @@ -236,8 +236,38 @@ \vskip 0.5\baselineskip } +% Length Units +% ------------ +% +% Emulating `CSS3 length units`_ unknown to LaTeX. +% +% rem:: +\DUprovidelength{\DUremdimen}{1em} + +% vmin:: + +\AtBeginDocument{ + \ifdim\paperwidth>\paperheight\relax + \DUprovidelength{\DUvmindimen}{0.01\paperheight} + \else + \DUprovidelength{\DUvmindimen}{0.01\paperwidth} + \fi +} + +% vmax:: + +\AtBeginDocument{ + \ifdim\paperwidth>\paperheight\relax + \DUprovidelength{\DUvmaxdimen}{0.01\paperwidth} + \else + \DUprovidelength{\DUvmaxdimen}{0.01\paperheight} + \fi +} + + % .. References: % % .. _Generating LaTeX with Docutils: % https://docutils.sourceforge.io/docs/user/latex.html +% .. _CSS3 length units: https://www.w3.org/TR/css-values-3/#lengths Modified: trunk/docutils/docutils/writers/odf_odt/__init__.py =================================================================== --- trunk/docutils/docutils/writers/odf_odt/__init__.py 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/docutils/writers/odf_odt/__init__.py 2024-09-29 09:31:39 UTC (rev 9943) @@ -2229,6 +2229,8 @@ size = float(size[:-2]) * 0.423 # convert pc to cm elif size.endswith('mm'): size = float(size[:-2]) * 0.1 # convert mm to cm + elif size.endswith('Q'): + size = float(size[:-1]) * 0.25 # convert Q to cm elif size.endswith('cm'): size = float(size[:-2]) elif size[-1:] in '0123456789.': # no unit, use px Modified: trunk/docutils/docutils/writers/xetex/__init__.py =================================================================== --- trunk/docutils/docutils/writers/xetex/__init__.py 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/docutils/writers/xetex/__init__.py 2024-09-29 09:31:39 UTC (rev 9943) @@ -147,7 +147,7 @@ self.requirements['_inputenc'] = (r'\XeTeXinputencoding %s ' % self.latex_encoding) - def to_latex_length(self, length_str: str) -> str: + def to_latex_length(self, length_str: str, node=None) -> str: """Convert "measure" `length_str` to LaTeX length specification. XeTeX does not know the length unit px. @@ -154,10 +154,10 @@ Use ``\\pdfpxdimen``, the macro holding the value of 1 px in pdfTeX. This way, configuring works the same for pdftex and xetex. """ - length_str = super().to_latex_length(length_str) + length_str = super().to_latex_length(length_str, node) if length_str.endswith('px'): if not self.fallback_stylesheet: self.fallbacks['_providelength'] = PreambleCmds.providelength - self.fallbacks['px'] = '\n\\DUprovidelength{\\pdfpxdimen}{1bp}\n' + self.fallbacks['px'] = '\n\\DUprovidelength{\\pdfpxdimen}{1bp}' return length_str.replace('px', '\\pdfpxdimen') return length_str Modified: trunk/docutils/test/functional/expected/latex_literal_block.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block.tex 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/test/functional/expected/latex_literal_block.tex 2024-09-29 09:31:39 UTC (rev 9943) @@ -19,7 +19,7 @@ %%% User specified packages and stylesheets %%% Fallback definitions for Docutils-specific commands -\usepackage{docutils}[2020/08/28] +\usepackage{docutils}[2024-09-24] % character width in monospaced font \newlength{\ttemwidth} Modified: trunk/docutils/test/functional/expected/latex_literal_block_fancyvrb.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block_fancyvrb.tex 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/test/functional/expected/latex_literal_block_fancyvrb.tex 2024-09-29 09:31:39 UTC (rev 9943) @@ -19,7 +19,7 @@ %%% User specified packages and stylesheets %%% Fallback definitions for Docutils-specific commands -\usepackage{docutils}[2020/08/28] +\usepackage{docutils}[2024-09-24] % character width in monospaced font \newlength{\ttemwidth} Modified: trunk/docutils/test/functional/expected/latex_literal_block_listings.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block_listings.tex 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/test/functional/expected/latex_literal_block_listings.tex 2024-09-29 09:31:39 UTC (rev 9943) @@ -25,7 +25,7 @@ %%% User specified packages and stylesheets %%% Fallback definitions for Docutils-specific commands -\usepackage{docutils}[2020/08/28] +\usepackage{docutils}[2024-09-24] % character width in monospaced font \newlength{\ttemwidth} Modified: trunk/docutils/test/functional/expected/latex_literal_block_verbatim.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block_verbatim.tex 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/test/functional/expected/latex_literal_block_verbatim.tex 2024-09-29 09:31:39 UTC (rev 9943) @@ -18,7 +18,7 @@ %%% User specified packages and stylesheets %%% Fallback definitions for Docutils-specific commands -\usepackage{docutils}[2020/08/28] +\usepackage{docutils}[2024-09-24] % character width in monospaced font \newlength{\ttemwidth} Modified: trunk/docutils/test/functional/expected/latex_literal_block_verbatimtab.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_literal_block_verbatimtab.tex 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/test/functional/expected/latex_literal_block_verbatimtab.tex 2024-09-29 09:31:39 UTC (rev 9943) @@ -19,7 +19,7 @@ %%% User specified packages and stylesheets %%% Fallback definitions for Docutils-specific commands -\usepackage{docutils}[2020/08/28] +\usepackage{docutils}[2024-09-24] % character width in monospaced font \newlength{\ttemwidth} Added: trunk/docutils/test/functional/expected/length_units_html5.html =================================================================== --- trunk/docutils/test/functional/expected/length_units_html5.html (rev 0) +++ trunk/docutils/test/functional/expected/length_units_html5.html 2024-09-29 09:31:39 UTC (rev 9943) @@ -0,0 +1,271 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta charset="utf-8" /> +<meta name="generator" content="Docutils 0.22b.dev: https://docutils.sourceforge.io/" /> +<meta name="viewport" content="width=device-width, initial-scale=1" /> +<title>Test length specifications</title> +<link rel="stylesheet" href="../input/data/minimal.css" type="text/css" /> +<link rel="stylesheet" href="../input/data/plain.css" type="text/css" /> +</head> +<body> +<main id="test-length-specifications"> +<h1 class="title">Test length specifications</h1> + +<section id="images-and-figures"> +<h2>Images and Figures</h2> +<figure> +<img alt="blue square" height="32" src="../input/data/blue%20square.png" width="32" /> +<figcaption> +<p>scale 100%, no size specification</p> +</figcaption> +</figure> +<figure style="width: 50%"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 25%;" /> +<figcaption> +<p>width 25%, no height, figure width 50%</p> +</figcaption> +</figure> +<figure style="width: 50%"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 25%; height: 16px;" /> +<figcaption> +<p>width 25%, height 16px, figure width 50%</p> +</figcaption> +</figure> +<figure style="width: 20em"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 10em; height: 16px;" /> +<figcaption> +<p>width 10 em, figure width 20 em</p> +</figcaption> +</figure> +<figure style="width: 40ex"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 20ex; height: 16px;" /> +<figcaption> +<p>width 20 ex, figure width 40 ex</p> +</figcaption> +</figure> +<figure style="width: 30ch"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 15ch; height: 16px;" /> +<figcaption> +<p>width 15 ch, figure width 30 ch</p> +</figcaption> +</figure> +<figure style="width: 20rem"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 10rem; height: 16px;" /> +<figcaption> +<p>width 10 rem, figure width 20 rem</p> +</figcaption> +</figure> +<figure style="width: 30vw"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 25vw; height: 16px;" /> +<figcaption> +<p>width 25 vw, figure width 30 vw</p> +</figcaption> +</figure> +<figure style="width: 30vh"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 25vh; height: 16px;" /> +<figcaption> +<p>width 25 vh, figure width 30 vh</p> +</figcaption> +</figure> +<figure style="width: 30vmin"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 25vmin; height: 16px;" /> +<figcaption> +<p>width 25 vmin, figure width 30 vmin</p> +</figcaption> +</figure> +<figure style="width: 30vmax"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 25vmax; height: 16px;" /> +<figcaption> +<p>width 25 vmax, figure width 30 vmax</p> +</figcaption> +</figure> +<figure style="width: 10cm"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 5cm; height: 16px;" /> +<figcaption> +<p>width 5 cm, figure width 10 cm</p> +</figcaption> +</figure> +<figure style="width: 100mm"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 50mm; height: 16px;" /> +<figcaption> +<p>width 50 mm, figure width 100 mm</p> +</figcaption> +</figure> +<figure style="width: 400Q"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 200Q; height: 16px;" /> +<figcaption> +<p>width 200 Q, figure width 400 Q</p> +</figcaption> +</figure> +<figure style="width: 4in"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 2in; height: 16px;" /> +<figcaption> +<p>width 2 in, figure width 4 in</p> +</figcaption> +</figure> +<figure style="width: 24pc"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 12pc; height: 16px;" /> +<figcaption> +<p>width 12 pc, figure width 24 pc</p> +</figcaption> +</figure> +<figure style="width: 288pt"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 144pt; height: 16px;" /> +<figcaption> +<p>width 144 pt, figure width 288pt</p> +</figcaption> +</figure> +<figure style="width: 384px"> +<img alt="blue square" src="../input/data/blue%20square.png" style="width: 192px; height: 16px;" /> +<figcaption> +<p>width 192 px, figure width 384 px</p> +</figcaption> +</figure> +<figure style="width: 384px"> +<img alt="blue square" src="../input/data/blue%20square.png" style="height: 16px;" width="192" /> +<figcaption> +<p>width 192 <no unit>, figure width 384 <no unit></p> +</figcaption> +</figure> +</section> +<section id="ch-em-and-rem-test1ch-test1em-test1rem"> +<h2>ch, em, and rem: <img alt="test1ch" src="../input/data/blue%20square.png" style="height: 1ch;" /> <img alt="test1em" src="../input/data/blue%20square.png" style="height: 1em;" /> <img alt="test1rem" src="../input/data/blue%20square.png" style="height: 1rem;" /></h2> +<p>Image height 1ch, 1em, and 1rem: <img alt="test1ch" src="../input/data/blue%20square.png" style="height: 1ch;" /> <img alt="test1em" src="../input/data/blue%20square.png" style="height: 1em;" /> <img alt="test1rem" src="../input/data/blue%20square.png" style="height: 1rem;" /></p> +<p>The units "em" and "ch" change with the current font size. +The unit "rem" is tied to the document root fontsize.</p> +</section> +<section id="tables"> +<h2>Tables</h2> +<table> +<tbody> +<tr><td><p>value</p></td> +<td><p>unit</p></td> +</tr> +</tbody> +</table> +<table style="width: 25%;"> +<tbody> +<tr><td><p>25</p></td> +<td><p>%</p></td> +</tr> +</tbody> +</table> +<table style="width: 10em;"> +<tbody> +<tr><td><p>10</p></td> +<td><p>em</p></td> +</tr> +</tbody> +</table> +<table style="width: 20ex;"> +<tbody> +<tr><td><p>20</p></td> +<td><p>ex</p></td> +</tr> +</tbody> +</table> +<table style="width: 15ch;"> +<tbody> +<tr><td><p>15</p></td> +<td><p>ch</p></td> +</tr> +</tbody> +</table> +<table style="width: 10rem;"> +<tbody> +<tr><td><p>10</p></td> +<td><p>rem</p></td> +</tr> +</tbody> +</table> +<table style="width: 25vw;"> +<tbody> +<tr><td><p>25</p></td> +<td><p>vw</p></td> +</tr> +</tbody> +</table> +<table style="width: 25vh;"> +<tbody> +<tr><td><p>25</p></td> +<td><p>vh</p></td> +</tr> +</tbody> +</table> +<table style="width: 25vmin;"> +<tbody> +<tr><td><p>25</p></td> +<td><p>vmin</p></td> +</tr> +</tbody> +</table> +<table style="width: 25vmax;"> +<tbody> +<tr><td><p>25</p></td> +<td><p>vmax</p></td> +</tr> +</tbody> +</table> +<table style="width: 5cm;"> +<tbody> +<tr><td><p>5</p></td> +<td><p>cm</p></td> +</tr> +</tbody> +</table> +<table style="width: 50mm;"> +<tbody> +<tr><td><p>50</p></td> +<td><p>mm</p></td> +</tr> +</tbody> +</table> +<table style="width: 200Q;"> +<tbody> +<tr><td><p>200</p></td> +<td><p>Q</p></td> +</tr> +</tbody> +</table> +<table style="width: 2in;"> +<tbody> +<tr><td><p>2</p></td> +<td><p>in</p></td> +</tr> +</tbody> +</table> +<table style="width: 12pc;"> +<tbody> +<tr><td><p>12</p></td> +<td><p>pc</p></td> +</tr> +</tbody> +</table> +<table style="width: 144pt;"> +<tbody> +<tr><td><p>144</p></td> +<td><p>pt</p></td> +</tr> +</tbody> +</table> +<table style="width: 192px;"> +<tbody> +<tr><td><p>192</p></td> +<td><p>px</p></td> +</tr> +</tbody> +</table> +<table style="width: 192px;"> +<tbody> +<tr><td><p>192</p></td> +<td><p><no unit></p></td> +</tr> +</tbody> +</table> +<style type="text/css"><!-- + figure {background: lightgreen;} + --></style></section> +</main> +</body> +</html> Property changes on: trunk/docutils/test/functional/expected/length_units_html5.html ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: trunk/docutils/test/functional/expected/length_units_latex.tex =================================================================== --- trunk/docutils/test/functional/expected/length_units_latex.tex (rev 0) +++ trunk/docutils/test/functional/expected/length_units_latex.tex 2024-09-29 09:31:39 UTC (rev 9943) @@ -0,0 +1,367 @@ +\documentclass[a4paper,landscape]{article} +% generated by Docutils <https://docutils.sourceforge.io/> +\usepackage{cmap} % fix search and cut-and-paste in Acrobat +\usepackage[T1]{fontenc} +\usepackage{float} % extended float configuration +\floatplacement{figure}{H} % place figures here definitely +\usepackage{graphicx} +\setcounter{secnumdepth}{0} +\usepackage{longtable,ltcaption,array} +\setlength{\extrarowheight}{2pt} +\newlength{\DUtablewidth} % internal use in tables +\newcommand{\DUcolumnwidth}[1]{\dimexpr#1\DUtablewidth-2\tabcolsep\relax} + +%%% Custom LaTeX preamble +% PDF Standard Fonts +\usepackage{mathptmx} % Times +\usepackage[scaled=.90]{helvet} +\usepackage{courier} + +%%% User specified packages and stylesheets +\usepackage{geometry} +\usepackage{nohyperref} + +%%% Fallback definitions for Docutils-specific commands +\usepackage{docutils}[2024-09-24] + +\ifdefined\DUchdimen % lengh unit "ch": width of a zero char +\else + \newlength{\DUchdimen} + \AtBeginDocument{\settowidth\DUchdimen{0}} % set after font setup, + % update with font changes (requires LaTeX > 2021-06-01, see lthooks-doc.pdf) + \AddToHook{cmd/selectfont/after}{\settowidth\DUchdimen{0}} +\fi + +% hyperlinks: +\ifdefined\hypersetup +\else + \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} + \usepackage{bookmark} + \urlstyle{same} % normal text font (alternatives: tt, rm, sf) +\fi +\hypersetup{ + pdftitle={Test length specifications}, +} + +%%% Body +\begin{document} +\title{Test length specifications% + \label{test-length-specifications}} +\author{} +\date{} +\maketitle + + +\section{Images and Figures% + \label{images-and-figures}% +} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[scale=1]{../input/data/blue square.png}} +\caption{scale 100\%, no size specification} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[width=0.25\linewidth]{../input/data/blue square.png}} +\caption{width 25\%, no height, figure width 50\%} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=0.25\linewidth]{../input/data/blue square.png}} +\caption{width 25\%, height 16px, figure width 50\%} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=10em]{../input/data/blue square.png}} +\caption{width 10 em, figure width 20 em} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=20ex]{../input/data/blue square.png}} +\caption{width 20 ex, figure width 40 ex} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=15\DUchdimen]{../input/data/blue square.png}} +\caption{width 15 ch, figure width 30 ch} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=10\DUremdimen]{../input/data/blue square.png}} +\caption{width 10 rem, figure width 20 rem} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=0.25\paperwidth]{../input/data/blue square.png}} +\caption{width 25 vw, figure width 30 vw} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=0.25\paperheight]{../input/data/blue square.png}} +\caption{width 25 vh, figure width 30 vh} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=25\DUvmindimen]{../input/data/blue square.png}} +\caption{width 25 vmin, figure width 30 vmin} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=25\DUvmaxdimen]{../input/data/blue square.png}} +\caption{width 25 vmax, figure width 30 vmax} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=5cm]{../input/data/blue square.png}} +\caption{width 5 cm, figure width 10 cm} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=50mm]{../input/data/blue square.png}} +\caption{width 50 mm, figure width 100 mm} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=50.0mm]{../input/data/blue square.png}} +\caption{width 200 Q, figure width 400 Q} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=2in]{../input/data/blue square.png}} +\caption{width 2 in, figure width 4 in} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=12pc]{../input/data/blue square.png}} +\caption{width 12 pc, figure width 24 pc} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=144bp]{../input/data/blue square.png}} +\caption{width 144 pt, figure width 288pt} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=192px]{../input/data/blue square.png}} +\caption{width 192 px, figure width 384 px} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16px,width=192bp]{../input/data/blue square.png}} +\caption{width 192 <no unit>, figure width 384 <no unit>} +\end{figure} + + +\section{ch, em, and rem: \includegraphics[height=1\DUchdimen]{../input/data/blue square.png} \includegraphics[height=1em]{../input/data/blue square.png} \includegraphics[height=1\DUremdimen]{../input/data/blue square.png}% + \label{ch-em-and-rem-test1ch-test1em-test1rem}% +} + +Image height 1ch, 1em, and 1rem: \includegraphics[height=1\DUchdimen]{../input/data/blue square.png} \includegraphics[height=1em]{../input/data/blue square.png} \includegraphics[height=1\DUremdimen]{../input/data/blue square.png} + +The units \textquotedbl{}em\textquotedbl{} and \textquotedbl{}ch\textquotedbl{} change with the current font size. +The unit \textquotedbl{}rem\textquotedbl{} is tied to the document root fontsize. + + +\section{Tables% + \label{tables}% +} + +\setlength{\DUtablewidth}{\dimexpr\linewidth-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +value + & +unit + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr0.25\linewidth-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +\% + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr10em-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +10 + & +em + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr20ex-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +20 + & +ex + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr15\DUchdimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +15 + & +ch + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr10\DUremdimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +10 + & +rem + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr0.25\paperwidth-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +vw + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr0.25\paperheight-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +vh + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr25\DUvmindimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +vmin + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr25\DUvmaxdimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +vmax + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr5cm-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +5 + & +cm + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr50mm-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +50 + & +mm + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr50.0mm-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +200 + & +Q + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr2in-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +2 + & +in + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr12pc-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +12 + & +pc + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr144bp-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +144 + & +pt + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr192px-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +192 + & +px + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr192bp-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +192 + & +<no unit> + \\ +\hline +\end{longtable*} + +\end{document} Property changes on: trunk/docutils/test/functional/expected/length_units_latex.tex ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: trunk/docutils/test/functional/expected/length_units_xetex.tex =================================================================== --- trunk/docutils/test/functional/expected/length_units_xetex.tex (rev 0) +++ trunk/docutils/test/functional/expected/length_units_xetex.tex 2024-09-29 09:31:39 UTC (rev 9943) @@ -0,0 +1,398 @@ +\documentclass[a4paper]{article} +% generated by Docutils <https://docutils.sourceforge.io/> +% rubber: set program xelatex +\usepackage{fontspec} +% \defaultfontfeatures{Scale=MatchLowercase} +% straight double quotes (defined in T1 but missing in TU): +\ifdefined \UnicodeEncodingName + \DeclareTextCommand{\textquotedbl}{\UnicodeEncodingName}{% + {\addfontfeatures{RawFeature=-tlig,Mapping=}\char34}}% +\fi +\usepackage{float} % extended float configuration +\floatplacement{figure}{H} % place figures here definitely +\usepackage{graphicx} +\setcounter{secnumdepth}{0} +\usepackage{longtable,ltcaption,array} +\setlength{\extrarowheight}{2pt} +\newlength{\DUtablewidth} % internal use in tables +\newcommand{\DUcolumnwidth}[1]{\dimexpr#1\DUtablewidth-2\tabcolsep\relax} + +%%% Custom LaTeX preamble +% Linux Libertine (free, wide coverage, not only for Linux) +\setmainfont{Linux Libertine O} +\setsansfont{Linux Biolinum O} +\setmonofont[HyphenChar=None,Scale=MatchLowercase]{DejaVu Sans Mono} + +%%% User specified packages and stylesheets + +%%% Fallback definitions for Docutils-specific commands + +% Provide a length variable and set default, if it is new +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1 + \else + \newlength{#1}\setlength{#1}{#2}% + \fi +} + +\ifdefined\DUchdimen % lengh unit "ch": width of a zero char +\else + \newlength{\DUchdimen} + \AtBeginDocument{\settowidth\DUchdimen{0}} % set after font setup, + % update with font changes (requires LaTeX > 2021-06-01, see lthooks-doc.pdf) + \AddToHook{cmd/selectfont/after}{\settowidth\DUchdimen{0}} +\fi + +\DUprovidelength{\pdfpxdimen}{1bp} + +\DUprovidelength{\DUremdimen}{1em} + +\AtBeginDocument{ + \ifdim\paperwidth>\paperheight\relax + \DUprovidelength{\DUvmaxdimen}{0.01\paperwidth} + \else + \DUprovidelength{\DUvmaxdimen}{0.01\paperheight} + \fi +} + +\AtBeginDocument{ + \ifdim\paperwidth>\paperheight\relax + \DUprovidelength{\DUvmindimen}{0.01\paperheight} + \else + \DUprovidelength{\DUvmindimen}{0.01\paperwidth} + \fi +} +% hyperlinks: +\ifdefined\hypersetup +\else + \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref} + \usepackage{bookmark} + \urlstyle{same} % normal text font (alternatives: tt, rm, sf) +\fi +\hypersetup{ + pdftitle={Test length specifications}, +} + +\title{Test length specifications% + \label{test-length-specifications}} +\author{} +\date{} + +%%% Body +\begin{document} +\maketitle + + +\section{Images and Figures% + \label{images-and-figures}% +} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[scale=1]{../input/data/blue square.png}} +\caption{scale 100\%, no size specification} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[width=0.25\linewidth]{../input/data/blue square.png}} +\caption{width 25\%, no height, figure width 50\%} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=0.25\linewidth]{../input/data/blue square.png}} +\caption{width 25\%, height 16px, figure width 50\%} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=10em]{../input/data/blue square.png}} +\caption{width 10 em, figure width 20 em} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=20ex]{../input/data/blue square.png}} +\caption{width 20 ex, figure width 40 ex} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=15\DUchdimen]{../input/data/blue square.png}} +\caption{width 15 ch, figure width 30 ch} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=10\DUremdimen]{../input/data/blue square.png}} +\caption{width 10 rem, figure width 20 rem} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=0.25\paperwidth]{../input/data/blue square.png}} +\caption{width 25 vw, figure width 30 vw} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=0.25\paperheight]{../input/data/blue square.png}} +\caption{width 25 vh, figure width 30 vh} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=25\DUvmindimen]{../input/data/blue square.png}} +\caption{width 25 vmin, figure width 30 vmin} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=25\DUvmaxdimen]{../input/data/blue square.png}} +\caption{width 25 vmax, figure width 30 vmax} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=5cm]{../input/data/blue square.png}} +\caption{width 5 cm, figure width 10 cm} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=50mm]{../input/data/blue square.png}} +\caption{width 50 mm, figure width 100 mm} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=50.0mm]{../input/data/blue square.png}} +\caption{width 200 Q, figure width 400 Q} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=2in]{../input/data/blue square.png}} +\caption{width 2 in, figure width 4 in} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=12pc]{../input/data/blue square.png}} +\caption{width 12 pc, figure width 24 pc} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=144bp]{../input/data/blue square.png}} +\caption{width 144 pt, figure width 288pt} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=192\pdfpxdimen]{../input/data/blue square.png}} +\caption{width 192 px, figure width 384 px} +\end{figure} + +\begin{figure} +\noindent\makebox[\linewidth][c]{\includegraphics[height=16\pdfpxdimen,width=192bp]{../input/data/blue square.png}} +\caption{width 192 <no unit>, figure width 384 <no unit>} +\end{figure} + + +\section{ch, em, and rem: \includegraphics[height=1\DUchdimen]{../input/data/blue square.png} \includegraphics[height=1em]{../input/data/blue square.png} \includegraphics[height=1\DUremdimen]{../input/data/blue square.png}% + \label{ch-em-and-rem-test1ch-test1em-test1rem}% +} + +Image height 1ch, 1em, and 1rem: \includegraphics[height=1\DUchdimen]{../input/data/blue square.png} \includegraphics[height=1em]{../input/data/blue square.png} \includegraphics[height=1\DUremdimen]{../input/data/blue square.png} + +The units \textquotedbl{}em\textquotedbl{} and \textquotedbl{}ch\textquotedbl{} change with the current font size. +The unit \textquotedbl{}rem\textquotedbl{} is tied to the document root fontsize. + + +\section{Tables% + \label{tables}% +} + +\setlength{\DUtablewidth}{\dimexpr\linewidth-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +value + & +unit + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr0.25\linewidth-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +\% + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr10em-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +10 + & +em + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr20ex-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +20 + & +ex + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr15\DUchdimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +15 + & +ch + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr10\DUremdimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +10 + & +rem + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr0.25\paperwidth-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +vw + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr0.25\paperheight-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +vh + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr25\DUvmindimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +vmin + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr25\DUvmaxdimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +25 + & +vmax + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr5cm-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +5 + & +cm + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr50mm-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +50 + & +mm + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr50.0mm-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +200 + & +Q + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr2in-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +2 + & +in + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr12pc-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +12 + & +pc + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr144bp-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +144 + & +pt + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr192\pdfpxdimen-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +192 + & +px + \\ +\hline +\end{longtable*} + +\setlength{\DUtablewidth}{\dimexpr192bp-3\arrayrulewidth\relax}% +\begin{longtable*}{|p{\DUcolumnwidth{0.500}}|p{\DUcolumnwidth{0.500}}|} +\hline + +192 + & +<no unit> + \\ +\hline +\end{longtable*} + +\end{document} Property changes on: trunk/docutils/test/functional/expected/length_units_xetex.tex ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Modified: trunk/docutils/test/functional/expected/standalone_rst_xetex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-29 09:31:17 UTC (rev 9942) +++ trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-29 09:31:39 UTC (rev 9943) @@ -33,12 +33,11 @@ %%% User specified packages and stylesheets %%% Fallback definitions for Docutils-specific commands -\usepackage{docutils}[2020/08/28] +\usepackage{docutils}[2024-09-24] \newcounter{enumv} \DUprovidelength{\pdfpxdimen}{1bp} - \providecommand*{\DUCLASScontents}{% \renewenvironment{itemize}% {\begin{list}{}{\setlength{\partopsep}{0pt} Added: trunk/docutils/test/functional/input/length_units.rst =================================================================== --- trunk/docutils/test/functional/input/length_units.rst (rev 0) +++ trunk/docutils/test/functional/input/length_units.rst 2024-09-29 09:31:39 UTC (rev 9943) @@ -0,0 +1,273 @@ +Test length specifications +========================== + +Images and Figures +------------------ + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :scale: 100 + + scale 100%, no size specification + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :width: 25 % + :figwidth: 50% + + width 25%, no height, figure width 50% + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 25% + :figwidth: 50 % + + width 25%, height 16px, figure width 50% + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 10em + :figwidth: 20 em + + width 10 em, figure width 20 em + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 20ex + :figwidth: 40 ex + + width 20 ex, figure width 40 ex + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 15 ch + :figwidth: 30ch + + width 15 ch, figure width 30 ch + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 10 rem + :figwidth: 20rem + + width 10 rem, figure width 20 rem + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 25 vw + :figwidth: 30 vw + + width 25 vw, figure width 30 vw + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 25 vh + :figwidth: 30 vh + + width 25 vh, figure width 30 vh + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 25 vmin + :figwidth: 30 vmin + + width 25 vmin, figure width 30 vmin + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 25 vmax + :figwidth: 30 vmax + + width 25 vmax, figure width 30 vmax + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 5 cm + :figwidth: 10 cm + + width 5 cm, figure width 10 cm + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 50mm + :figwidth: 100 mm + + width 50 mm, figure width 100 mm + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 200 Q + :figwidth: 400Q + + width 200 Q, figure width 400 Q + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 2 in + :figwidth: 4in + + width 2 in, figure width 4 in + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 12 pc + :figwidth: 24pc + + width 12 pc, figure width 24 pc + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 144pt + :figwidth: 288pt + + width 144 pt, figure width 288pt + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 192 px + :figwidth: 384px + + width 192 px, figure width 384 px + +.. figure:: ../input/data/blue%20square.png + :alt: blue square + :height: 16px + :width: 192 + :figwidth: 384 + + width 192 <no unit>, figure width 384 <no unit> + + +ch, em, and rem: |test1ch| |test1em| |test1rem| +----------------------------------------------- + +.. |test1em| image:: ../input/data/blue%20square.png + :height: 1em + +.. |test1rem| image:: ../input/data/blue%20square.png + :height: 1rem + +.. |test1ch| image:: ../input/data/blue%20square.png + :height: 1ch + +Image height 1ch, 1em, and 1rem: |test1ch| |test1em| |test1rem| + +The units "em" and "ch" change with the current font size. +The unit "rem" is tied to the document root fontsize. + + +Tables +------ + +.. csv-table:: + + value, unit + +.. csv-table:: + :width: 25% + + 25, % + + +.. csv-table:: + :width: 10em + + 10, em + +.. csv-table:: + :width: 20ex + + 20, ex + +.. csv-table:: + :width: 15 ch + + 15, ch + +.. csv-table:: + :width: 10rem + + 10, rem + +.. csv-table:: + :width: 25vw + + 25, vw + +.. csv-table:: + :width: 25vh + + 25, vh + +.. csv-table:: + :width: 25vmin + + 25, vmin + +.. csv-table:: + :width: 25vmax + + 25, vmax + +.. csv-table:: + :width: 5 cm + + 5, cm + +.. csv-table:: + :width: 50mm + + 50, mm + +.. csv-table:: + :width: 200 Q + + 200, Q + +.. csv-table:: + :width: 2 in + + 2, in + +.. csv-table:: + :width: 12 pc + + 12, pc + +.. csv-table:: + :width: 144pt + + 144, pt + +.. csv-table:: + :width: 192 px + + 192, px + +.. csv-table:: + :width: 192 + + 192, <no unit> + + +.. raw:: html + + <style type="text/css"><!-- + figure {background: lightgreen;} + --></style> Added: trunk/docutils/test/functional/tests/length_units_html5.py =================================================================== --- trunk/docutils/test/functional/tests/length_units_html5.py (rev 0) +++ trunk/docutils/test/functional/tests/length_units_html5.py 2024-09-29 09:31:39 UTC (rev 9943) @@ -0,0 +1,10 @@ +# Source and destination file names +test_source = "length_units.rst" +test_destination = "length_units_html5.html" + +# Keyword parameters passed to publish_file() +writer = "html5" +settings_overrides = { + # location of stylesheets (relative to ``docutils/test/``) + 'stylesheet_dirs': ('functional/input/data', ), + } Property changes on: trunk/docutils/test/functional/tests/length_units_html5.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: trunk/docutils/test/functional/tests/length_units_latex.py =================================================================== --- trunk/docutils/test/functional/tests/length_units_latex.py (rev 0) +++ trunk/docutils/test/functional/tests/length_units_latex.py 2024-09-29 09:31:39 UTC (rev 9943) @@ -0,0 +1,12 @@ +# Source and destination file names +test_source = "length_units.rst" +test_destination = "length_units_latex.tex" + +# Keyword parameters passed to publish_file() +writer = "latex" +settings_overrides = { + 'legacy_column_widths': False, + 'use_latex_citations': True, + 'stylesheet': 'docutils,geometry,nohyperref', + 'documentoptions': 'a4paper,landscape', + } Property changes on: trunk/docutils/test/functional/tests/length_units_latex.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: trunk/docutils/test/functional/tests/length_units_xetex.py =================================================================== --- trunk/docutils/test/functional/tests/length_units_xetex.py (rev 0) +++ trunk/docutils/test/functional/tests/length_units_xetex.py 2024-09-29 09:31:39 UTC (rev 9943) @@ -0,0 +1,10 @@ +# Source and destination file names +test_source = "length_units.rst" +test_destination = "length_units_xetex.tex" + +# Keyword parameters passed to publish_file() +writer = "xetex" +settings_overrides = { + 'legacy_column_widths': False, + 'use_latex_citations': True, + } Property changes on: trunk/docutils/test/functional/tests/length_units_xetex.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of proper... [truncated message content] |
From: <mi...@us...> - 2024-10-02 08:40:50
|
Revision: 9944 http://sourceforge.net/p/docutils/code/9944 Author: milde Date: 2024-10-02 08:40:47 +0000 (Wed, 02 Oct 2024) Log Message: ----------- Document two more doctree elements + other documentation updates. Document `<problematic>` and `<system_message>` doctree elements. Various more or less related documentation corrections and updates. Modified Paths: -------------- trunk/docutils/RELEASE-NOTES.rst trunk/docutils/docs/ref/doctree.rst trunk/docutils/docs/ref/rst/restructuredtext.rst trunk/docutils/docs/user/config.rst Modified: trunk/docutils/RELEASE-NOTES.rst =================================================================== --- trunk/docutils/RELEASE-NOTES.rst 2024-09-29 09:31:39 UTC (rev 9943) +++ trunk/docutils/RELEASE-NOTES.rst 2024-10-02 08:40:47 UTC (rev 9944) @@ -28,15 +28,16 @@ .. code:: diff - COMMAND [OPTIONS] [SOURCE [DESTINATION]] - + COMMAND [OPTIONS] [SOURCE [SOURCE2 [...]]] [>DESTINATION] + + COMMAND [OPTIONS] [SOURCE [SOURCE2 [...]]] * Stop accepting the DESTINATION positional argument in Docutils 1.0. - Use output redirection or the option ``--output=DESTINATION`` - (available since Docutils 0.20). + Use ``--output=DESTINATION`` (cf. the "output_" configuration setting) + or output redirection. - * Accept more than one source document and the short option - ``-o`` for ``--output`` in Docutils 2.0 + * Accept the short option ``-o`` for ``--output`` in Docutils 1.0 + * Accept more than one source document in Docutils 2.0 + For the rationale, see https://clig.dev/#arguments-and-flags. .. _entry points: @@ -438,7 +439,7 @@ are now ignored by the "xetex" writer. Place common settings in section `[latex writers]`_. - - New command line setting output_. Obsoletes the ``<destination>`` + - New configuration setting "output_". Obsoletes the ``<destination>`` positional argument (cf. `future changes`__). __ `command-line usage pattern`_ @@ -533,8 +534,7 @@ Example: with ``--id-prefix="DU-"``, a section with title "34. May" - currently gets the identifier key ``DU-may`` and after the - change the identifier key ``DU-34-may``. + now gets the identifier key ``DU-34-may`` instead of ``DU-may``. - The default value for the auto_id_prefix_ setting changed to ``%``: "use the tag name as prefix for auto-generated IDs". Modified: trunk/docutils/docs/ref/doctree.rst =================================================================== --- trunk/docutils/docs/ref/doctree.rst 2024-09-29 09:31:39 UTC (rev 9943) +++ trunk/docutils/docs/ref/doctree.rst 2024-10-02 08:40:47 UTC (rev 9944) @@ -277,7 +277,6 @@ :Docutils class: ``nodes.Part`` - Inline Elements --------------- @@ -2254,7 +2253,8 @@ The <inline> element is a generic inline container. :Category: `Inline Elements`_ -:Analogues: <inline> is analogous to the HTML <span> element. +:Analogues: <inline> is analogous to the HTML_ <span> element and the + Docbook_ <phrase> element. :Processing: Writers_ typically pass the classes_ attribute to the output document and leave styling to the backend or a custom stylesheet_. They may also process the classes_ attribute @@ -2944,9 +2944,45 @@ <problematic> ============= -`To be completed`_. +The <problematic> element highlights a source part that caused a parsing +problem. +:Category: `Inline Elements`_ +:Analogues: <problematic> has no direct analogues in common DTDs. +:Processing: Typically displayed in red colour. + If the refid_ attribute is present, the element should + point to the referenced element. +:Parents: All elements employing the `%text.model`_ parameter + entity in their content models may contain <problematic>. +:Children: <problematic> elements may contain text data + plus `inline elements`_ (`%text.model`_). +:Attributes: The <problematic> element contains the `common attributes`_ + and refid_. +Examples +-------- + +The reStructuredText parser marks ambiguous or invalid inline syntax as +<problematic> and adds a reference to the associated `\<system_message>`_. +The behaviour can be configured with the `report_level`_ setting. + +The following paragraph contains unbalanced `inline markup`_:: + + a single *star + +Pseudo-XML_ fragment from simple parsing:: + + <paragraph> + a single + <problematic ids="problematic-1" refid="system-message-1"> + * + star + <system_message backrefs="problematic-1" ids="system-message-1" + level="2" line="1" source="example.rst" type="WARNING"> + <paragraph> + Inline emphasis start-string without end-string. + + <raw> ===== @@ -3435,9 +3471,46 @@ <system_message> ================ -`To be completed`_. +The <system_message> element is used for feedback from the processing +system. +:Category: `Compound Body Elements`_ +:Analogues: <system_message> has no direct analogues in common DTDs. + It can be emulated with primitives and type effects. +:Processing: Rendered similar to an `\<admonition>`_, with the generated + title "System Message", its type_/level_ and, if available, + source_ and line_. +:Parents: All elements employing the `%body.elements`_ or + `%structure.model`_ parameter entities in their content models + may contain <system_message>. +:Children: <system_message> elements contain one or more `body elements`_. +:Attributes: The <system_message> element accepts the `common + attributes`_ plus backrefs_, level_, line_, and type_. +:Parameter Entities: The `%body.elements`_ parameter entity directly includes + <system_message>. The `%structure.model`_ parameter entity + indirectly includes <system_message>. +In Docutils, the generation of system messages can be configured with the +`report_level`_ setting. + +Examples +-------- + +An undefined or misspelled directive_ generates an error message:: + + .. contants:: + +Pseudo-XML_ fragment from simple parsing:: + + <system_message level="3" line="8" source="example.rst" type="ERROR"> + <paragraph> + Unknown directive type "contants". + <literal_block xml:space="preserve"> + .. contants:: + +See also `\<problematic>`_. + + <table> ======= @@ -4417,7 +4490,8 @@ Attribute type: `%number`_. Default value: none. -The ``level`` attribute is used in the `\<system_message>`_ element. +The ``level`` attribute is used in the `\<system_message>`_ element to +indicate the message's `severity level`_. See also the "type_" attribute. ``line`` @@ -4425,7 +4499,9 @@ Attribute type: `%number`_. Default value: none. -The ``line`` attribute is used in the `\<system_message>`_ element. +The ``line`` attribute is used in the `\<system_message>`_ element to +indicate the position of the reported problem in the document source. +See also the source_ attribute. ``ltrim`` @@ -4650,18 +4726,21 @@ Attribute type: `CDATA`_. Default value: none. -The ``source`` attribute is used to store the path or URI of the -source text that was used to produce the document tree. +The ``source`` attribute stores the path, URI, or a description +of the source that was used to produce the document tree. [#]_ -It is one of the `common attributes`_, declared for all Docutils -elements but typically only used with the `\<document>`_ and -`\<system_message>`_ elements. +``source`` is one of the `common attributes`_ but typically only +used with the `\<document>`_ and `\<system_message>`_ elements. -.. note:: All ``docutils.nodes.Node`` instances also support an - *internal* ``source`` attribute that is used when reporting - processing problems. +.. note:: All ``docutils.nodes.Node`` instances also support + *internal* ``source`` and ``line`` attributes + for use in diagnostic output. +.. [#] An element's ``source`` attribute may differ from the main + document ``source`` if the document is assembled from several + sources (e.g. via the `"include" directive`_). + ``start`` ========= @@ -4668,7 +4747,7 @@ Attribute type: `%number`_. Default value: none (implies 1). The ``start`` attribute is used in the `\<enumerated_list>`_ element to -store the ordinal value of the first item in the list, in decimal. +store the ordinal value of the first item in the list, in decimal notation. For lists beginning at value 1 ("1", "a", "A", "i", or "I"), this attribute may be omitted. @@ -4717,6 +4796,7 @@ .. _HTML <title> element: https://html.spec.whatwg.org/multipage/semantics.html#the-title-element + ``type`` ========= @@ -4723,6 +4803,8 @@ Attribute type: NMTOKEN_. Default value: none. The ``type`` attribute is used in the `\<system_message>`_ element. +It holds the name of the message's `severity level`_ (cf. the "level_" +attribute). ``uri`` @@ -4778,6 +4860,7 @@ element contains significant whitespace. The attribute value should not be set in a document instance. + ---------------------------- Parameter Entity Reference ---------------------------- @@ -4797,6 +4880,7 @@ In addition, the Docutils DTD defines parameter entities for `custom attribute types`_. + Attribute Entities ================== @@ -4827,6 +4911,7 @@ The `\<image>`_ element directly employs the ``%align-hv.att`` parameter entity in its attribute list. + ``%anonymous.att`` ------------------ @@ -4997,6 +5082,7 @@ indirectly employed in the attribute lists of the `\<citation_reference>`_, `\<footnote_reference>`_, `\<reference>`_, and `\<target>`_ elements. + ``%tbl.colspec.att`` -------------------- @@ -5263,10 +5349,10 @@ `XML Exchange Table Model DTD`, OASIS Technical Memorandum 9901:1999, http://www.oasis-open.org/html/tm9901.html. - W3C Recommendation, - https://www.w3.org/TR/xml/. .. [xml1.0] `Extensible Markup Language (XML) 1.0`, + W3C Recommendation, + https://www.w3.org/TR/xml/. .. _DocBook: https://tdg.docbook.org/tdg/5.1/. .. _DocBook <caution>: https://tdg.docbook.org/tdg/5.1/caution.html @@ -5304,6 +5390,7 @@ .. _datestamp: ../user/config.html#datestamp .. _id_prefix: ../user/config.html#id-prefix .. _image_loading: ../user/config.html#image-loading +.. _report_level: ../user/config.html#report-level .. _stylesheet: ../user/config.html#stylesheet .. _transform: @@ -5311,6 +5398,8 @@ .. _DocInfo transform: ../api/transforms.html#docinfo .. _DocTitle transform: ../api/transforms.html#doctitle +.. _severity level: ../peps/pep-0258.html#error-handling + .. _A ReStructuredText Primer: ../user/rst/quickstart.html .. _reStructuredText Markup Specification: rst/restructuredtext.html .. _bibliographic data: @@ -5327,9 +5416,10 @@ .. _explicit markup blocks: rst/restructuredtext.html#explicit-markup-blocks .. _footnote reference: rst/restructuredtext.html#footnote-references .. _grid table: rst/restructuredtext.html#grid-tables -.. _indirect target: rst/restructuredtext.html#indirect-hyperlink-targets +.. _indirect target: rst/restructuredtext.html#indirect-hyperlink-targets +.. _inline markup: rst/restructuredtext.html#inline-markup .. _internal hyperlink targets: - rst/restructuredtext.html#internal-hyperlink-targets + rst/restructuredtext.html#internal-hyperlink-targets .. _line block: rst/restructuredtext.html#line-blocks .. _literal block: rst/restructuredtext.html#literal-blocks .. _footnotes: @@ -5376,6 +5466,7 @@ .. _identifier normalization: rst/directives.html#identifier-normalization .. _"image" directive: rst/directives.html#image .. _"important" directive: rst/directives.html#important +.. _"include" directive: rst/directives.html#include .. _"list-table": rst/directives.html#list-table .. _"math" directive: rst/directives.html#math .. _"meta" directive: rst/directives.html#meta Modified: trunk/docutils/docs/ref/rst/restructuredtext.rst =================================================================== --- trunk/docutils/docs/ref/rst/restructuredtext.rst 2024-09-29 09:31:39 UTC (rev 9943) +++ trunk/docutils/docs/ref/rst/restructuredtext.rst 2024-10-02 08:40:47 UTC (rev 9944) @@ -457,10 +457,9 @@ reference (``note_``). Of course, each type of reference (hyperlink, footnote, citation) may be processed and rendered differently. Some care should be taken to avoid reference name conflicts. +References to `substitution definitions`_ (`substitution references`_) +use a different namespace. -`Substitution references`_ and `substitution definitions`_ use a -different namespace. - .. [#case-forgiving] Matching `substitution references`_ to `substitution definitions`_ is `case-sensitive but forgiving`_. Modified: trunk/docutils/docs/user/config.rst =================================================================== --- trunk/docutils/docs/user/config.rst 2024-09-29 09:31:39 UTC (rev 9943) +++ trunk/docutils/docs/user/config.rst 2024-10-02 08:40:47 UTC (rev 9944) @@ -227,8 +227,6 @@ https://docs.python.org/3/library/configparser.html .. _Python: https://www.python.org/ .. _RFC 822: https://www.rfc-editor.org/rfc/rfc822.txt -.. _front-end tool: -.. _application: tools.html __ ../api/runtime-settings.html#active-sections @@ -396,7 +394,8 @@ See also report_level_. -*Default*: 4 (severe). *Options*: ``--halt``, ``--strict``. +:Default: 4 (severe). +:Options: ``--halt``, ``--strict`` (same as ``--halt=info``). id_prefix @@ -407,8 +406,8 @@ format, as it is not subjected to the `identifier normalization`_. See also auto_id_prefix_. -*Default*: "" (no prefix). -*Option*: ``--id-prefix`` (hidden, intended mainly for programmatic use). +:Default: "" (no prefix). +:Option: ``--id-prefix`` (hidden, intended mainly for programmatic use). input_encoding @@ -471,11 +470,11 @@ output ------ -The path of the output destination. -An existing file will be overwritten without warning. -Use "-" for `stdout`. +The path of the output destination. Use "-" for `stdout`. -Obsoletes the `\<destination>`_ positional argument +.. Caution:: **An existing file will be overwritten** without warning! + +Obsoletes the `_destination`_ positional argument (cf. `Future changes`_ in the RELEASE-NOTES). *Default*: None (stdout). *Option*: ``--output``. @@ -568,18 +567,16 @@ report_level ------------ -Report system messages at or higher than <level>: +Report system messages at or higher than the given `severity level`_: - 1 info - 2 warning - 3 error - 4 severe - 5 none + 1 info, 2 warning, 3 error, 4 severe, 5 none See also halt_level_. :Default: 2 (warning). -:Options: ``--report``, ``-r``, ``--verbose``, ``-v``, ``--quiet``, ``-q``. +:Options: | ``--report``, ``-r`` (with level as number or name) + | ``--verbose``, ``-v`` (same as ``--report=1``) + | ``--quiet``, ``-q`` (same as ``--report=5``) root_prefix @@ -714,9 +711,10 @@ traceback --------- -Enable or disable Python tracebacks when halt-level system messages and -other exceptions occur. Useful for debugging, and essential for issue -reports. Exceptions are allowed to propagate, instead of being +Enable or disable Python tracebacks when system messages with +a severity above the `halt_level`_ and other exceptions occur. +Useful for debugging, and essential for issue reports. +Exceptions are allowed to propagate, instead of being caught and reported (in a user-friendly way) by Docutils. :Default: None (disabled). [#]_ @@ -1140,8 +1138,8 @@ embed_stylesheet ~~~~~~~~~~~~~~~~ -Embed the stylesheet in the output HTML file. The stylesheet file -must specified by the stylesheet_path_ setting and must be +Embed stylesheet(s) in the HTML output. The stylesheet files +must be specified by the stylesheet_path_ setting and must be accessible during processing. See also `embed_stylesheet [latex writers]`_. @@ -1879,7 +1877,7 @@ List of style files (comma-separated_). Relative paths are expanded if a matching file is found in the stylesheet_dirs__. If embed_stylesheet__ is False, paths are rewritten relative to -the output file (if output_ or `\<destination>`_ are specified) +the output file (if output_ or `_destination`_ are specified) or the current work directory. Overrides also stylesheet__. [#override]_ See also `stylesheet_path [html writers]`_. @@ -1888,7 +1886,6 @@ *Default*: empty list. *Option*: ``--stylesheet-path``. -.. _<destination>: tools.html#usage-pattern __ `stylesheet_dirs [latex writers]`_ __ `embed_stylesheet [latex writers]`_ __ @@ -2175,7 +2172,7 @@ [applications] ============== -Some `front end tools`_ provide additional settings. +The following applications (`front-end tools`_) provide additional settings. .. _buildhtml: @@ -2372,9 +2369,12 @@ _directories ~~~~~~~~~~~~ -(``buildhtml.py`` front end.) List of paths to source -directories, set from positional arguments. +Only with the `[buildhtml application]`_. +List of paths to source directories, set from `positional arguments +<tools.html#buildhtml-py>`__. + + *Default*: None (current working directory). No command-line options. _disable_config @@ -2386,13 +2386,18 @@ _destination ~~~~~~~~~~~~ -Path to output destination, set from positional arguments. +Path to output destination, set from `positional arguments`_ +or the output_ setting. -*Default*: None (stdout). No command-line options. +Deprecated, obsoleted by the output_ setting. Will be removed +in Docutils 2.0 (cf. `Future changes`_ in the RELEASE-NOTES). +*Default*: None (stdout). *Option*: ``--output``. + + _source ~~~~~~~ -Path to input source, set from positional arguments. +Path to input source, set from `positional arguments`_. *Default*: None (stdin). No command-line options. @@ -2502,6 +2507,8 @@ .. _publish_string(): ../api/publisher.html#publish-string .. _publish_from_doctree(): ../api/publisher.html#publish-from-doctree +.. _severity level: ../peps/pep-0258.html#error-handling + .. RestructuredText Directives .. _"class" directive: ../ref/rst/directives.html#class .. _"code": ../ref/rst/directives.html#code @@ -2542,8 +2549,11 @@ .. _Docutils HTML writers: html.html -.. _front end tools: tools.html +.. _application: +.. _front-end tool: +.. _front-end tools: tools.html .. _buildhtml.py: tools.html#buildhtml-py +.. _positional arguments: tools.html#usage-pattern .. _BCP 47: https://www.rfc-editor.org/rfc/bcp/bcp47.txt .. _Error Handlers: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <aa-...@us...> - 2024-10-13 00:25:00
|
Revision: 9946 http://sourceforge.net/p/docutils/code/9946 Author: aa-turner Date: 2024-10-13 00:24:58 +0000 (Sun, 13 Oct 2024) Log Message: ----------- Use UNIX-style (LF) line endings Modified Paths: -------------- trunk/docutils/docs/ref/rst/history.rst trunk/docutils/docutils/utils/_roman_numerals.py trunk/docutils/licenses/BSD-0-Clause.rst trunk/docutils/test/test_utils/test__roman_numerals.py Modified: trunk/docutils/docs/ref/rst/history.rst =================================================================== --- trunk/docutils/docs/ref/rst/history.rst 2024-10-04 12:21:52 UTC (rev 9945) +++ trunk/docutils/docs/ref/rst/history.rst 2024-10-13 00:24:58 UTC (rev 9946) @@ -1,167 +1,167 @@ -.. include:: ../../header2.rst - -============================= - History of reStructuredText -============================= -:Author: David Goodger -:Contact: doc...@li... -:Revision: $Revision$ -:Date: $Date$ -:Copyright: This document has been placed in the public domain. - -reStructuredText_, the specification, is based on StructuredText_ and -Setext_. StructuredText was developed by Jim Fulton of `Zope -Corporation`_ (formerly Digital Creations) and first released in 1996. -It is now released as a part of the open-source "Z Object Publishing -Environment" (ZOPE_). Ian Feldman's and Tony Sanders' earlier Setext_ -specification was either an influence on StructuredText or, by their -similarities, at least evidence of the correctness of this approach. - -I discovered StructuredText_ in late 1999 while searching for a way to -document the Python modules in one of my projects. Version 1.1 of -StructuredText was included in Daniel Larsson's pythondoc_. Although -I was not able to get pythondoc to work for me, I found StructuredText -to be almost ideal for my needs. I joined the Python Doc-SIG_ -(Documentation Special Interest Group) mailing list and found an -ongoing discussion of the shortcomings of the StructuredText -"standard". This discussion has been going on since the inception of -the mailing list in 1996, and possibly predates it. - -I decided to modify the original module with my own extensions and -some suggested by the Doc-SIG members. I soon realized that the -module was not written with extension in mind, so I embarked upon a -general reworking, including adapting it to the "re" regular -expression module (the original inspiration for the name of this -project). Soon after I completed the modifications, I discovered that -StructuredText.py was up to version 1.23 in the ZOPE distribution. -Implementing the new syntax extensions from version 1.23 proved to be -an exercise in frustration, as the complexity of the module had become -overwhelming. - -In 2000, development on StructuredTextNG ("Next Generation") began at -`Zope Corporation`_ (then Digital Creations). It seems to have many -improvements, but still suffers from many of the problems of classic -StructuredText. - -I decided that a complete rewrite was in order, and even started a -`reStructuredText SourceForge project`_ (now inactive). My -motivations (the "itches" I aim to "scratch") are as follows: - -- I need a standard format for inline documentation of the programs I - write. This inline documentation has to be convertible to other - useful formats, such as HTML. I believe many others have the same - need. - -- I believe in the Setext/StructuredText idea and want to help - formalize the standard. However, I feel the current specifications - and implementations have flaws that desperately need fixing. - -- reStructuredText could form part of the foundation for a - documentation extraction and processing system, greatly benefitting - Python. But it is only a part, not the whole. reStructuredText is - a markup language specification and a reference parser - implementation, but it does not aspire to be the entire system. I - don't want reStructuredText or a hypothetical Python documentation - processor to die stillborn because of over-ambition. - -- Most of all, I want to help ease the documentation chore, the bane - of many a programmer. - -Unfortunately I was sidetracked and stopped working on this project. -In November 2000 I made the time to enumerate the problems of -StructuredText and possible solutions, and complete the first draft of -a specification. This first draft was posted to the Doc-SIG in three -parts: - -- `A Plan for Structured Text`__ -- `Problems With StructuredText`__ -- `reStructuredText: Revised Structured Text Specification`__ - -__ https://mail.python.org/pipermail/doc-sig/2000-November/001239.html -__ https://mail.python.org/pipermail/doc-sig/2000-November/001240.html -__ https://mail.python.org/pipermail/doc-sig/2000-November/001241.html - -In March 2001 a flurry of activity on the Doc-SIG spurred me to -further revise and refine my specification, the result of which you -are now reading. An offshoot of the reStructuredText project has been -the realization that a single markup scheme, no matter how well -thought out, may not be enough. In order to tame the endless debates -on Doc-SIG, a flexible `Docstring Processing System framework`_ needed -to be constructed. This framework has become the more important of -the two projects; reStructuredText_ has found its place as one -possible choice for a single component of the larger framework. - -The project web site and the first project release were rolled out in -June 2001, including posting the second draft of the spec [#spec-2]_ -and the first draft of PEPs 256, 257, and 258 [#peps-1]_ to the -Doc-SIG. These documents and the project implementation proceeded to -evolve at a rapid pace. Implementation history details can be found -in the `project history file`_. - -In November 2001, the reStructuredText parser was nearing completion. -Development of the parser continued with the addition of small -convenience features, improvements to the syntax, the filling in of -gaps, and bug fixes. After a long holiday break, in early 2002 most -development moved over to the other Docutils components, the -"Readers", "Writers", and "Transforms". A "standalone" reader -(processes standalone text file documents) was completed in February, -and a basic HTML writer (producing HTML 4.01, using CSS-1) was -completed in early March. - -`PEP 287`_, "reStructuredText Standard Docstring Format", was created -to formally propose reStructuredText as a standard format for Python -docstrings, PEPs, and other files. It was first posted to -comp.lang.python_ and the Python-dev_ mailing list on 2002-04-02. - -Version 0.4 of the reStructuredText__ and `Docstring Processing -System`_ projects were released in April 2002. The two projects were -immediately merged, renamed to "Docutils_", and a 0.1 release soon -followed. - -.. __: `reStructuredText SourceForge project`_ - -.. [#spec-2] The second draft of the spec: - - - `An Introduction to reStructuredText`__ - - `Problems With StructuredText`__ - - `reStructuredText Markup Specification`__ - - `Python Extensions to the reStructuredText Markup - Specification`__ - - __ https://mail.python.org/pipermail/doc-sig/2001-June/001858.html - __ https://mail.python.org/pipermail/doc-sig/2001-June/001859.html - __ https://mail.python.org/pipermail/doc-sig/2001-June/001860.html - __ https://mail.python.org/pipermail/doc-sig/2001-June/001861.html - -.. [#peps-1] First drafts of the PEPs: - - - `PEP 256: Docstring Processing System Framework`__ - - `PEP 258: DPS Generic Implementation Details`__ - - `PEP 257: Docstring Conventions`__ - - Current working versions of the PEPs can be found in - https://docutils.sourceforge.io/docs/peps/, and official versions - can be found in the `master PEP repository`_. - - __ https://mail.python.org/pipermail/doc-sig/2001-June/001855.html - __ https://mail.python.org/pipermail/doc-sig/2001-June/001856.html - __ https://mail.python.org/pipermail/doc-sig/2001-June/001857.html - - -.. _reStructuredText: https://docutils.sourceforge.io/rst.html -.. _StructuredText: https://zopestructuredtext.readthedocs.org/ -.. _Setext: https://docutils.sourceforge.io/mirror/setext.html -.. _Docutils: https://docutils.sourceforge.io/ -.. _Doc-SIG: https://www.python.org/sigs/doc-sig/ -.. _Zope Corporation: http://www.zope.com -.. _ZOPE: https://www.zope.dev -.. _reStructuredText SourceForge project: - http://structuredtext.sourceforge.net/ -.. _pythondoc: http://starship.python.net/crew/danilo/pythondoc/ -.. _project history file: ../../../HISTORY.html -.. _PEP 287: ../../peps/pep-0287.html -.. _Docstring Processing System framework: ../../peps/pep-0256.html -.. _comp.lang.python: news:comp.lang.python -.. _Python-dev: https://mail.python.org/pipermail/python-dev/ -.. _Docstring Processing System: http://docstring.sourceforge.net/ -.. _master PEP repository: https://peps.python.org/ +.. include:: ../../header2.rst + +============================= + History of reStructuredText +============================= +:Author: David Goodger +:Contact: doc...@li... +:Revision: $Revision$ +:Date: $Date$ +:Copyright: This document has been placed in the public domain. + +reStructuredText_, the specification, is based on StructuredText_ and +Setext_. StructuredText was developed by Jim Fulton of `Zope +Corporation`_ (formerly Digital Creations) and first released in 1996. +It is now released as a part of the open-source "Z Object Publishing +Environment" (ZOPE_). Ian Feldman's and Tony Sanders' earlier Setext_ +specification was either an influence on StructuredText or, by their +similarities, at least evidence of the correctness of this approach. + +I discovered StructuredText_ in late 1999 while searching for a way to +document the Python modules in one of my projects. Version 1.1 of +StructuredText was included in Daniel Larsson's pythondoc_. Although +I was not able to get pythondoc to work for me, I found StructuredText +to be almost ideal for my needs. I joined the Python Doc-SIG_ +(Documentation Special Interest Group) mailing list and found an +ongoing discussion of the shortcomings of the StructuredText +"standard". This discussion has been going on since the inception of +the mailing list in 1996, and possibly predates it. + +I decided to modify the original module with my own extensions and +some suggested by the Doc-SIG members. I soon realized that the +module was not written with extension in mind, so I embarked upon a +general reworking, including adapting it to the "re" regular +expression module (the original inspiration for the name of this +project). Soon after I completed the modifications, I discovered that +StructuredText.py was up to version 1.23 in the ZOPE distribution. +Implementing the new syntax extensions from version 1.23 proved to be +an exercise in frustration, as the complexity of the module had become +overwhelming. + +In 2000, development on StructuredTextNG ("Next Generation") began at +`Zope Corporation`_ (then Digital Creations). It seems to have many +improvements, but still suffers from many of the problems of classic +StructuredText. + +I decided that a complete rewrite was in order, and even started a +`reStructuredText SourceForge project`_ (now inactive). My +motivations (the "itches" I aim to "scratch") are as follows: + +- I need a standard format for inline documentation of the programs I + write. This inline documentation has to be convertible to other + useful formats, such as HTML. I believe many others have the same + need. + +- I believe in the Setext/StructuredText idea and want to help + formalize the standard. However, I feel the current specifications + and implementations have flaws that desperately need fixing. + +- reStructuredText could form part of the foundation for a + documentation extraction and processing system, greatly benefitting + Python. But it is only a part, not the whole. reStructuredText is + a markup language specification and a reference parser + implementation, but it does not aspire to be the entire system. I + don't want reStructuredText or a hypothetical Python documentation + processor to die stillborn because of over-ambition. + +- Most of all, I want to help ease the documentation chore, the bane + of many a programmer. + +Unfortunately I was sidetracked and stopped working on this project. +In November 2000 I made the time to enumerate the problems of +StructuredText and possible solutions, and complete the first draft of +a specification. This first draft was posted to the Doc-SIG in three +parts: + +- `A Plan for Structured Text`__ +- `Problems With StructuredText`__ +- `reStructuredText: Revised Structured Text Specification`__ + +__ https://mail.python.org/pipermail/doc-sig/2000-November/001239.html +__ https://mail.python.org/pipermail/doc-sig/2000-November/001240.html +__ https://mail.python.org/pipermail/doc-sig/2000-November/001241.html + +In March 2001 a flurry of activity on the Doc-SIG spurred me to +further revise and refine my specification, the result of which you +are now reading. An offshoot of the reStructuredText project has been +the realization that a single markup scheme, no matter how well +thought out, may not be enough. In order to tame the endless debates +on Doc-SIG, a flexible `Docstring Processing System framework`_ needed +to be constructed. This framework has become the more important of +the two projects; reStructuredText_ has found its place as one +possible choice for a single component of the larger framework. + +The project web site and the first project release were rolled out in +June 2001, including posting the second draft of the spec [#spec-2]_ +and the first draft of PEPs 256, 257, and 258 [#peps-1]_ to the +Doc-SIG. These documents and the project implementation proceeded to +evolve at a rapid pace. Implementation history details can be found +in the `project history file`_. + +In November 2001, the reStructuredText parser was nearing completion. +Development of the parser continued with the addition of small +convenience features, improvements to the syntax, the filling in of +gaps, and bug fixes. After a long holiday break, in early 2002 most +development moved over to the other Docutils components, the +"Readers", "Writers", and "Transforms". A "standalone" reader +(processes standalone text file documents) was completed in February, +and a basic HTML writer (producing HTML 4.01, using CSS-1) was +completed in early March. + +`PEP 287`_, "reStructuredText Standard Docstring Format", was created +to formally propose reStructuredText as a standard format for Python +docstrings, PEPs, and other files. It was first posted to +comp.lang.python_ and the Python-dev_ mailing list on 2002-04-02. + +Version 0.4 of the reStructuredText__ and `Docstring Processing +System`_ projects were released in April 2002. The two projects were +immediately merged, renamed to "Docutils_", and a 0.1 release soon +followed. + +.. __: `reStructuredText SourceForge project`_ + +.. [#spec-2] The second draft of the spec: + + - `An Introduction to reStructuredText`__ + - `Problems With StructuredText`__ + - `reStructuredText Markup Specification`__ + - `Python Extensions to the reStructuredText Markup + Specification`__ + + __ https://mail.python.org/pipermail/doc-sig/2001-June/001858.html + __ https://mail.python.org/pipermail/doc-sig/2001-June/001859.html + __ https://mail.python.org/pipermail/doc-sig/2001-June/001860.html + __ https://mail.python.org/pipermail/doc-sig/2001-June/001861.html + +.. [#peps-1] First drafts of the PEPs: + + - `PEP 256: Docstring Processing System Framework`__ + - `PEP 258: DPS Generic Implementation Details`__ + - `PEP 257: Docstring Conventions`__ + + Current working versions of the PEPs can be found in + https://docutils.sourceforge.io/docs/peps/, and official versions + can be found in the `master PEP repository`_. + + __ https://mail.python.org/pipermail/doc-sig/2001-June/001855.html + __ https://mail.python.org/pipermail/doc-sig/2001-June/001856.html + __ https://mail.python.org/pipermail/doc-sig/2001-June/001857.html + + +.. _reStructuredText: https://docutils.sourceforge.io/rst.html +.. _StructuredText: https://zopestructuredtext.readthedocs.org/ +.. _Setext: https://docutils.sourceforge.io/mirror/setext.html +.. _Docutils: https://docutils.sourceforge.io/ +.. _Doc-SIG: https://www.python.org/sigs/doc-sig/ +.. _Zope Corporation: http://www.zope.com +.. _ZOPE: https://www.zope.dev +.. _reStructuredText SourceForge project: + http://structuredtext.sourceforge.net/ +.. _pythondoc: http://starship.python.net/crew/danilo/pythondoc/ +.. _project history file: ../../../HISTORY.html +.. _PEP 287: ../../peps/pep-0287.html +.. _Docstring Processing System framework: ../../peps/pep-0256.html +.. _comp.lang.python: news:comp.lang.python +.. _Python-dev: https://mail.python.org/pipermail/python-dev/ +.. _Docstring Processing System: http://docstring.sourceforge.net/ +.. _master PEP repository: https://peps.python.org/ Modified: trunk/docutils/docutils/utils/_roman_numerals.py =================================================================== --- trunk/docutils/docutils/utils/_roman_numerals.py 2024-10-04 12:21:52 UTC (rev 9945) +++ trunk/docutils/docutils/utils/_roman_numerals.py 2024-10-13 00:24:58 UTC (rev 9946) @@ -1,247 +1,247 @@ -# $Id$ -# Author: Adam Turner. -# Copyright: This module is placed in the public domain -# or under the `Zero Clause BSD licence`_, -# whichever is more permissive. -# -# .. _Zero Clause BSD licence: https://opensource.org/license/0BSD - -"""Conversion between integers and roman numerals.""" - -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING, final - -if TYPE_CHECKING: - from typing import Final, Self - -__all__ = ( - 'MIN', - 'MAX', - 'RomanNumeral', - 'OutOfRangeError', - 'InvalidRomanNumeralError', -) - -MIN: Final = 1 -"""The value of the smallest well-formed roman numeral.""" - -# Note that 4,999 (MMMMCMXCIX) breaks one of the rules of Roman numerals, -# that the same character may not appear more than thrice consecutively, -# meaning the largest 'well-formed' Roman numeral is 3,999 (MMMCMXCIX). -# We use 4,999 for backwards compatibility reasons. -MAX: Final = 4_999 -"""The value of the largest well-formed roman numeral.""" - - -class OutOfRangeError(TypeError): - """Number out of range (must be between 1 and 4,999).""" - - -class InvalidRomanNumeralError(ValueError): - """Not a valid Roman numeral.""" - - def __init__(self, value, *args): - msg = f'Invalid Roman numeral: {value}' - super().__init__(msg, *args) - - -@final -class RomanNumeral: - """A Roman numeral. - - Only values between 1 and 4,999 are valid. - Stores the value internally as an ``int``. - - >>> answer = RomanNumeral(42) - >>> print(answer.to_uppercase()) - XLII - """ - __slots__ = ('_value',) - _value: int - - def __init__(self, value: int, /) -> None: - if not isinstance(value, int): - msg = 'RomanNumeral: an integer is required, not %r' - raise TypeError(msg % type(value).__qualname__) - if value < MIN or value > MAX: - msg = 'Number out of range (must be between 1 and 4,999). Got %s.' - raise OutOfRangeError(msg % value) - super().__setattr__('_value', value) - - def __int__(self) -> int: - return self._value - - def __str__(self) -> str: - return self.to_uppercase() - - def __repr__(self): - return f'{self.__class__.__name__}({self._value!r})' - - def __eq__(self, other): - if isinstance(other, RomanNumeral): - return self._value == other._value - return NotImplemented - - def __lt__(self, other): - if isinstance(other, RomanNumeral): - return self._value < other._value - return NotImplemented - - def __hash__(self): - return hash(self._value) - - def __setattr__(self, key, value): - if key == '_value': - raise AttributeError('Cannot set the value attribute.') - super().__setattr__(key, value) - - def to_uppercase(self) -> str: - """Converts a ``RomanNumeral`` to an uppercase string. - - >>> answer = RomanNumeral(42) - >>> assert answer.to_uppercase() == 'XLII' - """ - out = [] - n = int(self) - for value, name, _ in _ROMAN_NUMERAL_PREFIXES: - while n >= value: - n -= value - out.append(name) - return ''.join(out) - - def to_lowercase(self) -> str: - """Converts a ``RomanNumeral`` to a lowercase string. - - >>> answer = RomanNumeral(42) - >>> assert answer.to_lowercase() == 'xlii' - """ - out = [] - n = int(self) - for value, _, name in _ROMAN_NUMERAL_PREFIXES: - while n >= value: - n -= value - out.append(name) - return ''.join(out) - - @classmethod - def from_string(self, string: str, /) -> Self: - """Creates a ``RomanNumeral`` from a well-formed string representation. - - Returns ``RomanNumeral`` or raises ``InvalidRomanNumeralError``. - - >>> answer = RomanNumeral.from_string('XLII') - >>> assert int(answer) == 42 - """ - # Not an empty string. - if not string or not isinstance(string, str): - raise InvalidRomanNumeralError(string) - - # ASCII-only uppercase string. - if string.isascii() and string.isupper(): - chars = string.encode('ascii') - elif string.isascii() and string.islower(): - chars = string.upper().encode('ascii') - else: - # Either Non-ASCII or mixed-case ASCII. - raise InvalidRomanNumeralError(string) - - # ASCII-only uppercase string only containing I, V, X, L, C, D, M. - if not frozenset(b'IVXLCDM').issuperset(chars): - raise InvalidRomanNumeralError(string) - - result: int = 0 - idx: int = 0 - - # Thousands: between 0 and 4 "M" characters at the start - for _ in range(4): - if chars[idx:idx + 1] == b'M': - result += 1000 - idx += 1 - else: - break - if len(chars) == idx: - return RomanNumeral(result) - - # Hundreds: 900 ("CM"), 400 ("CD"), 0-300 (0 to 3 "C" chars), - # or 500-800 ("D", followed by 0 to 3 "C" chars) - if chars[idx:idx + 2] == b'CM': - result += 900 - idx += 2 - elif chars[idx:idx + 2] == b'CD': - result += 400 - idx += 2 - else: - if chars[idx:idx + 1] == b'D': - result += 500 - idx += 1 - for _ in range(3): - if chars[idx:idx + 1] == b'C': - result += 100 - idx += 1 - else: - break - if len(chars) == idx: - return RomanNumeral(result) - - # Tens: 90 ("XC"), 40 ("XL"), 0-30 (0 to 3 "X" chars), - # or 50-80 ("L", followed by 0 to 3 "X" chars) - if chars[idx:idx + 2] == b'XC': - result += 90 - idx += 2 - elif chars[idx:idx + 2] == b'XL': - result += 40 - idx += 2 - else: - if chars[idx:idx + 1] == b'L': - result += 50 - idx += 1 - for _ in range(3): - if chars[idx:idx + 1] == b'X': - result += 10 - idx += 1 - else: - break - if len(chars) == idx: - return RomanNumeral(result) - - # Ones: 9 ("IX"), 4 ("IV"), 0-3 (0 to 3 "I" chars), - # or 5-8 ("V", followed by 0 to 3 "I" chars) - if chars[idx:idx + 2] == b'IX': - result += 9 - idx += 2 - elif chars[idx:idx + 2] == b'IV': - result += 4 - idx += 2 - else: - if chars[idx:idx + 1] == b'V': - result += 5 - idx += 1 - for _ in range(3): - if chars[idx:idx + 1] == b'I': - result += 1 - idx += 1 - else: - break - if len(chars) == idx: - return RomanNumeral(result) - raise InvalidRomanNumeralError(string) - - -_ROMAN_NUMERAL_PREFIXES: Final = [ - (1000, sys.intern('M'), sys.intern('m')), - (900, sys.intern('CM'), sys.intern('cm')), - (500, sys.intern('D'), sys.intern('d')), - (400, sys.intern('CD'), sys.intern('cd')), - (100, sys.intern('C'), sys.intern('c')), - (90, sys.intern('XC'), sys.intern('xc')), - (50, sys.intern('L'), sys.intern('l')), - (40, sys.intern('XL'), sys.intern('xl')), - (10, sys.intern('X'), sys.intern('x')), - (9, sys.intern('IX'), sys.intern('ix')), - (5, sys.intern('V'), sys.intern('v')), - (4, sys.intern('IV'), sys.intern('iv')), - (1, sys.intern('I'), sys.intern('i')), -] -"""Numeral value, uppercase character, and lowercase character.""" +# $Id$ +# Author: Adam Turner. +# Copyright: This module is placed in the public domain +# or under the `Zero Clause BSD licence`_, +# whichever is more permissive. +# +# .. _Zero Clause BSD licence: https://opensource.org/license/0BSD + +"""Conversion between integers and roman numerals.""" + +from __future__ import annotations + +import sys +from typing import TYPE_CHECKING, final + +if TYPE_CHECKING: + from typing import Final, Self + +__all__ = ( + 'MIN', + 'MAX', + 'RomanNumeral', + 'OutOfRangeError', + 'InvalidRomanNumeralError', +) + +MIN: Final = 1 +"""The value of the smallest well-formed roman numeral.""" + +# Note that 4,999 (MMMMCMXCIX) breaks one of the rules of Roman numerals, +# that the same character may not appear more than thrice consecutively, +# meaning the largest 'well-formed' Roman numeral is 3,999 (MMMCMXCIX). +# We use 4,999 for backwards compatibility reasons. +MAX: Final = 4_999 +"""The value of the largest well-formed roman numeral.""" + + +class OutOfRangeError(TypeError): + """Number out of range (must be between 1 and 4,999).""" + + +class InvalidRomanNumeralError(ValueError): + """Not a valid Roman numeral.""" + + def __init__(self, value, *args): + msg = f'Invalid Roman numeral: {value}' + super().__init__(msg, *args) + + +@final +class RomanNumeral: + """A Roman numeral. + + Only values between 1 and 4,999 are valid. + Stores the value internally as an ``int``. + + >>> answer = RomanNumeral(42) + >>> print(answer.to_uppercase()) + XLII + """ + __slots__ = ('_value',) + _value: int + + def __init__(self, value: int, /) -> None: + if not isinstance(value, int): + msg = 'RomanNumeral: an integer is required, not %r' + raise TypeError(msg % type(value).__qualname__) + if value < MIN or value > MAX: + msg = 'Number out of range (must be between 1 and 4,999). Got %s.' + raise OutOfRangeError(msg % value) + super().__setattr__('_value', value) + + def __int__(self) -> int: + return self._value + + def __str__(self) -> str: + return self.to_uppercase() + + def __repr__(self): + return f'{self.__class__.__name__}({self._value!r})' + + def __eq__(self, other): + if isinstance(other, RomanNumeral): + return self._value == other._value + return NotImplemented + + def __lt__(self, other): + if isinstance(other, RomanNumeral): + return self._value < other._value + return NotImplemented + + def __hash__(self): + return hash(self._value) + + def __setattr__(self, key, value): + if key == '_value': + raise AttributeError('Cannot set the value attribute.') + super().__setattr__(key, value) + + def to_uppercase(self) -> str: + """Converts a ``RomanNumeral`` to an uppercase string. + + >>> answer = RomanNumeral(42) + >>> assert answer.to_uppercase() == 'XLII' + """ + out = [] + n = int(self) + for value, name, _ in _ROMAN_NUMERAL_PREFIXES: + while n >= value: + n -= value + out.append(name) + return ''.join(out) + + def to_lowercase(self) -> str: + """Converts a ``RomanNumeral`` to a lowercase string. + + >>> answer = RomanNumeral(42) + >>> assert answer.to_lowercase() == 'xlii' + """ + out = [] + n = int(self) + for value, _, name in _ROMAN_NUMERAL_PREFIXES: + while n >= value: + n -= value + out.append(name) + return ''.join(out) + + @classmethod + def from_string(self, string: str, /) -> Self: + """Creates a ``RomanNumeral`` from a well-formed string representation. + + Returns ``RomanNumeral`` or raises ``InvalidRomanNumeralError``. + + >>> answer = RomanNumeral.from_string('XLII') + >>> assert int(answer) == 42 + """ + # Not an empty string. + if not string or not isinstance(string, str): + raise InvalidRomanNumeralError(string) + + # ASCII-only uppercase string. + if string.isascii() and string.isupper(): + chars = string.encode('ascii') + elif string.isascii() and string.islower(): + chars = string.upper().encode('ascii') + else: + # Either Non-ASCII or mixed-case ASCII. + raise InvalidRomanNumeralError(string) + + # ASCII-only uppercase string only containing I, V, X, L, C, D, M. + if not frozenset(b'IVXLCDM').issuperset(chars): + raise InvalidRomanNumeralError(string) + + result: int = 0 + idx: int = 0 + + # Thousands: between 0 and 4 "M" characters at the start + for _ in range(4): + if chars[idx:idx + 1] == b'M': + result += 1000 + idx += 1 + else: + break + if len(chars) == idx: + return RomanNumeral(result) + + # Hundreds: 900 ("CM"), 400 ("CD"), 0-300 (0 to 3 "C" chars), + # or 500-800 ("D", followed by 0 to 3 "C" chars) + if chars[idx:idx + 2] == b'CM': + result += 900 + idx += 2 + elif chars[idx:idx + 2] == b'CD': + result += 400 + idx += 2 + else: + if chars[idx:idx + 1] == b'D': + result += 500 + idx += 1 + for _ in range(3): + if chars[idx:idx + 1] == b'C': + result += 100 + idx += 1 + else: + break + if len(chars) == idx: + return RomanNumeral(result) + + # Tens: 90 ("XC"), 40 ("XL"), 0-30 (0 to 3 "X" chars), + # or 50-80 ("L", followed by 0 to 3 "X" chars) + if chars[idx:idx + 2] == b'XC': + result += 90 + idx += 2 + elif chars[idx:idx + 2] == b'XL': + result += 40 + idx += 2 + else: + if chars[idx:idx + 1] == b'L': + result += 50 + idx += 1 + for _ in range(3): + if chars[idx:idx + 1] == b'X': + result += 10 + idx += 1 + else: + break + if len(chars) == idx: + return RomanNumeral(result) + + # Ones: 9 ("IX"), 4 ("IV"), 0-3 (0 to 3 "I" chars), + # or 5-8 ("V", followed by 0 to 3 "I" chars) + if chars[idx:idx + 2] == b'IX': + result += 9 + idx += 2 + elif chars[idx:idx + 2] == b'IV': + result += 4 + idx += 2 + else: + if chars[idx:idx + 1] == b'V': + result += 5 + idx += 1 + for _ in range(3): + if chars[idx:idx + 1] == b'I': + result += 1 + idx += 1 + else: + break + if len(chars) == idx: + return RomanNumeral(result) + raise InvalidRomanNumeralError(string) + + +_ROMAN_NUMERAL_PREFIXES: Final = [ + (1000, sys.intern('M'), sys.intern('m')), + (900, sys.intern('CM'), sys.intern('cm')), + (500, sys.intern('D'), sys.intern('d')), + (400, sys.intern('CD'), sys.intern('cd')), + (100, sys.intern('C'), sys.intern('c')), + (90, sys.intern('XC'), sys.intern('xc')), + (50, sys.intern('L'), sys.intern('l')), + (40, sys.intern('XL'), sys.intern('xl')), + (10, sys.intern('X'), sys.intern('x')), + (9, sys.intern('IX'), sys.intern('ix')), + (5, sys.intern('V'), sys.intern('v')), + (4, sys.intern('IV'), sys.intern('iv')), + (1, sys.intern('I'), sys.intern('i')), +] +"""Numeral value, uppercase character, and lowercase character.""" Modified: trunk/docutils/licenses/BSD-0-Clause.rst =================================================================== --- trunk/docutils/licenses/BSD-0-Clause.rst 2024-10-04 12:21:52 UTC (rev 9945) +++ trunk/docutils/licenses/BSD-0-Clause.rst 2024-10-13 00:24:58 UTC (rev 9946) @@ -1,13 +1,13 @@ -Zero-Clause BSD -=============== - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE -FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +Zero-Clause BSD +=============== + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE +FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Modified: trunk/docutils/test/test_utils/test__roman_numerals.py =================================================================== --- trunk/docutils/test/test_utils/test__roman_numerals.py 2024-10-04 12:21:52 UTC (rev 9945) +++ trunk/docutils/test/test_utils/test__roman_numerals.py 2024-10-13 00:24:58 UTC (rev 9946) @@ -1,210 +1,210 @@ -#! /usr/bin/env python3 - -# $Id$ -# Author: Adam Turner. -# Copyright: This module is placed in the public domain -# or under the `Zero Clause BSD licence`_, -# whichever is more permissive. -# -# .. _Zero Clause BSD licence: https://opensource.org/license/0BSD - -""" -Tests for `docutils.utils._roman_numerals`. -""" - -from pathlib import Path -import sys -import unittest - -if __name__ == '__main__': - # prepend the "docutils root" to the Python library path - # so we import the local `docutils` package. - sys.path.insert(0, str(Path(__file__).resolve().parents[2])) - -from docutils.utils._roman_numerals import ( - MIN, - MAX, - RomanNumeral, - OutOfRangeError, - InvalidRomanNumeralError, -) - - -class NewRomanNumeralTestCase(unittest.TestCase): - def test_zero(self) -> None: - with self.assertRaises(OutOfRangeError) as ctx: - RomanNumeral(0) - msg = str(ctx.exception) - self.assertEqual( - msg, - 'Number out of range (must be between 1 and 4,999). Got 0.', - ) - - def test_one(self) -> None: - self.assertEqual(int(RomanNumeral(1)), 1) - - def test_MIN(self) -> None: - self.assertEqual(int(RomanNumeral(MIN)), MIN) - - def test_forty_two(self) -> None: - self.assertEqual(int(RomanNumeral(42)), 42) - - def test_four_thousand_nine_hundred_and_ninety_nine(self) -> None: - self.assertEqual(int(RomanNumeral(4_999)), 4_999) - - def test_MAX(self) -> None: - self.assertEqual(int(RomanNumeral(MAX)), MAX) - - def test_five_thousand(self) -> None: - with self.assertRaises(OutOfRangeError) as ctx: - RomanNumeral(5_000) - msg = str(ctx.exception) - self.assertEqual( - msg, - 'Number out of range (must be between 1 and 4,999). Got 5000.', - ) - - def test_minus_one(self) -> None: - with self.assertRaises(OutOfRangeError) as ctx: - RomanNumeral(-1) - msg = str(ctx.exception) - self.assertEqual( - msg, - 'Number out of range (must be between 1 and 4,999). Got -1.', - ) - - def test_float(self) -> None: - with self.assertRaises(TypeError) as ctx: - RomanNumeral(4.2) - msg = str(ctx.exception) - self.assertEqual( - msg, - "RomanNumeral: an integer is required, not 'float'", - ) - - -class ToStringTestCase(unittest.TestCase): - def test_str(self): - test_numerals = [ - 'I', 'II', 'III', 'IV', 'V', - 'VI', 'VII', 'VIII', 'IX', 'X', - 'XI', 'XII', 'XIII', 'XIV', 'XV', - 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', - 'XXI', 'XXII', 'XXIII', 'XXIV', - ] - for n, roman_str in enumerate(test_numerals, start=1): - with self.subTest(id=n, roman_str=roman_str): - num = RomanNumeral(n) - self.assertEqual(f'{num}', roman_str) - - def test_uppercase(self): - test_numerals = [ - 'I', 'II', 'III', 'IV', 'V', - 'VI', 'VII', 'VIII', 'IX', 'X', - 'XI', 'XII', 'XIII', 'XIV', 'XV', - 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', - 'XXI', 'XXII', 'XXIII', 'XXIV', - ] - for n, roman_str in enumerate(test_numerals, start=1): - with self.subTest(id=n, roman_str=roman_str): - num = RomanNumeral(n) - self.assertEqual(num.to_uppercase(), roman_str) - - def test_lowercase(self): - test_numerals = [ - 'i', 'ii', 'iii', 'iv', 'v', - 'vi', 'vii', 'viii', 'ix', 'x', - 'xi', 'xii', 'xiii', 'xiv', 'xv', - 'xvi', 'xvii', 'xviii', 'xix', 'xx', - 'xxi', 'xxii', 'xxiii', 'xxiv', - ] - for n, roman_str in enumerate(test_numerals, start=1): - with self.subTest(id=n, roman_str=roman_str): - num = RomanNumeral(n) - self.assertEqual(num.to_lowercase(), roman_str) - - def test_minitrue(self): - # IGNORANCE IS STRENGTH - num = RomanNumeral(1984) - self.assertEqual(f'{num}', 'MCMLXXXIV') - self.assertEqual(num.to_uppercase(), 'MCMLXXXIV') - self.assertEqual(num.to_lowercase(), 'mcmlxxxiv') - - -class FromStringTestCase(unittest.TestCase): - def test_uppercase(self): - test_numerals = [ - 'I', 'II', 'III', 'IV', 'V', - 'VI', 'VII', 'VIII', 'IX', 'X', - 'XI', 'XII', 'XIII', 'XIV', 'XV', - 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', - 'XXI', 'XXII', 'XXIII', 'XXIV', - ] - for n, roman_str in enumerate(test_numerals, start=1): - with self.subTest(id=n, roman_str=roman_str): - expected = RomanNumeral(n) - parsed = RomanNumeral.from_string(roman_str) - self.assertEqual(expected, parsed) - - def test_lowercase(self): - test_numerals = [ - 'i', 'ii', 'iii', 'iv', 'v', - 'vi', 'vii', 'viii', 'ix', 'x', - 'xi', 'xii', 'xiii', 'xiv', 'xv', - 'xvi', 'xvii', 'xviii', 'xix', 'xx', - 'xxi', 'xxii', 'xxiii', 'xxiv', - ] - for n, roman_str in enumerate(test_numerals, start=1): - with self.subTest(id=n, roman_str=roman_str): - expected = RomanNumeral(n) - parsed = RomanNumeral.from_string(roman_str) - self.assertEqual(expected, parsed) - - def test_special(self): - parsed = RomanNumeral.from_string('MDCCCXXIII') - self.assertEqual(RomanNumeral(1823), parsed) - - parsed = RomanNumeral.from_string('mdcccxxiii') - self.assertEqual(RomanNumeral(1823), parsed) - - parsed = RomanNumeral.from_string('MCMLXXXIV') - self.assertEqual(RomanNumeral(1984), parsed) - - parsed = RomanNumeral.from_string('mcmlxxxiv') - self.assertEqual(RomanNumeral(1984), parsed) - - parsed = RomanNumeral.from_string('MM') - self.assertEqual(RomanNumeral(2000), parsed) - - parsed = RomanNumeral.from_string('mm') - self.assertEqual(RomanNumeral(2000), parsed) - - parsed = RomanNumeral.from_string('MMMMCMXCIX') - self.assertEqual(RomanNumeral(4_999), parsed) - - parsed = RomanNumeral.from_string('mmmmcmxcix') - self.assertEqual(RomanNumeral(4_999), parsed) - - def test_invalid(self): - with self.assertRaises(InvalidRomanNumeralError) as ctx: - RomanNumeral.from_string('Not a Roman numeral!') - msg = str(ctx.exception) - self.assertEqual(msg, 'Invalid Roman numeral: Not a Roman numeral!') - - def test_mixed_case(self): - with self.assertRaises(InvalidRomanNumeralError) as ctx: - RomanNumeral.from_string('McMlXxXiV') - msg = str(ctx.exception) - self.assertEqual(msg, 'Invalid Roman numeral: McMlXxXiV') - - -class RoundTripTestCase(unittest.TestCase): - def test_round_trip(self): - for n in range(MIN, MAX + 1, 19): - num = RomanNumeral(n) - parsed = RomanNumeral.from_string(str(num)) - self.assertEqual(num, parsed) - - -if __name__ == '__main__': - unittest.main() +#! /usr/bin/env python3 + +# $Id$ +# Author: Adam Turner. +# Copyright: This module is placed in the public domain +# or under the `Zero Clause BSD licence`_, +# whichever is more permissive. +# +# .. _Zero Clause BSD licence: https://opensource.org/license/0BSD + +""" +Tests for `docutils.utils._roman_numerals`. +""" + +from pathlib import Path +import sys +import unittest + +if __name__ == '__main__': + # prepend the "docutils root" to the Python library path + # so we import the local `docutils` package. + sys.path.insert(0, str(Path(__file__).resolve().parents[2])) + +from docutils.utils._roman_numerals import ( + MIN, + MAX, + RomanNumeral, + OutOfRangeError, + InvalidRomanNumeralError, +) + + +class NewRomanNumeralTestCase(unittest.TestCase): + def test_zero(self) -> None: + with self.assertRaises(OutOfRangeError) as ctx: + RomanNumeral(0) + msg = str(ctx.exception) + self.assertEqual( + msg, + 'Number out of range (must be between 1 and 4,999). Got 0.', + ) + + def test_one(self) -> None: + self.assertEqual(int(RomanNumeral(1)), 1) + + def test_MIN(self) -> None: + self.assertEqual(int(RomanNumeral(MIN)), MIN) + + def test_forty_two(self) -> None: + self.assertEqual(int(RomanNumeral(42)), 42) + + def test_four_thousand_nine_hundred_and_ninety_nine(self) -> None: + self.assertEqual(int(RomanNumeral(4_999)), 4_999) + + def test_MAX(self) -> None: + self.assertEqual(int(RomanNumeral(MAX)), MAX) + + def test_five_thousand(self) -> None: + with self.assertRaises(OutOfRangeError) as ctx: + RomanNumeral(5_000) + msg = str(ctx.exception) + self.assertEqual( + msg, + 'Number out of range (must be between 1 and 4,999). Got 5000.', + ) + + def test_minus_one(self) -> None: + with self.assertRaises(OutOfRangeError) as ctx: + RomanNumeral(-1) + msg = str(ctx.exception) + self.assertEqual( + msg, + 'Number out of range (must be between 1 and 4,999). Got -1.', + ) + + def test_float(self) -> None: + with self.assertRaises(TypeError) as ctx: + RomanNumeral(4.2) + msg = str(ctx.exception) + self.assertEqual( + msg, + "RomanNumeral: an integer is required, not 'float'", + ) + + +class ToStringTestCase(unittest.TestCase): + def test_str(self): + test_numerals = [ + 'I', 'II', 'III', 'IV', 'V', + 'VI', 'VII', 'VIII', 'IX', 'X', + 'XI', 'XII', 'XIII', 'XIV', 'XV', + 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', + 'XXI', 'XXII', 'XXIII', 'XXIV', + ] + for n, roman_str in enumerate(test_numerals, start=1): + with self.subTest(id=n, roman_str=roman_str): + num = RomanNumeral(n) + self.assertEqual(f'{num}', roman_str) + + def test_uppercase(self): + test_numerals = [ + 'I', 'II', 'III', 'IV', 'V', + 'VI', 'VII', 'VIII', 'IX', 'X', + 'XI', 'XII', 'XIII', 'XIV', 'XV', + 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', + 'XXI', 'XXII', 'XXIII', 'XXIV', + ] + for n, roman_str in enumerate(test_numerals, start=1): + with self.subTest(id=n, roman_str=roman_str): + num = RomanNumeral(n) + self.assertEqual(num.to_uppercase(), roman_str) + + def test_lowercase(self): + test_numerals = [ + 'i', 'ii', 'iii', 'iv', 'v', + 'vi', 'vii', 'viii', 'ix', 'x', + 'xi', 'xii', 'xiii', 'xiv', 'xv', + 'xvi', 'xvii', 'xviii', 'xix', 'xx', + 'xxi', 'xxii', 'xxiii', 'xxiv', + ] + for n, roman_str in enumerate(test_numerals, start=1): + with self.subTest(id=n, roman_str=roman_str): + num = RomanNumeral(n) + self.assertEqual(num.to_lowercase(), roman_str) + + def test_minitrue(self): + # IGNORANCE IS STRENGTH + num = RomanNumeral(1984) + self.assertEqual(f'{num}', 'MCMLXXXIV') + self.assertEqual(num.to_uppercase(), 'MCMLXXXIV') + self.assertEqual(num.to_lowercase(), 'mcmlxxxiv') + + +class FromStringTestCase(unittest.TestCase): + def test_uppercase(self): + test_numerals = [ + 'I', 'II', 'III', 'IV', 'V', + 'VI', 'VII', 'VIII', 'IX', 'X', + 'XI', 'XII', 'XIII', 'XIV', 'XV', + 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', + 'XXI', 'XXII', 'XXIII', 'XXIV', + ] + for n, roman_str in enumerate(test_numerals, start=1): + with self.subTest(id=n, roman_str=roman_str): + expected = RomanNumeral(n) + parsed = RomanNumeral.from_string(roman_str) + self.assertEqual(expected, parsed) + + def test_lowercase(self): + test_numerals = [ + 'i', 'ii', 'iii', 'iv', 'v', + 'vi', 'vii', 'viii', 'ix', 'x', + 'xi', 'xii', 'xiii', 'xiv', 'xv', + 'xvi', 'xvii', 'xviii', 'xix', 'xx', + 'xxi', 'xxii', 'xxiii', 'xxiv', + ] + for n, roman_str in enumerate(test_numerals, start=1): + with self.subTest(id=n, roman_str=roman_str): + expected = RomanNumeral(n) + parsed = RomanNumeral.from_string(roman_str) + self.assertEqual(expected, parsed) + + def test_special(self): + parsed = RomanNumeral.from_string('MDCCCXXIII') + self.assertEqual(RomanNumeral(1823), parsed) + + parsed = RomanNumeral.from_string('mdcccxxiii') + self.assertEqual(RomanNumeral(1823), parsed) + + parsed = RomanNumeral.from_string('MCMLXXXIV') + self.assertEqual(RomanNumeral(1984), parsed) + + parsed = RomanNumeral.from_string('mcmlxxxiv') + self.assertEqual(RomanNumeral(1984), parsed) + + parsed = RomanNumeral.from_string('MM') + self.assertEqual(RomanNumeral(2000), parsed) + + parsed = RomanNumeral.from_string('mm') + self.assertEqual(RomanNumeral(2000), parsed) + + parsed = RomanNumeral.from_string('MMMMCMXCIX') + self.assertEqual(RomanNumeral(4_999), parsed) + + parsed = RomanNumeral.from_string('mmmmcmxcix') + self.assertEqual(RomanNumeral(4_999), parsed) + + def test_invalid(self): + with self.assertRaises(InvalidRomanNumeralError) as ctx: + RomanNumeral.from_string('Not a Roman numeral!') + msg = str(ctx.exception) + self.assertEqual(msg, 'Invalid Roman numeral: Not a Roman numeral!') + + def test_mixed_case(self): + with self.assertRaises(InvalidRomanNumeralError) as ctx: + RomanNumeral.from_string('McMlXxXiV') + msg = str(ctx.exception) + self.assertEqual(msg, 'Invalid Roman numeral: McMlXxXiV') + + +class RoundTripTestCase(unittest.TestCase): + def test_round_trip(self): + for n in range(MIN, MAX + 1, 19): + num = RomanNumeral(n) + parsed = RomanNumeral.from_string(str(num)) + self.assertEqual(num, parsed) + + +if __name__ == '__main__': + unittest.main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-10-13 12:36:17
|
Revision: 9947 http://sourceforge.net/p/docutils/code/9947 Author: milde Date: 2024-10-13 12:36:14 +0000 (Sun, 13 Oct 2024) Log Message: ----------- "include" directive: handle duplicate names and IDs in sub-documents When the :parser: option is specified, the included file is parsed into a dummy `<document>` and children are appended. Let internal bookkeeping attributes reference the main document equivalents, so that element names and IDs share a namespace with the including document. Modified Paths: -------------- trunk/docutils/docs/ref/rst/directives.rst trunk/docutils/docs/user/config.rst trunk/docutils/docutils/parsers/rst/directives/misc.py trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py Added Paths: ----------- trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include.xml Removed Paths: ------------- trunk/docutils/test/data/duplicate-id.xml Modified: trunk/docutils/docs/ref/rst/directives.rst =================================================================== --- trunk/docutils/docs/ref/rst/directives.rst 2024-10-13 00:24:58 UTC (rev 9946) +++ trunk/docutils/docs/ref/rst/directives.rst 2024-10-13 12:36:14 UTC (rev 9947) @@ -1603,6 +1603,10 @@ Parse the included content with the specified parser. See the `"parser" configuration setting`_ for available parsers. + .. Caution:: + There is is no check whether the inserted elements are valid at the + point of insertion. It is recommended to validate_ the document. + (New in Docutils 0.17) ``start-after`` : text_ @@ -2273,6 +2277,7 @@ .. _"title" configuration setting: ../../user/config.html#title .. _toc_backlinks: ../../user/config.html#toc-backlinks .. _use_latex_toc: ../../user/config.html#use-latex-toc +.. _validate: ../../user/config.html#validate .. _reStructuredText Standard Definition Files: definitions.html Modified: trunk/docutils/docs/user/config.rst =================================================================== --- trunk/docutils/docs/user/config.rst 2024-10-13 00:24:58 UTC (rev 9946) +++ trunk/docutils/docs/user/config.rst 2024-10-13 12:36:14 UTC (rev 9947) @@ -672,10 +672,12 @@ List of "classes" attribute values (comma-separated_). Values are appended. [#append-values]_ -Matching elements are removed from the `document tree`_. +Matching elements are removed from the `document tree`_ +(by the `StripClassesAndElements` transform_). .. WARNING:: Potentially dangerous: may lead to an invalid document tree and subsequent writer errors. Use with caution. + It is recommended to validate_ the document. *Default*: empty list. *Option*: ``--strip-elements-with-class``. @@ -777,7 +779,9 @@ validate -------- -Validate the parsing result. +Validate the parsing result. Report elements that do not comply +with the restrictions set out in the `Docutils Generic document +type definition`_. *Default*: False. *Options*: ``--validate``, ``--no-validation``. @@ -2497,6 +2501,7 @@ .. References +.. _Docutils Generic document type definition: .. _Docutils Document Tree: .. _Document Tree: ../ref/doctree.html @@ -2507,6 +2512,8 @@ .. _publish_string(): ../api/publisher.html#publish-string .. _publish_from_doctree(): ../api/publisher.html#publish-from-doctree +.. _transform: ../api/transforms.html + .. _severity level: ../peps/pep-0258.html#error-handling .. RestructuredText Directives Modified: trunk/docutils/docutils/parsers/rst/directives/misc.py =================================================================== --- trunk/docutils/docutils/parsers/rst/directives/misc.py 2024-10-13 00:24:58 UTC (rev 9946) +++ trunk/docutils/docutils/parsers/rst/directives/misc.py 2024-10-13 12:36:14 UTC (rev 9947) @@ -217,6 +217,9 @@ settings._source = self.options['source'] document = utils.new_document(settings._source, settings) document.include_log = self.state.document.include_log + document.ids = self.state.document.ids + document.nameids = self.state.document.nameids + document.nametypes = self.state.document.nametypes parser = self.options['parser']() parser.parse(text, document) self.state.document.parse_messages.extend(document.parse_messages) Deleted: trunk/docutils/test/data/duplicate-id.xml =================================================================== --- trunk/docutils/test/data/duplicate-id.xml 2024-10-13 00:24:58 UTC (rev 9946) +++ trunk/docutils/test/data/duplicate-id.xml 2024-10-13 12:36:14 UTC (rev 9947) @@ -1,5 +0,0 @@ -<section> - <title ids="s4">nice heading</title> - <paragraph>Text with <strong ids="s4">strong - statement</strong> and more text.</paragraph> -</section> Added: trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include.xml =================================================================== --- trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include.xml (rev 0) +++ trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include.xml 2024-10-13 12:36:14 UTC (rev 9947) @@ -0,0 +1,5 @@ +<section> + <title names="nice\ heading">nice heading</title> + <paragraph>Text with <strong ids="common-id">strong + statement</strong> and more text.</paragraph> +</section> Property changes on: trunk/docutils/test/test_parsers/test_rst/test_directives/includes/include.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Modified: trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py =================================================================== --- trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py 2024-10-13 00:24:58 UTC (rev 9946) +++ trunk/docutils/test/test_parsers/test_rst/test_directives/test_include.py 2024-10-13 12:36:14 UTC (rev 9947) @@ -17,7 +17,7 @@ # so we import the local `docutils` package. sys.path.insert(0, str(Path(__file__).resolve().parents[4])) -from docutils import parsers, utils +from docutils import core, parsers, utils from docutils.frontend import get_default_settings from docutils.parsers.rst import Parser from docutils.utils import new_document @@ -25,12 +25,11 @@ from test.test_parsers.test_rst.test_directives.test_code \ import PYGMENTS_2_14_PLUS +FILE_DIR = Path(__file__).resolve().parent +TEST_ROOT = FILE_DIR.parents[2] -TEST_ROOT = Path(__file__).resolve().parents[3] - - # optional 3rd-party markdown parser -md_parser_name = 'recommonmark' +md_parser_name = 'pycmark' try: # check availability md_parser_class = parsers.get_parser_class(md_parser_name) except ImportError: @@ -52,6 +51,8 @@ settings.warning_stream = '' settings.halt_level = 5 for name, cases in totest.items(): + if name == 'with transforms': + continue # see test_publish() below for casenum, (case_input, case_expected) in enumerate(cases): with self.subTest(id=f'totest[{name!r}][{casenum}]'): document = new_document('test data', settings.copy()) @@ -59,7 +60,23 @@ output = document.pformat() self.assertEqual(case_expected, output) + def test_publish(self): + # Special case for tests of issue reporting. + # To see the system message from the duplicate id, we need transforms. + settings = {'_disable_config': True, + 'output_encoding': 'unicode', + 'warning_stream': '', + } + name = 'with transforms' + for casenum, (sample, expected) in enumerate(totest[name]): + with self.subTest(id=f'totest[{name!r}][{casenum}]'): + output = core.publish_string(sample, + source_path='test data', + parser=Parser(), + settings_overrides=settings) + self.assertEqual(expected, output) + try: chr(0x11111111) except ValueError as detail: @@ -68,11 +85,10 @@ unichr_exception = '' -# prepend this directory (relative to the test root): +# prepend this directory (relative to the cwd): def mydir(path): - return os.path.relpath( - os.path.join(TEST_ROOT, 'test_parsers/test_rst/test_directives', path), - os.getcwd()).replace('\\', '/') + return os.path.relpath(os.path.join(FILE_DIR, path), + os.getcwd()).replace('\\', '/') include1 = mydir('include1.rst') @@ -90,7 +106,7 @@ include16 = mydir('includes/include16.rst') include_literal = mydir('include_literal.rst') include_md = mydir('include.md') -include_xml = TEST_ROOT/'data/duplicate-id.xml' +include_xml = mydir('includes/include.xml') include = TEST_ROOT/'data/include.rst' latin2 = TEST_ROOT/'data/latin2.rst' utf_16_file = TEST_ROOT/'data/utf-16-le-sig.rst' @@ -833,6 +849,33 @@ .. end of inclusion from "{include10}" """], [f"""\ +Inclusion 1 +=========== +Name clash: The included file uses the same section title. + +.. include:: {include1} + :parser: rst +""", +f"""\ +<document source="test data"> + <section dupnames="inclusion\\ 1" ids="inclusion-1"> + <title> + Inclusion 1 + <paragraph> + Name clash: The included file uses the same section title. + <section dupnames="inclusion\\ 1" ids="inclusion-1-1"> + <title> + Inclusion 1 + <system_message backrefs="inclusion-1-1" level="1" line="2" source="{include1}" type="INFO"> + <paragraph> + Duplicate implicit target name: "inclusion 1". + <paragraph> + This file is used by \n\ + <literal> + test_include.py + . +"""], +[f"""\ Include file with whitespace in the path: .. include:: {include11} @@ -1465,32 +1508,6 @@ File "include15.rst": example of rekursive inclusion. """], [f"""\ -Include Docutils XML file: - -.. include:: {include_xml} - :parser: xml - -The duplicate id is reported and would be appended -by the "universal.Messages" transform. -""", -"""\ -<document source="test data"> - <paragraph> - Include Docutils XML file: - <section> - <title ids="s4"> - nice heading - <paragraph> - Text with \n\ - <strong ids="s4"> - strong - statement - and more text. - <paragraph> - The duplicate id is reported and would be appended - by the "universal.Messages" transform. -"""], -[f"""\ No circular inclusion. .. list-table:: @@ -1531,7 +1548,7 @@ <document source="test data"> <paragraph> Include Markdown source. - <section ids="title-1" names="title\\ 1"> + <section depth="1" ids="section-1"> <title> Title 1 <paragraph> @@ -1542,14 +1559,88 @@ also emphasis <paragraph> No whitespace required around a - <reference name="phrase reference" refuri="/uri"> + <reference refuri="/uri"> phrase reference . + <target ids="phrase-reference" names="phrase\\ reference" refuri="/uri"> <paragraph> A paragraph. """], ] +# Transforms are required for these tests: The system_message about +# duplicate name/id is appended by the "universal.Messages" transform. +totest['with transforms'] = [ +[f"""\ +.. _common id: +Include Docutils XML file: + +.. include:: {include_xml} + :parser: xml +""", +f"""\ +<document source="test data"> + <target refid="common-id"> + <paragraph ids="common-id" names="common\\ id"> + Include Docutils XML file: + <section> + <title names="nice\\ heading"> + nice heading + <paragraph> + Text with \n\ + <strong ids="common-id"> + strong + statement + and more text. + <section classes="system-messages"> + <title> + Docutils System Messages + <system_message level="3" line="3" source="{include_xml}" type="ERROR"> + <paragraph> + Duplicate ID: "common-id" used by <target ids="common-id" names="common\\ id"> and <strong ids="common-id"> +"""], +[f"""\ +Inclusion 1 +=========== +Name clash: The included file uses the same section title `inclusion 1`_. + +.. include:: {include1} + :parser: rst + +Inclusion 2 +=========== +""", +"""\ +<document source="test data"> + <section dupnames="inclusion\\ 1" ids="inclusion-1"> + <title> + Inclusion 1 + <paragraph> + Name clash: The included file uses the same section title \n\ + <problematic ids="problematic-1" refid="system-message-1"> + `inclusion 1`_ + . + <section dupnames="inclusion\\ 1" ids="inclusion-1-1"> + <title> + Inclusion 1 + <paragraph> + This file is used by \n\ + <literal> + test_include.py + . + <section ids="inclusion-2" names="inclusion\\ 2"> + <title> + Inclusion 2 + <section classes="system-messages"> + <title> + Docutils System Messages + <system_message backrefs="problematic-1" ids="system-message-1" level="3" line="3" source="test data" type="ERROR"> + <paragraph> + Duplicate target name, cannot be used as a unique reference: "inclusion 1". +"""], +] + + if __name__ == '__main__': unittest.main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-10-13 12:40:48
|
Revision: 9948 http://sourceforge.net/p/docutils/code/9948 Author: milde Date: 2024-10-13 12:40:46 +0000 (Sun, 13 Oct 2024) Log Message: ----------- Downgrade "duplicate ID" message from "serious" to "error". A duplicate ID is not a critical error where the output will inevitably contain severe errors but rather "a major issue that should adressed. If ignored, the output will contain unpredictable errors." (cf. :PEP:`0258` Error Handling). Re-use `nodes.document.set_id()` in the XML parser, but only for registering an existing ID, do not generate IDs. Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/docutils/nodes.py trunk/docutils/docutils/parsers/docutils_xml.py Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-10-13 12:36:14 UTC (rev 9947) +++ trunk/docutils/HISTORY.rst 2024-10-13 12:40:46 UTC (rev 9948) @@ -65,6 +65,7 @@ raise ValueError for invalid attribute names or values. - New function `parse_measure()`. - Removed `Element.set_class()`. + - Downgrade "duplicate ID" message level from SERIOUS to ERROR. * docutils/parsers/docutils_xml.py Modified: trunk/docutils/docutils/nodes.py =================================================================== --- trunk/docutils/docutils/nodes.py 2024-10-13 12:36:14 UTC (rev 9947) +++ trunk/docutils/docutils/nodes.py 2024-10-13 12:40:46 UTC (rev 9948) @@ -1869,7 +1869,10 @@ for id in node['ids']: self.ids.setdefault(id, node) if self.ids[id] is not node: - msg = self.reporter.severe('Duplicate ID: "%s".' % id) + msg = self.reporter.error(f'Duplicate ID: "{id}" used by ' + f'{self.ids[id].starttag()} ' + f'and {node.starttag()}', + base_node=node) if msgnode is not None: msgnode += msg return id Modified: trunk/docutils/docutils/parsers/docutils_xml.py =================================================================== --- trunk/docutils/docutils/parsers/docutils_xml.py 2024-10-13 12:36:14 UTC (rev 9947) +++ trunk/docutils/docutils/parsers/docutils_xml.py 2024-10-13 12:40:46 UTC (rev 9948) @@ -151,14 +151,8 @@ if key in node.list_attributes: value = value.split() node.attributes[key] = value # node becomes invalid! - # register ids, check for duplicates - for id in node['ids']: - document.ids.setdefault(id, node) - if document.ids[id] is not node: - document.reporter.error(f'Duplicate ID: "{id}" used by ' - f'{document.ids[id].starttag()} ' - f'and {node.starttag()}', - base_node=node) + if node['ids']: # register, check for duplicates + document.set_id(node) # Append content: # update "unindent" flag: change line indentation? This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-10-13 13:44:26
|
Revision: 9949 http://sourceforge.net/p/docutils/code/9949 Author: milde Date: 2024-10-13 13:44:24 +0000 (Sun, 13 Oct 2024) Log Message: ----------- Add internal source and line attributes to more nodes. The rST parser now also adds internal source and line attributes to `<compound>`, `<container>`, `<sidebar>`, `<topic>`, `<line_block>`, and `<line>` nodes. Based on a pull request by Rob Taylor (on the github mirror) but adding source and line info instead of the "raw" line number to account for source parts included with the "include" directive, also fixing line blocks (both directive and via line-block syntax), and adding a test case. See also [feature-requests:#41]. Modified Paths: -------------- trunk/docutils/docutils/parsers/rst/directives/body.py trunk/docutils/docutils/parsers/rst/states.py trunk/docutils/test/test_parsers/test_rst/test_source_line.py Modified: trunk/docutils/docutils/parsers/rst/directives/body.py =================================================================== --- trunk/docutils/docutils/parsers/rst/directives/body.py 2024-10-13 12:40:46 UTC (rev 9948) +++ trunk/docutils/docutils/parsers/rst/directives/body.py 2024-10-13 13:44:24 UTC (rev 9949) @@ -54,6 +54,8 @@ text = '\n'.join(self.content) node = self.node_class(text, *(titles + messages)) node['classes'] += self.options.get('class', []) + (node.source, + node.line) = self.state_machine.get_source_and_line(self.lineno) self.add_name(node) if text: self.state.nested_parse(self.content, self.content_offset, node) @@ -86,7 +88,12 @@ class LineBlock(Directive): + """Legacy directive for line blocks. + Use is deprecated in favour of the line block syntax, + cf. `parsers.rst.states.Body.line_block()`. + """ + option_spec = {'class': directives.class_option, 'name': directives.unchanged} has_content = True @@ -94,12 +101,16 @@ def run(self): self.assert_has_content() block = nodes.line_block(classes=self.options.get('class', [])) + (block.source, + block.line) = self.state_machine.get_source_and_line(self.lineno) self.add_name(block) node_list = [block] - for line_text in self.content: + for i, line_text in enumerate(self.content): text_nodes, messages = self.state.inline_text( line_text.strip(), self.lineno + self.content_offset) line = nodes.line(line_text, '', *text_nodes) + line.source = block.source + line.line = block.line + i if line_text.strip(): line.indent = len(line_text) - len(line_text.lstrip()) block += line @@ -274,6 +285,8 @@ text = '\n'.join(self.content) node = nodes.compound(text) node['classes'] += self.options.get('class', []) + (node.source, + node.line) = self.state_machine.get_source_and_line(self.lineno) self.add_name(node) self.state.nested_parse(self.content, self.content_offset, node) return [node] @@ -300,6 +313,8 @@ % (self.name, self.arguments[0])) node = nodes.container(text) node['classes'].extend(classes) + (node.source, + node.line) = self.state_machine.get_source_and_line(self.lineno) self.add_name(node) self.state.nested_parse(self.content, self.content_offset, node) return [node] Modified: trunk/docutils/docutils/parsers/rst/states.py =================================================================== --- trunk/docutils/docutils/parsers/rst/states.py 2024-10-13 12:40:46 UTC (rev 9948) +++ trunk/docutils/docutils/parsers/rst/states.py 2024-10-13 13:44:24 UTC (rev 9949) @@ -632,7 +632,7 @@ URIs) is found last. :text: source string - :lineno: absolute line number (cf. statemachine.get_source_and_line()) + :lineno: absolute line number, cf. `statemachine.get_source_and_line()` """ self.reporter = memo.reporter self.document = memo.document @@ -1599,6 +1599,8 @@ block = nodes.line_block() self.parent += block lineno = self.state_machine.abs_line_number() + (block.source, + block.line) = self.state_machine.get_source_and_line(lineno) line, messages, blank_finish = self.line_block_line(match, lineno) block += line self.parent += messages @@ -1628,6 +1630,8 @@ text = '\n'.join(indented) text_nodes, messages = self.inline_text(text, lineno) line = nodes.line(text, '', *text_nodes) + (line.source, + line.line) = self.state_machine.get_source_and_line(lineno) if match.string.rstrip() != '|': # not empty line.indent = len(match.group(1)) - 1 return line, messages, blank_finish Modified: trunk/docutils/test/test_parsers/test_rst/test_source_line.py =================================================================== --- trunk/docutils/test/test_parsers/test_rst/test_source_line.py 2024-10-13 12:40:46 UTC (rev 9948) +++ trunk/docutils/test/test_parsers/test_rst/test_source_line.py 2024-10-13 13:44:24 UTC (rev 9949) @@ -271,6 +271,67 @@ <paragraph internal:line="10" internal:source="test data"> Final paragraph in line 10 """], +["""\ +Paragraph + +.. sidebar:: + + .. compound:: + paragraph at line 6 + + | line block, + first line + | line block, second line at line 10 + | indented + line + + .. line-block:: line block at line 14 + with legacy directive + + continuation at line 17 + +.. topic:: topic title at line 19 + + .. container:: + + container content at line 23 + +Final paragraph at line 25 +""", +"""\ +<document source="test data"> + <paragraph internal:line="1" internal:source="test data"> + Paragraph + <sidebar internal:line="3" internal:source="test data"> + <compound internal:line="5" internal:source="test data"> + <paragraph internal:line="6" internal:source="test data"> + paragraph at line 6 + <line_block internal:line="8" internal:source="test data"> + <line internal:line="8" internal:source="test data"> + line block, + first line + <line internal:line="10" internal:source="test data"> + line block, second line at line 10 + <line_block> + <line internal:line="11" internal:source="test data"> + indented + line + <line_block internal:line="14" internal:source="test data"> + <line internal:line="14" internal:source="test data"> + line block at line 14 + <line internal:line="15" internal:source="test data"> + with legacy directive + <paragraph internal:line="17" internal:source="test data"> + continuation at line 17 + <topic internal:line="19" internal:source="test data"> + <title> + topic title at line 19 + <container internal:line="21" internal:source="test data"> + <paragraph internal:line="23" internal:source="test data"> + container content at line 23 + <paragraph internal:line="25" internal:source="test data"> + Final paragraph at line 25 +"""], ]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-10-15 11:24:34
|
Revision: 9950 http://sourceforge.net/p/docutils/code/9950 Author: milde Date: 2024-10-15 11:24:32 +0000 (Tue, 15 Oct 2024) Log Message: ----------- Allow transient elements `<target>` and `<pending>` before a figure `<caption>`. In rST, the "figure" directive's content must start with a paragraph (that becomes the caption) or an empty comment (to get a legend without caption). The change allows passing a "classes" or "names" attribute value to the figure caption via the "class" directive rsp. an internal hyperlink target. Change the `references.PropagateTargets` transform to remove a `<target>` element followed by a `<caption>` (after propagating ids and names) to keep the doctree valid. Fix the HTML5 writer, to apply the attributes to the `<figcaption>` element, (instead of the included `<p>`). Fix LaTeX writer to handle "classes" and "ids" attributes of a `<caption>` element. Add test cases. Remove misleading test case. Figures without caption are invalid and won't get a "Figure 1."-style caption with the Docutils writers. Modified Paths: -------------- trunk/docutils/docutils/parsers/rst/directives/images.py trunk/docutils/docutils/transforms/references.py trunk/docutils/docutils/writers/html5_polyglot/__init__.py trunk/docutils/docutils/writers/latex2e/__init__.py trunk/docutils/test/functional/expected/latex_memoir.tex trunk/docutils/test/functional/expected/standalone_rst_docutils_xml.xml trunk/docutils/test/functional/expected/standalone_rst_html4css1.html trunk/docutils/test/functional/expected/standalone_rst_html5.html trunk/docutils/test/functional/expected/standalone_rst_latex.tex trunk/docutils/test/functional/expected/standalone_rst_pseudoxml.txt trunk/docutils/test/functional/expected/standalone_rst_xetex.tex trunk/docutils/test/functional/input/data/standard.rst trunk/docutils/test/functional/tests/standalone_rst_docutils_xml.py trunk/docutils/test/test_parsers/test_rst/test_directives/test_figures.py Modified: trunk/docutils/docutils/parsers/rst/directives/images.py =================================================================== --- trunk/docutils/docutils/parsers/rst/directives/images.py 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/docutils/parsers/rst/directives/images.py 2024-10-15 11:24:32 UTC (rev 9950) @@ -152,22 +152,29 @@ if align: figure_node['align'] = align if self.content: + # optional caption (single paragraph or empty comment) + # + optional legend (arbitrary body elements). node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) - first_node = node[0] - if isinstance(first_node, nodes.paragraph): - caption = nodes.caption(first_node.rawsource, '', - *first_node.children) - caption.source = first_node.source - caption.line = first_node.line - figure_node += caption - elif not (isinstance(first_node, nodes.comment) - and len(first_node) == 0): + for i, child in enumerate(node): + # skip temporary nodes that will be removed by transforms + if isinstance(child, (nodes.target, nodes.pending)): + figure_node += child + continue + if isinstance(child, nodes.paragraph): + caption = nodes.caption(child.rawsource, '', + *child.children) + caption.source = child.source + caption.line = child.line + figure_node += caption + break + if isinstance(child, nodes.comment) and len(child) == 0: + break error = self.reporter.error( - 'Figure caption must be a paragraph or empty comment.', - nodes.literal_block(self.block_text, self.block_text), - line=self.lineno) + 'Figure caption must be a paragraph or empty comment.', + nodes.literal_block(self.block_text, self.block_text), + line=self.lineno) return [figure_node, error] - if len(node) > 1: - figure_node += nodes.legend('', *node[1:]) + if len(node) > i+1: + figure_node += nodes.legend('', *node[i+1:]) return [figure_node] Modified: trunk/docutils/docutils/transforms/references.py =================================================================== --- trunk/docutils/docutils/transforms/references.py 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/docutils/transforms/references.py 2024-10-15 11:24:32 UTC (rev 9950) @@ -76,11 +76,15 @@ getattr(target, 'expect_referenced_by_name', {})) next_node.expect_referenced_by_id.update( getattr(target, 'expect_referenced_by_id', {})) + # Remove target node from places where it is invalid. + if isinstance(target.parent, nodes.figure) and isinstance( + next_node, nodes.caption): + target.parent.remove(target) + continue # Set refid to point to the first former ID of target # which is now an ID of next_node. target['refid'] = target['ids'][0] - # Clear ids and names; they have been moved to - # next_node. + # Clear ids and names; they have been moved to next_node. target['ids'] = [] target['names'] = [] self.document.note_refid(target) Modified: trunk/docutils/docutils/writers/html5_polyglot/__init__.py =================================================================== --- trunk/docutils/docutils/writers/html5_polyglot/__init__.py 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/docutils/writers/html5_polyglot/__init__.py 2024-10-15 11:24:32 UTC (rev 9950) @@ -150,8 +150,8 @@ # use the <figcaption> semantic tag. def visit_caption(self, node) -> None: if isinstance(node.parent, nodes.figure): - self.body.append('<figcaption>\n') - self.body.append(self.starttag(node, 'p', '')) + self.body.append(self.starttag(node, 'figcaption')) + self.body.append('<p>') def depart_caption(self, node) -> None: self.body.append('</p>\n') @@ -275,7 +275,7 @@ # place inside HTML5 <figcaption> element (together with caption) def visit_legend(self, node) -> None: - if not isinstance(node.parent[1], nodes.caption): + if not isinstance(node.previous_sibling(), nodes.caption): self.body.append('<figcaption>\n') self.body.append(self.starttag(node, 'div', CLASS='legend')) Modified: trunk/docutils/docutils/writers/latex2e/__init__.py =================================================================== --- trunk/docutils/docutils/writers/latex2e/__init__.py 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/docutils/writers/latex2e/__init__.py 2024-10-15 11:24:32 UTC (rev 9950) @@ -1794,8 +1794,11 @@ def visit_caption(self, node) -> None: self.out.append('\n\\caption{') + self.out += self.ids_to_labels(node, set_anchor=False) + self.visit_inline(node) def depart_caption(self, node) -> None: + self.depart_inline(node) self.out.append('}\n') def visit_title_reference(self, node) -> None: Modified: trunk/docutils/test/functional/expected/latex_memoir.tex =================================================================== --- trunk/docutils/test/functional/expected/latex_memoir.tex 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/expected/latex_memoir.tex 2024-10-15 11:24:32 UTC (rev 9950) @@ -913,7 +913,7 @@ \begin{DUclass}{figclass2} \begin{figure} % align = "left" \noindent\makebox[\linewidth][c]{\includegraphics[width=40px]{../../../docs/user/rst/images/biohazard.png}} -\caption{This is the caption.} +\caption{\label{caption-label}\DUrole{captionclass1}{\DUrole{captionclass2}{This is the caption.}}} \begin{DUlegend} This is the legend. Modified: trunk/docutils/test/functional/expected/standalone_rst_docutils_xml.xml =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_docutils_xml.xml 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/expected/standalone_rst_docutils_xml.xml 2024-10-15 11:24:32 UTC (rev 9950) @@ -889,7 +889,7 @@ <paragraph>A left-aligned figure, 70% wide:</paragraph> <figure align="left" classes="figclass1 figclass2" width="70%"> <image alt="reStructuredText, the markup syntax" classes="class1 class2" uri="../../../docs/user/rst/images/biohazard.png" width="40px"></image> - <caption>This is the caption.</caption> + <caption classes="captionclass1 captionclass2" ids="caption-label" names="caption-label">This is the caption.</caption> <legend> <paragraph>This is the legend.</paragraph> <paragraph>The legend may consist of several paragraphs.</paragraph> Modified: trunk/docutils/test/functional/expected/standalone_rst_html4css1.html =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_html4css1.html 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/expected/standalone_rst_html4css1.html 2024-10-15 11:24:32 UTC (rev 9950) @@ -643,7 +643,7 @@ <p>A left-aligned figure, 70% wide:</p> <div class="figclass1 figclass2 figure align-left" style="width: 70%"> <img alt="reStructuredText, the markup syntax" class="class1 class2" src="../../../docs/user/rst/images/biohazard.png" style="width: 40px;" /> -<p class="caption">This is the caption.</p> +<p class="captionclass1 captionclass2 caption" id="caption-label">This is the caption.</p> <div class="legend"> <p>This is the legend.</p> <p>The legend may consist of several paragraphs.</p> Modified: trunk/docutils/test/functional/expected/standalone_rst_html5.html =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_html5.html 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/expected/standalone_rst_html5.html 2024-10-15 11:24:32 UTC (rev 9950) @@ -638,7 +638,7 @@ <p>A left-aligned figure, 70% wide:</p> <figure class="figclass1 figclass2 align-left" style="width: 70%"> <img alt="reStructuredText, the markup syntax" class="class1 class2" src="../../../docs/user/rst/images/biohazard.png" style="width: 40px;" /> -<figcaption> +<figcaption class="captionclass1 captionclass2" id="caption-label"> <p>This is the caption.</p> <div class="legend"> <p>This is the legend.</p> Modified: trunk/docutils/test/functional/expected/standalone_rst_latex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2024-10-15 11:24:32 UTC (rev 9950) @@ -915,7 +915,7 @@ \begin{DUclass}{figclass2} \begin{figure} % align = "left" \noindent\makebox[\linewidth][c]{\includegraphics[width=40px]{../../../docs/user/rst/images/biohazard.png}} -\caption{This is the caption.} +\caption{\label{caption-label}\DUrole{captionclass1}{\DUrole{captionclass2}{This is the caption.}}} \begin{DUlegend} This is the legend. Modified: trunk/docutils/test/functional/expected/standalone_rst_pseudoxml.txt =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_pseudoxml.txt 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/expected/standalone_rst_pseudoxml.txt 2024-10-15 11:24:32 UTC (rev 9950) @@ -1374,7 +1374,7 @@ A left-aligned figure, 70% wide: <figure align="left" classes="figclass1 figclass2" width="70%"> <image alt="reStructuredText, the markup syntax" classes="class1 class2" uri="../../../docs/user/rst/images/biohazard.png" width="40px"> - <caption> + <caption classes="captionclass1 captionclass2" ids="caption-label" names="caption-label"> This is the caption. <legend> <paragraph> @@ -2425,15 +2425,15 @@ <system_message level="1" line="476" source="functional/input/data/standard.rst" type="INFO"> <paragraph> Hyperlink target "image-target-3" is not referenced. - <system_message level="1" line="640" source="functional/input/data/standard.rst" type="INFO"> + <system_message level="1" line="643" source="functional/input/data/standard.rst" type="INFO"> <paragraph> Hyperlink target "target1" is not referenced. - <system_message level="1" line="641" source="functional/input/data/standard.rst" type="INFO"> + <system_message level="1" line="644" source="functional/input/data/standard.rst" type="INFO"> <paragraph> Hyperlink target "target2" is not referenced. - <system_message level="1" line="686" source="functional/input/data/standard.rst" type="INFO"> + <system_message level="1" line="689" source="functional/input/data/standard.rst" type="INFO"> <paragraph> Hyperlink target "docutils" is not referenced. - <system_message level="1" line="852" source="functional/input/data/standard.rst" type="INFO"> + <system_message level="1" line="855" source="functional/input/data/standard.rst" type="INFO"> <paragraph> Hyperlink target "hyperlink targets" is not referenced. Modified: trunk/docutils/test/functional/expected/standalone_rst_xetex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-10-15 11:24:32 UTC (rev 9950) @@ -940,7 +940,7 @@ \begin{DUclass}{figclass2} \begin{figure} % align = "left" \noindent\makebox[\linewidth][c]{\includegraphics[width=40\pdfpxdimen]{../../../docs/user/rst/images/biohazard.png}} -\caption{This is the caption.} +\caption{\label{caption-label}\DUrole{captionclass1}{\DUrole{captionclass2}{This is the caption.}}} \begin{DUlegend} This is the legend. Modified: trunk/docutils/test/functional/input/data/standard.rst =================================================================== --- trunk/docutils/test/functional/input/data/standard.rst 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/input/data/standard.rst 2024-10-15 11:24:32 UTC (rev 9950) @@ -550,6 +550,9 @@ :width: 40 px :figwidth: 70 % + .. class:: captionclass1 captionclass2 + .. _caption-label: + This is the caption. This is the legend. Modified: trunk/docutils/test/functional/tests/standalone_rst_docutils_xml.py =================================================================== --- trunk/docutils/test/functional/tests/standalone_rst_docutils_xml.py 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/functional/tests/standalone_rst_docutils_xml.py 2024-10-15 11:24:32 UTC (rev 9950) @@ -8,4 +8,5 @@ 'sectsubtitle_xform': True, # format output with indents and newlines 'indents': True, + 'validate': True, # check conformance to Docutils Generic DTD } Modified: trunk/docutils/test/test_parsers/test_rst/test_directives/test_figures.py =================================================================== --- trunk/docutils/test/test_parsers/test_rst/test_directives/test_figures.py 2024-10-13 13:44:24 UTC (rev 9949) +++ trunk/docutils/test/test_parsers/test_rst/test_directives/test_figures.py 2024-10-15 11:24:32 UTC (rev 9950) @@ -41,6 +41,7 @@ totest = {} totest['figures'] = [ +# Note: A figure with no caption nor legend is not valid according to the DTD. ["""\ .. figure:: picture.png """, @@ -94,6 +95,30 @@ A picture with a legend but no caption. """], ["""\ +.. figure:: picture.png + + .. The comment replacing the caption must be empty. + + This should be a legend. +""", +"""\ +<document source="test data"> + <figure> + <image uri="picture.png"> + <system_message level="3" line="1" source="test data" type="ERROR"> + <paragraph> + Figure caption must be a paragraph or empty comment. + <literal_block xml:space="preserve"> + .. figure:: picture.png + \n\ + .. The comment replacing the caption must be empty. + \n\ + This should be a legend. +"""], +# Passing a class value to the caption is done with a class directive +# that inserts a pending node (to be removed by the ClassAttribute transform). +# A hyperlink target before the caption is removed by a transform, too. +["""\ .. Figure:: picture.png :height: 100 :width: 200 @@ -100,14 +125,24 @@ :scale: 50 :loading: embed - A picture with image options and a caption. + .. class:: custom + .. _figure:caption: + + A picture with image options and a caption with class value and target. """, """\ <document source="test data"> <figure> <image height="100" loading="embed" scale="50" uri="picture.png" width="200"> + <pending> + .. internal attributes: + .transform: docutils.transforms.misc.ClassAttribute + .details: + class: ['custom'] + directive: 'class' + <target ids="figure-caption" names="figure:caption"> <caption> - A picture with image options and a caption. + A picture with image options and a caption with class value and target. """], ["""\ .. Figure:: picture.png @@ -116,18 +151,19 @@ :width: 200 :scale: 50 :loading: lazy + :class: image-class :figwidth: 300 :figclass: class1 class2 :name: fig:pix - A picture with image options on individual lines, and this caption. + A figure with options and this caption. """, """\ <document source="test data"> <figure classes="class1 class2" width="300px"> - <image alt="alternate text" height="100" ids="fig-pix" loading="lazy" names="fig:pix" scale="50" uri="picture.png" width="200"> + <image alt="alternate text" classes="image-class" height="100" ids="fig-pix" loading="lazy" names="fig:pix" scale="50" uri="picture.png" width="200"> <caption> - A picture with image options on individual lines, and this caption. + A figure with options and this caption. """], ["""\ .. figure:: picture.png @@ -162,21 +198,7 @@ A figure with wrong alignment. """], ["""\ -This figure lacks a caption. It may still have a -"Figure 1."-style caption appended in the output. - .. figure:: picture.png -""", -"""\ -<document source="test data"> - <paragraph> - This figure lacks a caption. It may still have a - "Figure 1."-style caption appended in the output. - <figure> - <image uri="picture.png"> -"""], -["""\ -.. figure:: picture.png A picture with a caption and a legend. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mi...@us...> - 2024-10-18 08:57:33
|
Revision: 9951 http://sourceforge.net/p/docutils/code/9951 Author: milde Date: 2024-10-18 08:57:32 +0000 (Fri, 18 Oct 2024) Log Message: ----------- Document, that type hints use Python 3.10 syntax. Modified Paths: -------------- trunk/docutils/HISTORY.rst trunk/docutils/README.rst Modified: trunk/docutils/HISTORY.rst =================================================================== --- trunk/docutils/HISTORY.rst 2024-10-15 11:24:32 UTC (rev 9950) +++ trunk/docutils/HISTORY.rst 2024-10-18 08:57:32 UTC (rev 9951) @@ -19,12 +19,16 @@ * General - - We have started to add type hints to Docutils. - This will be a complex programme of work, and as such - for the time being these type hints are 'provisional', - and should not be relied upon by consumers of Docutils - (feature-request #87). - - Add tox.ini to pyproject.toml to be in sdist (bug #486). + - We have started to add type hints to Docutils (feature-request #87). + + This will be a complex programme of work and as such, + for the time being, these type hints are "provisional" + and should not be relied upon. + + By default, the Python interpreter treats type hints as annotations. + Python >= 3.10 is required with active type hints + (``typing.TYPE_CHECKING == True``). + - Fix license issue (bug #487). * docs/ref/docutils.dtd @@ -201,6 +205,10 @@ - Fix conversion of image width in "%" if the height is specified. - Adjust fallback DPI value (currently not used) to match CSS units. +* pyproject.toml + + - Add tox.ini to the "include" list (fixes bug #486). + * tools/rst2odt.py - Use `core.publish_file()` instead of `core.publish_file_to_binary()`. Modified: trunk/docutils/README.rst =================================================================== --- trunk/docutils/README.rst 2024-10-15 11:24:32 UTC (rev 9950) +++ trunk/docutils/README.rst 2024-10-18 08:57:32 UTC (rev 9951) @@ -78,6 +78,10 @@ * Docutils versions 0.19 to 0.20.1 require Python 3.7 or later. * Docutils versions 0.16 to 0.18 require Python 2.7 or 3.5+. +The **type hints** added in version 0.22 use Python 3.10 syntax. +However, the Python interpreter treats them as annotations +unless ``typing.TYPE_CHECKING`` is set to ``True``. + .. _Python: https://www.python.org/. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |