UV: Document pack islands features and new ui #104468

Closed
Chris Blackbourn wants to merge 63 commits from Chris_Blackbourn/blender-manual:uv_pack_islands into blender-v3.6-release

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
49 changed files with 9967 additions and 536 deletions

View File

@ -27,6 +27,8 @@ Utilities
---------
- update to update the repository to the most recent version.
- format_py to auto-format Python scripts.
endef
# HELP_TEXT (end)
@ -125,6 +127,9 @@ report_po_progress:
update:
@git pull --rebase
format_py:
@autopep8 --in-place --recursive .
# ----------------------
# Help for build targets

View File

@ -8,9 +8,10 @@ In this case you need only enable the Add-on in the Add-on Preferences.
However, the latest releases can be found on our GitHub.
Downloads should only be taken the from the official releases page:
Downloads should only be taken the from the
`official releases page <https://github.com/Clockmender/Precision-Drawing-Tools/releases>`__.
https://github.com/Clockmender/Precision-Drawing-Tools/releases
Patches and Commits, that may add new features and/or bug fixes may be downloaded
from the Commits to the Master branch, no development code should be used
@ -55,6 +56,6 @@ again only edit the message section in quotes, not the PDT assignments.
Issues
======
Please report any issues, or feature request, etc. using the Issues section
of the PDT Repository (https://github.com/Clockmender/Precision-Drawing-Tools/issues),
Please report any issues, or feature request, etc. using the Issues section of the
`PDT Repository <https://github.com/Clockmender/Precision-Drawing-Tools/issues>`__,
that way they can be properly tracked, actioned and incorporated into the add-on.

View File

@ -42,14 +42,15 @@ See `Examples`_ at the end of this page.
- A list of software that deals with PDB in different ways can be found on
the `RCSB site <https://www.rcsb.org/docs/additional-resources/molecular-graphics-software>`__. There also is
`Vesta <https://jp-minerals.org/vesta/en/>`__, `ASE <https://wiki.fysik.dtu.dk/ase/>`__ and all the
`quantum chemical calculators <https://en.wikipedia.org/wiki/List_of_quantum_chemistry_and_solid-state_physics_
software>`__ used in research, which can create or even calculate atomic structures and store them in PDB/XYZ
files.
`quantum chemical calculators
<https://en.wikipedia.org/wiki/List_of_quantum_chemistry_and_solid-state_physics_software>`__
used in research, which can create or even calculate atomic structures and store them in PDB/XYZ files.
.. seealso:: **Forum**
- Please, use the `Blender Artists forum <https://blenderartists.org/t/atomic-blender-pdb-xyz-for-blender-2-8-and-
higher/1197801>`__ for comments and questions or directly the `Blender chat <https://blender.chat/home>`__.
- Please, use the `Blender Artists forum
<https://blenderartists.org/t/atomic-blender-pdb-xyz-for-blender-2-8-and-higher/1197801>`__
for comments and questions or directly the `Blender chat <https://blender.chat/home>`__.
- There also is the possibility to ask questions on `Stack Exchange <https://blender.stackexchange.com/>`__.
However, note that some of the developers like Blendphys don't have enough credits, which are, however, needed to
have the permission for giving answers on Stack Exchange.

View File

@ -7,7 +7,7 @@ Autodesk 3DS
:Category: Import-Export
:Menu: :menuselection:`File --> Import/Export --> 3D Studio (.3ds)`
:Version: 2.3.4
:Version: 2.4.1
:Blender: 3.6
:Authors: Bob Holcomb, Campbell Barton, Sebastian Schrand
:Maintainer: Sebastian Sille (NRGSille)
@ -36,7 +36,7 @@ Image Search
This enables a recursive file search if an image file can't be found.
Read Keyframe
Reads the keyframe tracks from a 3ds file and transforms the objects to the data wich was found.
Reads the keyframe tracks from a 3ds file and transforms the objects to the data which was found.
Usually only one frame is found in static scenes, it will be imported to the timeline.
If the 3ds scene is animated, the complete animation will be imported to the timeline.
@ -60,7 +60,7 @@ Apply Transform
World Space
Use world matrix instead of local matrix to transform the objects.
This is useful for older 3ds files from 3D Studio DOS wich only used world space to transform the objects.
This is useful for older 3ds files from 3D Studio DOS which only used world space to transform the objects.
It is also useful if the object was exported without apply transform.
@ -73,6 +73,10 @@ Include
Selection Only
When checked, only selected objects are exported. Otherwise export all objects in the scene.
Write Keyframe
Writes the keyframe section of a 3ds file and exports the animation if an action was found.
The animation can be imported the same way, un-check if any importer crashes,
not every application can handle the keyframe section.
Transform
^^^^^^^^^
@ -88,11 +92,11 @@ Forward / Up
Materials
=========
Materials in 3ds are defined in various color and percent chunks wich can include
Materials in 3ds are defined in various color and percent chunks which can include
either integer percent and 24bit color values or float color and percent values,
both can be read by the importer and will be converted to blender values.
The exporter uses the integer values, since this is used from 3ds version 3 and above.
The material definitions wich Blender can use are the following:
The material definitions which Blender can use are the following:
- 3ds Diffuse Color <-> blender Base Color
- 3ds Specular Color <-> blender Specular Color
@ -101,8 +105,8 @@ The material definitions wich Blender can use are the following:
- 3ds Mat Shin2 <-> blender Specular Intensity
- 3ds Mat Shin3 <-> blender Metallic
- 3ds Mat Opacity <-> blender Alpha inverted
- 3ds Mat Bump PCT <-> blender Normalmap Strength
- 3ds Self Illum PCT <-> blender Emission Strength
- 3ds Mat Bump PCT <-> blender Normal-map Strength
- 3ds Self Illumination PCT <-> blender Emission Strength
Textures
@ -111,8 +115,8 @@ Textures
Each 3ds material can include different texture mappings,
which are all imported to Blender material nodes including texture coordinates.
The 3ds exporter basically takes the images and coordinates,
wich are directly connected to the Principled BSDF shader,
if an image is connected to a colormix shader, it will exported as secondary texture.
which are directly connected to the Principled BSDF shader,
if an image is connected to a color-mix shader, it will exported as secondary texture.
Shininess maps to roughness and opacity to the alpha channel,
they must be color inverted afterwards to match with Blender definition.
The material mappings are defined as following:
@ -122,9 +126,9 @@ The material mappings are defined as following:
- 3ds Shininess Map <-> blender Roughness Texture
- 3ds Reflection Map <-> blender Metallic Texture
- 3ds Opacity Map <-> blender Alpha Texture
- 3ds Self Illum Map <-> blender Emission Texture
- 3ds Self Illumination Map <-> blender Emission Texture
- 3ds Bump Map <-> blender Normal Map (tangent space)
- 3ds Tex2 Map <-> blender Color Texture (connect to mixshader)
- 3ds Tex2 Map <-> blender Color Texture (connect to mix-shader)
.. figure:: /images/addons_io_3ds_material-nodes.jpg
@ -140,12 +144,12 @@ Meshes
======
Meshes are made of triangles only, no quads are supported,
3ds Studio uses edge visibilty flags to hide and show edges, many 3ds files use them to mark the quads.
3ds Studio uses edge visibility flags to hide and show edges, many 3ds files use them to mark the quads.
The Blender 3ds importer and exporter will use those flags to mark edges sharp,
this can be used to convert the triangles back to quads.
The importer can read the smoothchunk and shades a face smooth if it belongs to a smoothgroup,
The importer can read the smooth-chunk and shades a face smooth if it belongs to a smooth-group,
the exporter creates a smooth chunk if the mesh contains any smooth faces.
3ds only supports one pair of UV coordinates per vertex. If any vertex has more UVs, it will be dublicated.
3ds only supports one pair of UV coordinates per vertex. If any vertex has more UVs, it will be duplicated.
Ambient
@ -178,3 +182,4 @@ Keyframes
The importer can read the keyframes, they will be added to the timeline.
Most animations will play, but the transformations may not be correct,
some axes or rotations can be inverted. It depends on how it was exported from other applications.
The exporter can write the keyframes of the timeline to an animated 3ds file.

View File

@ -6,7 +6,7 @@ AutoCAD DXF
.. reference::
:Category: Import-Export
:Menu: :menuselection:`File --> Import/Export --> AutoCAD DXF`
:Menu: :menuselection:`File --> Import/Export --> AutoCAD DXF (.dxf)`
.. _dxf-import:

View File

@ -330,7 +330,7 @@ Timeline Extra Info
Display amount of frames left until Frame End, very handy especially when rendering an animation or OpenGL preview.
Display current/end time in `SMPTE <https://en.wikipedia.org/wiki/SMPTE_timecode>`_.
Display current/end time in `SMPTE <https://en.wikipedia.org/wiki/SMPTE_timecode>`__.
Usage: Find it in the Timeline Editor's header.
@ -381,7 +381,7 @@ Sequencer: Display Image File Name
When seeking through an image sequence, display the active strips'
file name for the current frame, and its playhead (in square brackets).
Usage: Find it in the VSE header.
Usage: Find it in the sequencer header.
EXR Render: Warn when Z not connected

View File

@ -414,8 +414,8 @@ that generate the various patterns of many living organisms.
See `this video <https://youtu.be/J-0NzU1TmIY>`__ for an example of the Reaction-Diffusion simulation with Tissue.
Radom Materials
---------------
Random Materials
----------------
(To Do)

View File

@ -76,7 +76,7 @@ Timeline Scrub
Call a timeline popup at mouse position to scrub without leaving the 3D viewport.
Default shortcut to call the timeline is :kbd:`Alt-MMB`.
The shortcut enable the scrubbing when hovering timeline editors as well (dopesheet, sequencer, etc).
The shortcut enable the scrubbing when hovering timeline editors as well (dope-sheet, sequencer, etc).
Scene start/end and keyframes are represented with symbols on the timeline.

View File

@ -1,6 +1,5 @@
.. DO NOT EDIT THIS FILE, GENERATED BY 'blender_help_extract.py'
CHANGES TO THIS FILE MUST BE MADE IN BLENDER'S SOURCE CODE, SEE:
https://projects.blender.org/blender/blender/src/branch/main/source/creator/creator_args.c
@ -10,10 +9,8 @@
Command Line Arguments
**********************
Blender |BLENDER_VERSION|
Usage: blender [args ...] [file] [args ...]
| Blender |BLENDER_VERSION|
| Usage: ``blender [args ...] [file] [args ...]``
.. _command-line-args-render-options:
@ -22,10 +19,13 @@ Render Options
``-b``, ``--background``
Run in background (often used for UI-less rendering).
``-a``, ``--render-anim``
Render frames from start to end (inclusive).
``-S``, ``--scene`` ``<name>``
Set the active scene ``<name>`` for rendering.
``-f``, ``--render-frame`` ``<frame>``
Render frame ``<frame>`` and save it.
@ -33,12 +33,16 @@ Render Options
* A comma separated list of frames can also be used (no spaces).
* A range of frames can be expressed using ``..`` separator between the first and last frames (inclusive).
``-s``, ``--frame-start`` ``<frame>``
Set start to frame ``<frame>``, supports +/- for relative frames too.
``-e``, ``--frame-end`` ``<frame>``
Set end to frame ``<frame>``, supports +/- for relative frames too.
``-j``, ``--frame-jump`` ``<frames>``
Set number of frames to step forward after each rendered frame.
``-o``, ``--render-output`` ``<path>``
Set the render path and file name.
Use ``//`` at the start of the path to render relative to the blend-file.
@ -57,13 +61,36 @@ Render Options
blender -b animation.blend -o //render_ -F PNG -x 1 -a
``//render_`` becomes ``//render_####``, writing frames as ``//render_0001.png``
``-E``, ``--engine`` ``<engine>``
Specify the render engine.
Use ``-E help`` to list available engines.
``-t``, ``--threads`` ``<threads>``
Use amount of ``<threads>`` for rendering and other operations
[1-1024], 0 for systems processor count.
.. _command-line-args-cycles-render-options:
Cycles Render Options
=====================
Cycles add-on options must be specified following a double dash.
``--cycles-device`` ``<device>``
Set the device used for rendering.
Valid options are: ``CPU`` ``CUDA`` ``OPTIX`` ``HIP`` ``ONEAPI`` ``METAL``.
Append +CPU to a GPU device to render on both CPU and GPU.
Example:
.. code-block:: sh
blender -b file.blend -f 20 -- --cycles-device OPTIX
``--cycles-print-stats``
Log statistics about render memory and time usage.
.. _command-line-args-format-options:
@ -73,10 +100,11 @@ Format Options
``-F``, ``--render-format`` ``<format>``
Set the render format.
Valid options are:
``TGA`` ``RAWTGA`` ``JPEG`` ``IRIS`` ``IRIZ`` ``AVIRAW`` ``AVIJPEG`` ``PNG`` ``BMP``
``TGA`` ``RAWTGA`` ``JPEG`` ``IRIS`` ``IRIZ`` ``AVIRAW`` ``AVIJPEG`` ``PNG`` ``BMP``.
Formats that can be compiled into Blender, not available on all systems:
``HDR`` ``TIFF`` ``OPEN_EXR`` ``OPEN_EXR_MULTILAYER`` ``MPEG`` ``CINEON`` ``DPX`` ``DDS`` ``JP2`` ``WEBP``
``HDR`` ``TIFF`` ``OPEN_EXR`` ``OPEN_EXR_MULTILAYER`` ``MPEG`` ``CINEON`` ``DPX`` ``DDS`` ``JP2`` ``WEBP``.
``-x``, ``--use-extension`` ``<bool>``
Set option to add the file extension to the end of the file.
@ -96,7 +124,7 @@ Animation Playback Options
Open with lower left corner at ``<sx>``, ``<sy>``.
``-m``
Read from disk (Do not buffer).
``-f`` ``<fps>`` ``<fps-base>``
``-f`` ``<fps>`` ``<fps_base>``
Specify FPS to start with.
``-j`` ``<frame>``
Set frame step to ``<frame>``.
@ -116,16 +144,22 @@ Window Options
``-w``, ``--window-border``
Force opening with borders.
``-W``, ``--window-fullscreen``
Force opening in fullscreen mode.
``-p``, ``--window-geometry`` ``<sx>`` ``<sy>`` ``<w>`` ``<h>``
Open with lower left corner at ``<sx>``, ``<sy>`` and width and height as ``<w>``, ``<h>``.
``-M``, ``--window-maximized``
Force opening maximized.
``-con``, ``--start-console``
Start with the console window open (ignored if ``-b`` is set), (Windows only).
``--no-native-pixels``
Do not use native pixel size, for high resolution displays (MacBook ``Retina``).
``--no-window-focus``
Open behind other windows and without taking focus.
@ -136,23 +170,31 @@ Python Options
==============
``-y``, ``--enable-autoexec``
Enable automatic Python script execution (default).
Enable automatic Python script execution.
``-Y``, ``--disable-autoexec``
Disable automatic Python script execution (pydrivers & startup scripts).
Disable automatic Python script execution (pydrivers & startup scripts), (default).
``-P``, ``--python`` ``<filepath>``
Run the given Python script file.
``--python-text`` ``<name>``
Run the given Python script text block.
``--python-expr`` ``<expression>``
Run the given expression as a Python script.
``--python-console``
Run Blender with an interactive console.
``--python-exit-code`` ``<code>``
Set the exit-code in [0..255] to exit if a Python exception is raised
(only for scripts executed from the command line), zero disables.
``--python-use-system-env``
Allow Python to use system environment variables such as ``PYTHONPATH`` and the user site-packages directory.
``--addons`` ``<addon(s)>``
Comma separated list (no spaces) of add-ons to enable in addition to any default add-ons.
@ -170,15 +212,20 @@ Logging Options
so ``--log "*undo*"`` logs every kind of undo-related message.
Use "^" prefix to ignore, so ``--log "*,^wm.operator.*"`` logs all except for ``wm.operators.*``
Use "*" to log everything.
``--log-level`` ``<level>``
Set the logging verbosity level (higher for more details) defaults to 1,
use -1 to log all levels.
``--log-show-basename``
Only show file name in output (not the leading path).
``--log-show-backtrace``
Show a back trace for each log message (debug builds only).
``--log-show-timestamp``
Show a timestamp for each log message in seconds since start.
``--log-file`` ``<filepath>``
Set a file to output the log to.
@ -194,73 +241,109 @@ Debug Options
* Enables memory error detection
* Disables mouse grab (to interact with a debugger in some cases)
* Keeps Python's ``sys.stdin`` rather than setting it to None
``--debug-value`` ``<value>``
Set debug value of ``<value>`` on startup.
``--debug-events``
Enable debug messages for the event system.
``--debug-ffmpeg``
Enable debug messages from FFmpeg library.
``--debug-handlers``
Enable debug messages for event handling.
``--debug-libmv``
Enable debug messages from libmv library.
``--debug-cycles``
Enable debug messages from Cycles.
``--debug-memory``
Enable fully guarded memory allocation and debugging.
``--debug-jobs``
Enable time profiling for background jobs.
``--debug-python``
Enable debug messages for Python.
``--debug-depsgraph``
Enable all debug messages from dependency graph.
``--debug-depsgraph-eval``
Enable debug messages from dependency graph related on evaluation.
``--debug-depsgraph-build``
Enable debug messages from dependency graph related on graph construction.
``--debug-depsgraph-tag``
Enable debug messages from dependency graph related on tagging.
``--debug-depsgraph-no-threads``
Switch dependency graph to a single threaded evaluation.
``--debug-depsgraph-time``
Enable debug messages from dependency graph related on timing.
``--debug-depsgraph-pretty``
Enable colors for dependency graph debug messages.
``--debug-depsgraph-uuid``
Verify validness of session-wide identifiers assigned to ID datablocks.
``--debug-ghost``
Enable debug messages for Ghost (Linux only).
``--debug-wintab``
Enable debug messages for Wintab.
``--debug-gpu``
Enable GPU debug context and information for OpenGL 4.3+.
``--debug-gpu-force-workarounds``
Enable workarounds for typical GPU issues and disable all GPU extensions.
``--debug-gpu-disable-ssbo``
Disable usage of shader storage buffer objects.
``--debug-gpu-renderdoc``
Enable Renderdoc integration for GPU frame grabbing and debugging.
``--debug-wm``
Enable debug messages for the window manager, shows all operators in search, shows keymap errors.
``--debug-xr``
Enable debug messages for virtual reality contexts.
Enables the OpenXR API validation layer, (OpenXR) debug messages and general information prints.
``--debug-xr-time``
Enable debug messages for virtual reality frame rendering times.
``--debug-all``
Enable all debug messages.
``--debug-io``
Enable debug messages for I/O (Collada, ...).
``--debug-fpe``
Enable floating-point exceptions.
``--debug-exit-on-error``
Immediately exit when internal errors are detected.
``--debug-freestyle``
Enable debug messages for Freestyle.
``--disable-crash-handler``
Disable the crash handler.
``--disable-abort-handler``
Disable the abort handler.
``--verbose`` ``<verbose>``
Set the logging verbosity level for debug messages that support it.
@ -281,49 +364,60 @@ Misc Options
``--open-last``
Open the most recently opened blend file, instead of the default startup file.
``--app-template`` ``<template>``
Set the application template (matching the directory name), use ``default`` for none.
``--factory-startup``
Skip reading the startup.blend in the users home directory.
Skip reading the ``startup.blend`` in the users home directory.
``--enable-event-simulate``
Enable event simulation testing feature ``bpy.types.Window.event_simulate``.
``--env-system-datafiles``
Set the ``BLENDER_SYSTEM_DATAFILES`` environment variable.
``--env-system-scripts``
Set the ``BLENDER_SYSTEM_SCRIPTS`` environment variable.
``--env-system-python``
Set the ``BLENDER_SYSTEM_PYTHON`` environment variable.
``-noaudio``
Force sound system to None.
``-setaudio``
Force sound system to a specific device.
``None`` ``SDL`` ``OpenAL`` ``CoreAudio`` ``JACK`` ``PulseAudio`` ``WASAPI``.
``-h``, ``--help``
Print this help text and exit.
``/?``
Print this help text and exit (Windows only).
``-R``
Register blend-file extension, then exit (Windows only).
``-r``
Silently register blend-file extension, then exit (Windows only).
``-r``, ``--register``
Register blend-file extension for current user, then exit (Windows only).
``--register-allusers``
Register blend-file extension for all users, then exit (Windows only).
``--unregister``
Unregister blend-file extension for current user, then exit (Windows only).
``--unregister-allusers``
Unregister blend-file extension for all users, then exit (Windows only).
``-v``, ``--version``
Print Blender version and exit.
``--``
End option processing, following arguments passed unchanged. Access via Python's ``sys.argv``.
.. _command-line-args-other-options:
Other Options
=============
``--debug-freestyle``
Enable debug messages for Freestyle.
.. _command-line-args-argument-parsing:
Argument Parsing
@ -337,7 +431,6 @@ Arguments must be separated by white space, eg:
...will exit since ``-ba`` is an unknown argument.
.. _command-line-args-argument-order:
Argument Order
@ -347,7 +440,7 @@ Arguments are executed in the order they are given. eg:
.. code-block:: sh
blender --background test.blend --render-frame 1 --render-output '/tmp'
blender --background test.blend --render-frame 1 --render-output "/tmp"
...will not render to ``/tmp`` because ``--render-frame 1`` renders before the output path is set.
@ -363,23 +456,22 @@ Arguments are executed in the order they are given. eg:
...works as expected.
.. _command-line-args-environment-variables:
Environment Variables
=====================
:BLENDER_USER_RESOURCES: Top level directory for user files.
(other ``BLENDER_USER_*`` variables override when set).
(other ``BLENDER_USER_*`` variables override when set).
:BLENDER_USER_CONFIG: Directory for user configuration files.
:BLENDER_USER_SCRIPTS: Directory for user scripts.
:BLENDER_USER_DATAFILES: Directory for user data files (icons, translations, ..).
:BLENDER_SYSTEM_RESOURCES: Top level directory for system files.
(other ``BLENDER_SYSTEM_*`` variables override when set).
(other ``BLENDER_SYSTEM_*`` variables override when set).
:BLENDER_SYSTEM_SCRIPTS: Directory for system wide scripts.
:BLENDER_SYSTEM_DATAFILES: Directory for system wide data files.
:BLENDER_SYSTEM_PYTHON: Directory for system Python libraries.
:OCIO: Path to override the OpenColorIO config file.
:TEMP: Store temporary files here.
:TMP: or $TMPDIR Store temporary files here.
:TEMP: Store temporary files here (MS-Windows).
:TMP: or $TMPDIR Store temporary files here (UNIX Systems).

View File

@ -14,13 +14,14 @@ and consequently we can render via a remote shell (typically SSH).
- See :doc:`Command Line Arguments </advanced/command_line/arguments>`
for a full list of arguments
(for example to specify which scene to render, the end frame number, etc.), or simply run:
- See :ref:`Command Line Launching <command_line-launch-index>`
for specific instructions on launching Blender from the command line.
.. code-block:: sh
blender --help
- See :ref:`Command Line Launching <command_line-launch-index>`
for specific instructions on launching Blender from the command line.
.. note::
Arguments are executed in the order they are given!
@ -98,20 +99,4 @@ Cycles
In addition to the options above, which apply to all render engines,
Cycles has additional options to further control its behavior.
.. code-block:: sh
blender -b file.blend -f 20 -- --cycles-device CPU
.. note::
Unlike the generic options, the Cycles-specific ones must be passed on
the end of the command line, following a double dash.
``--cycles-device CPU``
Override the device that is used to render frames.
Currently supported options are ``CPU``, ``CUDA``, ``OPTIX``, ``HIP``, ``ONEAPI``, and ``METAL``.
Additionally, you can append ``+CPU`` to any GPU type for hybrid rendering.
``--cycles-print-stats``
Show detailed statistics about memory and time usage for Cycles renders on the console.
See :ref:`Cycles Render Options <command-line-args-cycles-render-options>`

View File

@ -228,15 +228,16 @@ Apply Pose Flipped
be applied for asymmetrical facial expressions that depend on the camera
angle. While blending (see below), keep :kbd:`Ctrl` pressed to blend the flipped pose.
. _bpy.ops.poselib.blend_pose_asset:
.. _bpy.ops.poselib.blend_pose_asset:
Blend Pose
Allows you to gradually blend a pose from the library into the character's pose.
Click the button, then move the mouse left/right to determine the desired blend.
A pose asset can be "subtracted" while blending. Drag to the right to blend as usual, drag to the left to subtract the pose.
While blending, you can use :kbd:`Tab` to toggle between the original and the blended pose.
As usual in Blender, :kbd:`LMB` or press :kbd:`Enter` to confirm; :kbd:`RMB` or press :kbd:`Esc` to cancel the operator.
Blending can also exaggerate a pose, by pressing :kbd:`E` (for Extrapolate) and applying a pose for more than 100%.
A pose asset can be "subtracted" while blending. Drag to the right to blend as usual, drag to the left to subtract
the pose. While blending, you can use :kbd:`Tab` to toggle between the original and the blended pose.
As usual in Blender, :kbd:`LMB` or press :kbd:`Return` to confirm; :kbd:`RMB` or press :kbd:`Esc` to cancel the
operator. Blending can also exaggerate a pose, by pressing :kbd:`E` (for Extrapolate) and applying a pose for more
than 100%.
.. _bpy.ops.poselib.pose_asset_select_bones:

View File

@ -184,9 +184,9 @@ If an input image to a node is not perfectly aligned with the operation domain o
different size in pixels, the node would typically need to do a process called Interpolation, where
the input image is read at the exact positions of the pixels of the operation domain. This can be
done using different interpolation methods, including Nearest-Neighbor, Bilinear, and Bicubic
interpolations. Those interpolation methods are demonstrated in the following `Wikipedia gallery
<https://en.wikipedia.org/wiki/Comparison_gallery_of_image_scaling_algorithms>`_. Transformation
nodes like the :ref:`Transform <bpy.types.CompositorNodeTransform>` and :ref:`Rotate
interpolations. Those interpolation methods are demonstrated in the following
`Wikipedia gallery <https://en.wikipedia.org/wiki/Comparison_gallery_of_image_scaling_algorithms>`__.
Transformation nodes like the :ref:`Transform <bpy.types.CompositorNodeTransform>` and :ref:`Rotate
<bpy.types.CompositorNodeRotate>` nodes include an interpolation option to set how they prefer their
output image to be read and interpolated.

View File

@ -26,7 +26,7 @@ sys.setrecursionlimit(2000)
# Not used directly by Sphinx, but used by this file and the buildbot.
blender_version = '3.6'
blender_version = '4.0'
# -- Project information -----------------------------------------------------
@ -237,7 +237,7 @@ epub_publisher = 'Blender Foundation'
# The language of the text. It defaults to the language option
# or 'en' if the language is not set.
#epub_language = ''
# epub_language = ''
epub_copyright = 'This manual is licensed under a CC-BY-SA 4.0 Int. License.'
@ -330,17 +330,17 @@ latex_logo = "../resources/theme/blender-logo.svg"
# This value determines the topmost sectioning unit. It should be chosen from
# 'part', 'chapter' or 'section'.
#latex_toplevel_sectioning = 'None'
# latex_toplevel_sectioning = 'None'
# A list of document names to append as an appendix to all manuals.
#latex_appendices = []
# latex_appendices = []
# If true, generate domain-specific indices in addition to the general index.
#latex_domain_indices = True
# latex_domain_indices = True
# If true, add page references after internal references.
# This is very useful for printed copies of the manual.
#latex_show_pagerefs = False
# latex_show_pagerefs = False
# Control whether to display URL addresses.
latex_show_urls = "no"
@ -415,17 +415,17 @@ texinfo_documents = [
]
# A list of document names to append as an appendix to all manuals.
#texinfo_appendices = []
# texinfo_appendices = []
# If true, generate domain-specific indices in addition to the general index.
#texinfo_domain_indices = True
# texinfo_domain_indices = True
# Control how to display URL addresses.
#texinfo_show_urls = 'footnote'
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the “Top” nodes menu
# containing entries for each sub-node in the document.
#texinfo_no_detailmenu = False
# texinfo_no_detailmenu = False
# -- Extension configuration -------------------------------------------------

View File

@ -73,8 +73,7 @@ Guidelines for Reviewers
``WIP:`` prefix in the title, indicating the author considers the pull request not ready to be merged.
No review is expected unless the author specifically asks for it.
- Writers are expected to reply to pull requests in 3 working days.
- Add relevant modules/projects to tags.
- Assign individuals (instead of modules/projects) for reviewers, to avoid too much noise.
- Add relevant modules/projects to the labels.
- Encourage new writes to do review, it's a good way to learn and important to grow the project.

View File

@ -24,7 +24,7 @@ This will give you a foundation environment for:
Below examples show the process to create a new set of files for French, language code ``fr``, on Linux platform.
Other platforms might vary slightly but should be mainly the same.
#. `Create a Blender ID <https://id.blender.org/register/>` if you have not done so already
#. `Create a Blender ID <https://id.blender.org/register/>`__ if you have not done so already
#. Log into `projects.blender.org <https://projects.blender.org/>`__ and
`Create an Issue <https://projects.blender.org/blender/documentation/issues/new>`__
requesting for commit access in order to transfer changes to the central repository of the translation team.

View File

@ -54,7 +54,8 @@ Selecting
---------
- Select channel (text in white/black): :kbd:`LMB`
- Multi Select/Deselect: :kbd:`Shift-LMB`
- Multi Select/Deselect: :kbd:`Ctrl-LMB`
- Range Select: :kbd:`Shift-LMB`
- Select All: :kbd:`A`
- Deselect All: :kbd:`Alt-A`
- Box Select: (:kbd:`LMB` drag) or :kbd:`B` (:kbd:`LMB` drag)

View File

@ -150,14 +150,14 @@ Copy/Paste
.. admonition:: Reference
:Menu: :menuselection:`Key --> Copy Keyframes`, :menuselection:`Key --> Paste Keyframes`
:Menu: :menuselection:`Key --> Copy`, :menuselection:`Key --> Paste`
:Shortcut: :kbd:`Ctrl-C`, :kbd:`Ctrl-V`
Use :kbd:`Ctrl-C` to copy selected keyframes and :kbd:`Ctrl-V` to paste the previously copied keyframes.
During the paste action, the :ref:`bpy.ops.screen.redo_last` panel provides some options in
how the paste is applied.
Offset
Frame Offset
:No Offset:
Pastes the keyframes in the location they were copied from.
:Frame Relative:
@ -167,6 +167,19 @@ Offset
Pastes the keyframes with the first keyframe of the copied set placed at the current frame.
:Frame End:
Pastes the keyframes with the last keyframe of the copied set placed at the current frame.
Value Offset
:No Offset:
Pastes the keyframes with the value they were copied from.
:Cursor Value:
Paste the keyframes at the 2D cursor as a starting point.
:Current Frame Value:
Paste keyframes relative to the value of the curve under the cursor.
:Right Key:
Paste keyframes such that the last frame matches the key value right of the cursor.
:Left Key:
Paste keyframes such that the first key matches the key value left of the cursor.
Type
:Mix:
Integrates the pasted keyframes in with existing keyframes only overwriting keyframes that share a frame.
@ -442,3 +455,31 @@ seem to be never modified by this tool.
- .. figure:: /images/editors_graph-editor_fcurves_editing_smooth.png
F-Curve after smoothing.
.. _bpy.ops.graph.gaussian_smooth:
Smooth (Gaussian)
-----------------
.. reference::
:Menu: :menuselection:`Key --> Smooth --> Smooth (Gaussian)`
Smooths the selected keyframes using a Gaussian kernel. It can handle gaps in the keyframe data.
The operator is modal with a blend factor, making it possible to tweak the strength of the filter.
Factor
A blend factor from original to filtered curve.
Sigma
The shape of the gaussian distribution. Lower values mean a sharper curve, giving keys that are close to each
other more weight. A high value behaves like a simple average filter.
Filter Width
A wider filter looks at more keyframes, producing a smoother result.
At a size of 1 the filter only looks at the keyframes to the immediate left and right for a weighted average.
.. figure:: /images/editors_graph-editor_gaussian_smooth.jpg
F-Curve after applying the Gaussian Smooth with the original curve overlayed.

View File

@ -163,8 +163,9 @@ Interpolation
.. seealso::
For more info and a few live demos, see https://easings.net and
http://robertpenner.com/easing/
For more info and a few live demos,
see `easings.net <https://easings.net>`__ and
`Robert Penner's Easing Functions <http://robertpenner.com/easing>`__.
.. rubric:: Dynamic Effects

View File

@ -237,6 +237,7 @@ Start Tweaking Strips Actions (Full Stack)
.. reference::
:Menu: :menuselection:`Edit --> Start Tweaking Strips Actions (Full Stack)`
:Shortcut: :kbd:`Tab`
Allows you to edit the contents of the strip without disabling all the tracks above the tweaked strip.
This allows keyframing to work as expected, and preserves the pose that you visually keyed.
@ -257,10 +258,8 @@ Start Tweaking Strips Actions (Lower Stack)
.. reference::
:Menu: :menuselection:`Edit --> Start Tweaking Strips Actions (Lower Stack)`
:Shortcut: :kbd:`Tab`
The contents of Action strips can be edited, but you must be in *Tweak Mode* to do so.
The keyframes of the action can then be edited in the Dope Sheet.
When you finished editing the strip, simply go to :menuselection:`Edit --> Stop Tweaking Strips Actions`
or press :kbd:`Tab`.

View File

@ -53,7 +53,8 @@ Shared Location
This is the default and gives the illusion that multiple faces in a UV map can share the same vertex;
in reality, they have separate vertices that overlap.
Shared Vertex
Automatically select UV vertices that correspond to the same mesh vertex, even if they have different UV coordinates.
Automatically select UV vertices that correspond to the same mesh vertex,
even if they have different UV coordinates.
This is also the behavior when *Sync Selection* is enabled.
Select Menu
@ -104,7 +105,8 @@ Select Similar :kbd:`Shift-G`
:Area 3D: Selects faces with a similar area in the 3D mesh.
:Material: Selects faces that have the same :doc:`Material </render/materials/index>`.
:Object:
Selects faces that belong to the same object. This is useful when multiple objects are in Edit mode at once.
Selects faces that belong to the same object.
This is useful when multiple objects are in Edit mode at once.
:Polygon Sides: Selects faces with a similar number of edges.
:Winding: Select faces that have the same orientation (facing upwards or downwards in the UV map).
@ -126,9 +128,10 @@ Select Split :kbd:`Y`
"Detaches" the selected faces so they can be moved elsewhere without affecting their neighbors.
.. hint::
Unlike :doc:`Split Selection </modeling/meshes/editing/mesh/split>` for meshes, which physically disconnects
faces, this is a pure selection operator. In UV space, the faces were never connected to begin with; it only seemed
that way because *Sticky Selection* automatically selected the vertices of the neighboring faces.
faces, this is a pure selection operator. In UV space, the faces were never connected to begin with;
it only seemed that way because *Sticky Selection* automatically selected the vertices of the neighboring faces.
*Select Split* deselects those vertices again.
As an alternative to *Select Split*, you can set the *Sticky Selection Mode* to *Disabled*.

View File

@ -23,7 +23,7 @@ The gizmos however are unique for the Preview.
.. figure:: /images/editors_vse_type.svg
:alt: Preview window
Figure 1: Preview window of VSE.
Figure 1: Preview window of Video Sequencer.
Sequencer preview is used to display result of rendering Sequencer timeline.
This can be further configured to display output from certain channel, overlay or image analyzer (scope).

View File

@ -4,7 +4,7 @@
Smooth Hair Curves
******************
Smoothes the shape of hair curves.
Smooths the shape of hair curves.
.. peertube:: 7fpUB2eRT6zjMyHRzJ2ZoJ

View File

@ -193,10 +193,8 @@ Follow Active Quads
:Menu: :menuselection:`UV --> Follow Active Quads`
:Shortcut: :kbd:`U`
The Follow Active Quads tool takes the selected faces and lays them out
by following continuous face loops, even if the mesh face is irregularly-shaped.
Note that it does not respect the image size,
so you may have to scale them all down a bit to fit the image area.
Extrapolate UV's based on the active quad by following continuous face loops,
even if the mesh face is irregularly-shaped.
Options
@ -205,16 +203,27 @@ Options
Edge Length Mode
Method to space UV edge loops.
:Even: Space all UVs evenly.
:Length: Todo.
:Length Average: Average space UVs edge length of each loop.
:Even:
Space all UVs evenly, where the shape of the quad in the 3D viewport is ignored.
:Length:
Each face's UV's are calculated based on the edge length.
While this minimizes distortion, adjacent loops may become disconnected.
:Length Average:
Average space UVs edge length of each loop.
This has the benefit of minimizing distortion, while keeping UV's connected.
.. note::
Please note that it is the shape of the active quad in UV space that is being followed,
not its shape in 3D space. To get a clean 90-degree unwrap make sure the active quad is
a rectangle in UV space before using "Follow active quad".
For a clean 90-degree unwrap it's typically best to first make sure the quad a rectangle in UV space.
Otherwise any distortion in the active UV is extended which doesn't result in a useful grid-layout.
.. note::
The resulting unwrap is not clamped within the UV bounds,
you may wish to scale down the active quad's UV's so the result is in a usable range.
.. _bpy.ops.uv.cube_project:

View File

@ -286,23 +286,33 @@ The *Pack Islands* tool can be used to optimize the UV layout by adjusting exist
to efficiently fill the :term:`Texture Space`. Based on the options selected,
the tool will scale, translate and rotate the islands,
ensuring a specified margin exists between them to maximize the usage of the UV space.
Pinned islands can have additional restrictions applied to customize the packing process even further.
Pack To
Determines the final placement of UV islands after completing the packing operation.
Shape Method
The method to use when considering the shape of each island.
:Closest UDIM: Pack islands to the :doc:`UDIM </modeling/meshes/uv/workflows/udims>` grid
nearest to the center of the selection.
:Active UDIM: Pack islands to the active UDIM image tile or, if no image is available,
the UDIM grid tile where the 2D cursor is located.
:Original bounding box: Find the original bounding box of the selection,
packs the islands, and then moves them back inside the original box.
:Exact Shape (Concave):
Use the complete shape of the island, including filling any holes or concave regions around the island.
:Boundary Shape (Convex):
Takes into account the boundary (Convex Hull) of the island.
This method will not place islands inside holes.
:Bounding Box: Uses the simple bounding box of the island.
Scale
Scale the islands to fill the unit square, or pack islands towards the lower left corner.
Rotate
Allows the rotation of islands, as well as translation and scaling, to optimize texture usage.
Merge Overlapped
Before the main packing operation, overlapping islands are detected and temporarily combined.
During packing, the relative rotation and position of the merged islands are preserved.
Rotation Method
The allowable rotations to use for each each island.
:Any:
Any rotation which improves the packing is allowed.
:Axis-aligned:
The island will first be rotated into a smallest rectangle. Additional rotation will only be in 90-degree turns.
:Cardinal: Like the four cardinal direction on a compass, North, South, East and West, only 90-degree turns will be allowed.
Margin Method
The method to use when calculating the empty space between islands.
@ -314,15 +324,30 @@ ensuring a specified margin exists between them to maximize the usage of the UV
Margin
The scale for the empty space between islands.
Shape Method
The method to use when considering the shape of each island.
Pinned Islands
An island which has any of it's UVs pinned is considered a *Pinned Island*.
With this option, you can change the way *Pinned Islands* are packed
:Exact shape (Concave):
Use the complete shape of the island, including filling any holes or concave regions around the island.
:Boundary shape (Convex):
Takes into account the boundary (Convex Hull) of the island.
This method will not place islands inside holes.
:Bounding box: Uses the simple bounding box of the island.
:Pack: *Pinned Islands* are packed in the same way as other islands.
:Lock Scale: The scale of the *Pinned Islands* will not change.
:Lock Rotation: *Pinned Islands* will not rotate.
:Lock Rotation and Scale: *Pinned Islands* can translate, but not scale nor rotate.
:Lock in Place: *Pinned Islands* will be unable to move. The other islands will pack around them.
:Ignore: Even if an island is selected, if it contains a pin, it will not be included in the *Pack Islands* calculation.
Merge Overlapping
Before the main packing operation, overlapping islands are detected and temporarily combined.
During packing, the relative rotation and position of the merged islands are preserved.
Pack To
Determines the final placement of UV islands after completing the packing operation.
:Closest UDIM: Pack islands to the :doc:`UDIM </modeling/meshes/uv/workflows/udims>` grid
nearest to the center of the selection.
:Active UDIM: Pack islands to the active UDIM image tile or, if no image is available,
the UDIM grid tile where the 2D cursor is located.
:Original bounding box: Find the original bounding box of the selection,
packs the islands, and then moves them back inside the original box.
.. note::

View File

@ -15,9 +15,12 @@ That particle system will control how the mesh is exploded.
Both the number of emitted particles and number of faces determine how granular the *Explode* modifier is.
More of each faces and particles will mean more individual pieces.
Here is a `demo video <https://archive.blender.org/wiki/index.php/File:Manual_-_Explode_Modifier_-_Exploding_Cube_-_
2.5.ogg/>`__ showing a cube with a particle system and *Explode* modifier. (`blend-file <https://archive.blender.org/
wiki/index.php/File:Manual_-_Explode_Modifier_-_Exploding_Cube_-_2.5.blend>`__).
Here is a
`demo video <https://archive.blender.org/wiki/index.php/File:Manual_-_Explode_Modifier_-_Exploding_Cube_
-_2.5.ogg/>`__
showing a cube with a particle system and *Explode* modifier.
(`blend-file <https://archive.blender.org/wiki/index.php/File:Manual_-_Explode_Modifier_-_Exploding_Cube_
-_2.5.blend>`__).
.. note::

View File

@ -49,8 +49,8 @@ Soft bodies are well suited for:
The following videos may give you some more ideas:
- https://www.youtube.com/watch?v=hLnY-OFUBzM
- https://www.youtube.com/watch?v=qdusMZlBbQ4
- `New Penguoen <https://www.youtube.com/watch?v=hLnY-OFUBzM>`__.
- `Blender Softbody Simulations <https://www.youtube.com/watch?v=qdusMZlBbQ4>`__.
Creating a Soft Body

View File

@ -240,4 +240,3 @@ In this case you can:
#. If you build Blender yourself, try to download and install a newer CUDA developer toolkit.
Normally users do not need to install the CUDA toolkit as Blender comes with precompiled kernels.

View File

@ -175,7 +175,7 @@ Training Samples
.. _bpy.types.CyclesRenderSettings.use_surface_guiding:
Surface
Enable path guiding for the diffuse component of surfaces.
Enable path guiding for the diffuse and glossy components of surfaces.
.. _bpy.types.CyclesRenderSettings.use_volume_guiding:

View File

@ -53,8 +53,8 @@ Falloff
.. figure:: /images/render_cycles_world-settings_mist-example1-BI.jpg
Mist example (`blend-file <https://archive.blender.org/wiki/index.php/File:25-Manual-World-Mist-
Example1.blend>`__).
Mist example
(`blend-file <https://archive.blender.org/wiki/index.php/File:25-Manual-World-Mist-Example1.blend>`__).
.. _bpy.types.CyclesVisibilitySettings.camera:

View File

@ -135,7 +135,7 @@ Size X, Y, Z
Sample Bias :guilabel:`Sculpt Mode`
Value added to texture samples.
This can be used if the midlevel of a height map is not correct.
This can be used if the mid-level of a height map is not correct.
.. _bpy.types.Brush.use_color_as_displacement:

View File

@ -12,7 +12,7 @@ When executed, it uniformly expand outwards a pattern from the vertex under the
These operators are meant to be used interactively through the shortcut.
There is also a `full showcase of the Expand features and use cases <https://www.youtube.com/watch?v=XT7h6lmE5bc>`_.
There is also a `full showcase of the Expand features and use cases <https://www.youtube.com/watch?v=XT7h6lmE5bc>`__.
.. figure:: /images/sculpt-paint_sculpting_expand_example.png

View File

@ -27,4 +27,4 @@ but other transform brushes like :doc:`Pose </sculpt_paint/sculpting/tools/pose>
:doc:`Boundary </sculpt_paint/sculpting/tools/boundary>` also support cloth sculpting in the brush settings.
A demo file for trying out the various brushes and tools is available
`here <https://www.blender.org/download/demo-files/#sculpting>`_.
`here <https://www.blender.org/download/demo-files/#sculpting>`__.

View File

@ -34,7 +34,7 @@ to displace geometry in three directions instead of just one.
.. figure:: /images/sculpt-paint_sculpt_vdm_example.png
:width: 580px
An example of various VDM brushes used on a smooth head from the offical demo file.
An example of various VDM brushes used on a smooth head from the official demo file.
For easy creation of VDM brushes, enable the :doc:`VDM Brush Baker </addons/baking/vdm_brush_baker>` addon.
`Download the demo file <https://www.blender.org/download/demo-files/#sculpting>`__

View File

@ -28,7 +28,7 @@ Expand
Snapping
^^^^^^^^
It is possible to enable snapping in the header of the VSE.
It is possible to enable snapping in the header of the Video Sequencer.
The snapping behavior can be configured as follows:
.. _bpy.types.SequencerToolSettings.snap_to_current_frame:

41
pyproject.toml Normal file
View File

@ -0,0 +1,41 @@
# SPDX-License-Identifier: GPL-2.0-or-later
[tool.autopep8]
# Configuration for `autopep8`, allowing the command: autopep8 .
# to reformat all source files.
#
# NOTE: the settings defined here map directly to command line arguments
# which will override these settings when passed in to autopep8.
max_line_length = 120
ignore = [
# Info: Use `isinstance()` instead of comparing types directly.
# Why disable? Changes code logic, in rare cases we want to compare exact types.
"E721",
# Info: Fix bare except.
# Why disable? Disruptive, leave our exceptions alone.
"E722",
# Info: Fix module level import not at top of file.
# Why disable? Re-ordering imports is disruptive and breaks some scripts
# that need to check if a module has already been loaded in the case of reloading.
"E402",
# Info: Fix various deprecated code (via lib2to3)
# Why disable? Does nothing besides incorrectly adding a duplicate import,
# could be reported as a bug except this is likely to be removed soon, see:
# https://github.com/python/cpython/issues/84540.
"W690",
]
# Use aggressive as many useful edits are disabled unless it's enabled.
# Any edits which are overly disruptive or risky can be removed in the `ignore` list.
aggressive = 2
# Exclude:
# - `./tools/svn_rev_map` because it's a large data-file.
exclude = """
./tools/svn_rev_map/sha1_to_rev.py,
"""
# Omit settings such as `jobs`, `in_place` & `recursive` as they can cause editor utilities that auto-format on save
# to fail if the STDIN/STDOUT is used for formatting (which isn't compatible with these options).

File diff suppressed because it is too large Load Diff

View File

@ -1,325 +1,188 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# <pep8 compliant>
"""
This script extracts RST fro Blender's "--help",
using simple conventions & REGEX parsing.
Example:
python tools_maintenance/blender_help_extract.py /path/to/blender manual/advanced/command_line/arguments.rst
"""
# Conversion from There are some cases which aren't handled (and aren't needed at the moment),
# noting for completeness.
#
# - Multi-line code-blocks as each block is currently only a single line.
# - Skip parsing text inside comment blocks (literal quoting single brackets for e.g.).
import os
import re
# This script extracts the '--help' message from Blender's source code,
# using primitive regex parsing.
#
# e.g:
# python tools_maintenance/blender_help_extract.py \
# ../blender/source/creator/creator_args.c \
# manual/advanced/command_line/arguments.rst
import subprocess
def text_remove_comments(text):
def replacer(match):
s = match.group(0)
if s.startswith('/'):
return " "
else:
return s
pattern = re.compile(
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.DOTALL | re.MULTILINE
)
return re.sub(pattern, replacer, text)
def text_remove_preprocess(text):
lines = text.split("\n")
non_comment_lines = [line for line in lines if not line.strip().startswith("#")]
return "\n".join(non_comment_lines)
def text_join_lines(text):
lines = text.split("\n")
lines_out = [[]]
for l in lines:
lines_out[-1].append(l)
if l.endswith((";", "{", ")", "}")) or l.lstrip().startswith("#"):
lines_out.append([])
text = "\n".join(
[
" ".join(l.lstrip() if i != 0 else l for i, l in enumerate(l_group))
for l_group in lines_out
]
def help_text_make_version_and_usage_substitution(text: str) -> str:
text = re.sub(
re.compile(r"^(Blender) +\d.*\n(Usage:) +(.*)$", flags=re.MULTILINE),
lambda x: (
"| {:s} |BLENDER_VERSION|\n"
"| {:s} ``{:s}``"
).format(x.group(1), x.group(2), x.group(3)),
text,
)
return text
def text_expand_macros(text):
# CB() macro
def replacer_CB(match):
return match.group(2) + "_doc, " + match.group(2)
def help_text_make_args_literal(text: str) -> str:
pattern_CB = re.compile(
r'\b(CB)\s*\(([^\,]+)\)',
re.DOTALL | re.MULTILINE
re_content_table = (
(
re.compile(r"(\-+[A-Za-z\-]+)"),
lambda x: "``" + x.group(1) + "``",
),
)
# CB_EX() macro
def replacer_CB_EX(match):
return match.group(2) + "_doc_" + match.group(3) + ", " + match.group(2)
re_argument_line = re.compile(r"^(\s*)(\-+[A-Za-z\-]+.*)$", flags=re.MULTILINE)
pattern_CB_EX = re.compile(
r'\b(CB_EX)\s*\(([^\,]+),\s*([^\)]+)\)',
re.DOTALL | re.MULTILINE
def re_argument_line_fn(x: re.Match[str]) -> str:
indent = x.group(1)
content = x.group(2)
for re_expr, re_fn in re_content_table:
content = re.sub(re_expr, re_fn, content)
# Weak but works to replace or's with commas.
content = content.replace("`` or ``-", "``, ``-", 1)
return indent + content
text = re.sub(re_argument_line, re_argument_line_fn, text)
return text
def help_text_make_single_quotes_literal(text: str) -> str:
re_table = (
(
re.compile(r"(\s+)'([^\']+)'"),
lambda x: x.group(1) + "``" + x.group(2) + "``",
),
(
re.compile(r"([-+]?<[A-Za-z_0-9\(\)]+>)"),
lambda x: "``" + x.group(1) + "``",
),
)
# STRINGIFY_ARG() macro
def replacer_STRINGIFY_ARG(match):
return "\"``" + match.group(2) + "``\""
pattern_STRINGIFY_ARG = re.compile(
r'\b(STRINGIFY_ARG)\s*\(([^\)]+)\)',
re.DOTALL | re.MULTILINE
)
text = re.sub(pattern_CB, replacer_CB, text)
text = re.sub(pattern_CB_EX, replacer_CB_EX, text)
text = re.sub(pattern_STRINGIFY_ARG, replacer_STRINGIFY_ARG, text)
for re_expr, re_fn in re_table:
text = re.sub(re_expr, re_fn, text)
return text
def text_extract_args(text):
def help_text_make_title_and_dedent(text: str) -> str:
re_title = re.compile(r"\n\n([A-Z][^:]+):$", flags=re.MULTILINE)
title_char = "="
args = {}
# use replace to scan (misuse!)
def re_title_fn(x: re.Match[str]) -> str:
heading = x.group(1)
return (
"\n"
"\n"
".. _command-line-args-{:s}:\n"
"\n"
"{:s}\n"
"{:s}\n"
).format(
"".join([(c if c.isalpha() else "-") for c in heading.lower()]),
heading,
(title_char * len(heading)),
)
def replacer(match):
fn = match.group(1)
s = match.group(2)
text = re.sub(re_title, re_title_fn, text)
# remove first 2 args
s = s.split(',', 1)[-1]
# remove last 2 args
s = s.rsplit(',', 2)[0]
# Un-indent entirely indented blocks (directly after the title).
lines = text.splitlines(keepends=False)
i = 0
while i < len(lines):
if not (lines[i].startswith(title_char) and lines[i].strip(title_char) == ""):
# Not a title, continue.
i += 1
continue
if fn == "BLI_args_add":
# get first 2 args
arg_short, arg_long, s = [w.strip() for w in s.split(",", 2)]
elif fn == "BLI_args_add_case":
# get first 2 args
arg_short, _, arg_long, _, s = [w.strip() for w in s.split(",", 4)]
del _
else:
# should never happen
raise Exception("Bad function call %r" % fn)
# We have a title, check the next non-blank line.
i_next = i + 1
while lines[i_next] == "":
i_next += 1
if not lines[i_next].startswith(" "):
# No indentation, continue.
i = i_next
continue
if arg_short == "NULL":
arg_short = None
else:
arg_short = eval(arg_short, {})
if arg_long == "NULL":
arg_long = None
else:
arg_long = eval(arg_long, {})
args[arg_short, arg_long] = s
# print(arg_short, arg_long, s)
pattern = re.compile(
r'\b(BLI_args_add[_case]*)\s*\(((?:(?!\)\s*;).)*?)\)\s*;',
re.DOTALL | re.MULTILINE
)
re.sub(pattern, replacer, text)
return args
def text_extract_strings(text):
strings = {}
# use replace to scan (misuse!)
text = (
text
).replace(
"PY_ENABLE_AUTO", " \" (default)\""
).replace(
"PY_DISABLE_AUTO", " \"\""
).replace(
"STRINGIFY(BLENDER_STARTUP_FILE)", "\"startup.blend\""
).replace(
"STRINGIFY(BLENDER_MAX_THREADS)", "\"1024\""
)
def replacer(match):
var = match.group(1).strip()
s = match.group(2)
s = " ".join([w.strip() for w in s.split("\n")])
s = eval(s, {})
strings[var] = s
pattern = re.compile(
r'\bstatic\s+const\s+char\s+([A-Za-z0-9_]+)\[\]\s*=\s*((?:(?!"\s*;).)*?")\s*;',
re.DOTALL | re.MULTILINE
)
re.sub(pattern, replacer, text)
return strings
def text_extract_help(text, args, static_strings):
func_id = 'static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)\n'
index_start = text.find(func_id)
assert(index_start != -1)
index_end = text.find("exit(0);", index_start)
# print(index_start, index_end)
body = text[index_start + len(func_id):index_end]
body = [l for l in body.split("\n") if not l.strip().startswith("#")]
body = [l.strip() for l in body]
body = [l for l in body if l]
# args dicts
args_short = {}
args_long = {}
args_used = set()
for (arg_short, arg_long), value in args.items():
if arg_short is not None:
args_short[arg_short] = (arg_short, arg_long), value
if arg_long is not None:
args_long[arg_long] = (arg_short, arg_long), value
# there is some overlap in short/long args, second pass to fix
# by assigning long-only
for (arg_short, arg_long), value in args.items():
if arg_short is not None:
if arg_long is None:
args_short[arg_short] = (arg_short, arg_long), value
def args_get(arg):
value = args_long.get(arg)
if value is None:
value = args_short.get(arg)
if value is None:
raise Exception("Can't find %r" % arg)
return value
text_rst = []
# execute the code!
other_vars = {
"BKE_blender_version_string": lambda: "|BLENDER_VERSION|",
}
def write_arg(arg):
(arg_short, arg_long), arg_text = args_get(arg)
args_used.add((arg_short, arg_long))
# replacement table
arg_text = re.sub(r"\"\s*STRINGIFY_ARG\s*\(([a-zA-Z0-9_]+)\)\"", r"``\1``", arg_text)
arg_text = arg_text.replace('" STRINGIFY(BLENDER_MAX_THREADS) "', "64")
arg_text = arg_text.replace('" STRINGIFY(BLENDER_STARTUP_FILE) "', "startup.blend")
arg_text = arg_text.replace('" PY_ENABLE_AUTO', '\"')
arg_text = arg_text.replace('" PY_DISABLE_AUTO', ', (default).\"')
# print(arg_text)
arg_text = eval(arg_text, static_strings)
arg_text = arg_text.replace("\t", " ")
text_rst.append("``" + "``, ``".join([w for w in (arg_short, arg_long) if w is not None]) + "`` ")
text_rst.append(arg_text + "\n")
ind_re = None
for l in body:
if l.startswith("printf"):
l = eval(l.replace("printf(", "").replace(");", ""), other_vars)
if type(l) is tuple:
# Run the C-style string format.
l = l[0] % l[1:]
if l.lstrip() == l and l.strip("\n").endswith(":"):
# Create RST heading & unique reference target.
l = l.strip(":\n")
l = (
"\n"
"\n"
".. _command-line-args-%s:\n"
"\n"
"%s\n"
"%s\n"
"\n"
) % (
# Create reference so each heading can be linked to.
"".join([(c if c.isalpha() else "-") for c in l.lower()]),
# The heading.
l,
# Heading underline.
len(l) * "=",
)
ind_re = None
# Measure indent and de-dent until indentation not met.
indent_len = len(lines[i_next]) - len(lines[i_next].lstrip())
indent = " " * indent_len
while i_next < len(lines):
if lines[i_next].startswith(indent):
lines[i_next] = lines[i_next][indent_len:]
elif lines[i_next] == "":
pass
else:
# unindent to the previous min indent
for _ in range(2):
if ind_re is None:
ind_re = r"\A\t{0,}"
ind_m = re.match(ind_re, l)
if ind_m:
ind_re = r"\A\t{" + str(ind_m.end(0)) + r"}"
l = re.sub(ind_re, '', l)
break
else:
# indent is less than before
ind_re = None
break
i_next += 1
l = l.replace("\t", " ")
i = i_next
text_rst.append(l)
elif l.startswith("BLI_args_print_arg_doc("):
arg = l.split(",")[-1].strip(");\n")
arg = eval(arg, {})
write_arg(arg)
elif l.startswith("BLI_args_print_other_doc("):
items = list(args.items())
# sort as strings since we can't order (None <> str)
items.sort(key=lambda i: str(i[0]))
for key, value in items:
if key not in args_used:
write_arg(key[0] or key[1])
text = "\n".join(lines)
text_rst = "".join(text_rst)
return text
# not essential, but nice to have <word> as ``<word>``
text_rst = re.sub(r"([\+\-]*<[a-zA-Z0-9\(\)_\-]+>)", r"``\1``", text_rst)
# ------
# Post process (formatting)
# text_rst = re.split(r"\\n|[()]", text_rst)
text_rst = text_rst.splitlines()
def help_text_make_environment_variables(text: str) -> str:
env_vars = []
for i, l in enumerate(text_rst):
# detect env var list
l_strip = l.lstrip()
if l_strip.startswith("$"):
l_strip, l_tail = l_strip.lstrip("$").split(" ", 1)
if l_strip.isupper():
l = ":%s: %s" % (l_strip, l_tail)
del l_tail
elif l_strip.startswith("#"):
indent = l[:len(l) - len(l_strip)]
l = "\n" + indent + ".. code-block:: sh\n\n" + indent + " " + l.lstrip("# ") + "\n"
else:
# use "'" as "``", except when used as plural, e.g. "Python's"
l = re.sub("(?<![a-z])'|'(?![st])", "``", l)
del l_strip
# Single lines.
re_env = re.compile(r"^(\s*)\$([A-Z][A-Z0-9_]*)(\s+)", flags=re.MULTILINE)
text_rst[i] = l.rstrip(" ")
def re_env_fn(x: re.Match[str]) -> str:
env_var = x.group(2)
env_vars.append(env_var)
return x.group(1) + ":" + env_var + ":" + x.group(3)
# finally, make switches literal if they proceed literal args
# or have their own line.
# -a ``<b>`` ... --> ``-a`` ``<b>``
# and...
# -a --> ``-a``
for i, l in enumerate(text_rst):
if l.lstrip().startswith("-"):
l = re.sub(r"(\s+)(\-[a-z])(\s+``)", r"\1``\2``\3", l)
l = re.sub(r"^(\s+)(\-[a-z])$", r"\1``\2``", l)
text_rst[i] = l
text = re.sub(re_env, re_env_fn, text)
text_rst = [
".. DO NOT EDIT THIS FILE, GENERATED BY %r\n" % os.path.basename(__file__),
def re_env_var_quote_fn(x: re.Match[str]) -> str:
beg, end = x.span(1)
# Ignore environment variables that were just converted into field definitions.
if x.string[beg - 1] == ":" and x.string[end] == ":":
# Do nothing.
return x.group(1)
return "``" + x.group(1) + "``"
# Now literal quote all environment variables.
re_env_var_quote = re.compile(r"\b({:s}\b)".format("|".join(env_vars)))
text = re.sub(re_env_var_quote, re_env_var_quote_fn, text)
return text
def help_text_make_code_blocks(text: str) -> str:
re_code_block = re.compile(r"^(\s*)(# .*)$", flags=re.MULTILINE)
def re_code_block_fn(x: re.Match[str]) -> str:
indent = x.group(1)
content = x.group(2)
return (
"\n"
"{:s}.. code-block:: sh\n"
"\n"
"{:s} {:s}\n"
).format(indent, indent, content[1:].lstrip())
text = re.sub(re_code_block, re_code_block_fn, text)
return text
def help_text_as_rst(text: str) -> str:
text_header = (
".. DO NOT EDIT THIS FILE, GENERATED BY '{:s}'\n"
"\n"
" CHANGES TO THIS FILE MUST BE MADE IN BLENDER'S SOURCE CODE, SEE:\n"
" https://projects.blender.org/blender/blender/src/branch/main/source/creator/creator_args.c\n"
@ -330,46 +193,69 @@ def text_extract_help(text, args, static_strings):
"Command Line Arguments\n"
"**********************\n"
"\n"
] + text_rst
).format(os.path.basename(__file__))
text_rst = "\n".join(text_rst)
text_rst = text_rst + "\n"
text_rst = text_rst.replace("\n\n\n\n", "\n\n\n")
# Expand tabs & strip trailing space.
text = text.expandtabs(3)
text = "\n".join([line.rstrip() for line in text.splitlines()]) + "\n"
return text_rst
text = help_text_make_version_and_usage_substitution(text)
text = help_text_make_args_literal(text)
text = help_text_make_single_quotes_literal(text)
text = help_text_make_title_and_dedent(text)
text = help_text_make_environment_variables(text)
text = help_text_make_code_blocks(text)
# Hack: `/?` is a special case.
text = text.replace("\n/?\n", "\n``/?``\n", 1)
# Apply the header last (no need for it to be parsed).
return text_header + text
def main():
def main() -> None:
import sys
source_file = sys.argv[-2]
blender_bin = sys.argv[-2]
output_file = sys.argv[-1]
if not source_file.endswith("creator_args.c"):
print("Expected 'creator_args.c' to be passed as the second last argument")
return
if not output_file.endswith(".rst"):
print("Expected an '.rst' file to be passed as the last argument")
return
with open(source_file, 'r') as f:
text = f.read()
env = os.environ.copy()
env["ASAN_OPTIONS"] = (
env.get("ASAN_OPTIONS", "") +
":exitcode=0:check_initialization_order=0:strict_init_order=0:detect_leaks=0"
)
text = text_remove_comments(text)
text = text_remove_preprocess(text)
# join ',\n' - function args split across lines.
text = text_join_lines(text)
# expand CB macros
text = text_expand_macros(text)
# first pass, extract 'BLI_args_add'
text_beg = "BEGIN_BLOCK"
text_end = "END_BLOCK"
text = subprocess.check_output(
[
blender_bin,
"--factory-startup",
"--background",
"--python-exit-code", "1",
"--python-expr",
# Code begin/end text because of Blender's chatty reporting of version and that it quit.
(
"print("
"'{:s}\\n' + "
"__import__('bpy').app.help_text(all=True) + "
"'\\n{:s}'"
")"
).format(text_beg, text_end),
],
env=env,
).decode("utf-8")
args = text_extract_args(text)
# Extract between begin/end markers.
text = text[text.find(text_beg) + len(text_beg) + 1: text.find(text_end)]
static_strings = text_extract_strings(text)
text_rst = help_text_as_rst(text)
text_rst = text_extract_help(text, args, static_strings)
with open(output_file, 'w') as f:
f.write(text_rst)
with open(output_file, "w", encoding="utf-8") as fh:
fh.write(text_rst)
if __name__ == "__main__":

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# Copyright 2015 Anton Felix Lorenzen <anfelor@web.de>
# <pep8 compliant>
'''
Module of Translation Tracker: report the number of complete strings in a file.

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# Copyright 2015 Anton Felix Lorenzen <anfelor@web.de>
# <pep8 compliant>
'''
Translation Tracker: report the number of complete translations.

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# <pep8 compliant>
# DEVELOPER NOTE:
#

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# <pep8 compliant>
"""
This utility checks naming conventions (Blender specific).

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# <pep8 compliant>
"""
This utility checks image paths:

View File

@ -49,56 +49,91 @@ def check_word(w):
return dict_spelling.check(w)
def regex_key_raise(x):
raise Exception("Unknown role! " + "".join(x.groups()))
# A table of regex and their replacement functions.
#
# This is used to clean up text from `docutils.nodes.NodeVisitor.visit_Text` which doesn't remove inline markup.
# Note that in some cases the order matters, especially with include/excluding roles.
RE_TEXT_REPLACE_ROLES_INCLUDE = ("menuselection", "guilabel")
RE_TEXT_REPLACE_ROLES_EXCLUDE = ("kbd", "ref", "doc", "abbr")
RE_TEXT_REPLACE_TABLE = (
# Match HTML link: `Text <url>`__
# A URL may span multiple lines.
(
re.compile(r"(`)([^`<]+)(<[^`>]+>)(`)(__)", re.MULTILINE),
lambda x: x.groups()[1].strip(),
),
# Roles with plain-text: :some_role:`Text <ref>`
(
re.compile(r"(:[A-Za-z_]+:)(`)([^`<]+)(<[^`>]+>)(`)", flags=re.MULTILINE),
lambda x: x.groups()[2].strip(),
),
# Roles to always include.
(
re.compile(r"(:(" + ("|".join(RE_TEXT_REPLACE_ROLES_INCLUDE)) + r"):)(`)([^`]+)(`)", flags=re.MULTILINE),
lambda x: x.groups()[3].strip(),
),
# Roles to always exclude.
(
re.compile(r"(:(" + ("|".join(RE_TEXT_REPLACE_ROLES_EXCLUDE)) + r"):)(`)([^`]+)(`)", flags=re.MULTILINE),
lambda _: " ",
),
# Ensure all roles are handled.
(
re.compile(r"(:[A-Za-z_]+:)(`)([^`]+)(`)", flags=re.MULTILINE),
regex_key_raise,
),
# Match substitution for removal: `|identifier|`
(
re.compile(r"\|[a-zA-Z0-9_]+\|"),
lambda _: " ",
),
)
RE_WORDS = re.compile(
r"\b("
# Capital words, with optional '-' and "'".
r"[A-Z]+[\-'A-Z]*[A-Z]|"
# Lowercase words, with optional '-' and "'".
r"[A-Za-z][\-'a-z]*[a-z]+"
r")\b"
)
def check_spelling_body(text):
for w in text.split():
# skip directive args (e.g. figure target), could do differently?
if w.startswith(":") and w.endswith(":"):
continue
if w.startswith("<") and w.endswith(">"):
# Wash text or inline RST.
for re_expr, re_replace_fn in RE_TEXT_REPLACE_TABLE:
text = re.sub(re_expr, re_replace_fn, text)
for re_match in RE_WORDS.finditer(text):
w = re_match.group(0)
# Skip entirely uppercase words.
# These are typically used for acronyms: XYZ, UDIM, API ... etc.
if w.isupper():
continue
w = w.strip("{}[](),.!?;\"'1234567890-_*")
w_lower = w.lower()
if w.startswith(":") and w.endswith(":"):
continue
if w.startswith("<") and w.endswith(">"):
if USE_ONCE and w_lower in once_words:
continue
# skip character and name entities
if w.startswith("\\") or w.startswith("|"):
continue
if check_word(w):
pass
elif "-" in w and all(check_word(w_split) for w_split in w.split("-")):
pass # all words split by dash are correct, also pass
else:
bad_words.add(w)
# print(" %r" % w)
# now we've gotten rid of typical roles, strip other chars
w = w.strip(":`()<>{}")
# skip python references
if w.startswith("bpy."):
continue
# skip document references and keyboard shortcuts
if w.startswith("doc:") or w.startswith("kbd:") or w.startswith("menuselection:") or w.startswith("ref:"):
continue
w_ = w
for w in w_.split("/"):
if not w:
continue
w_lower = w.lower()
if USE_ONCE and w_lower in once_words:
continue
if check_word(w):
pass
elif "-" in w and all(check_word(w_split) for w_split in w.split("-")):
pass # all words split by dash are correct, also pass
else:
bad_words.add(w)
# print(" %r" % w)
if USE_ONCE:
once_words.add(w_lower)
if USE_ONCE:
once_words.add(w_lower)
CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
@ -192,6 +227,7 @@ directives.register_directive('highlight', directive_ignore_recursive)
directives.register_directive('parsed-literal', directive_ignore_recursive)
# Custom directives from extensions
directives.register_directive('youtube', directive_ignore_recursive)
directives.register_directive('peertube', directive_ignore_recursive)
directives.register_directive('vimeo', directive_ignore_recursive)
directives.register_directive('todolist', directive_ignore_recursive)
@ -223,7 +259,7 @@ def role_ignore_recursive(
name, rawtext, text, lineno, inliner,
options={}, content=[],
):
return [RoleIgnore("", '', *(), **{})], []
return [RoleIgnoreRecursive("", '', *(), **{})], []
roles.register_canonical_role('abbr', role_ignore)
@ -306,13 +342,21 @@ def check_spelling(filename):
doc.walkabout(visitor)
RST_CONTEXT_FLAG_LITERAL = 1 << 0
RST_CONTEXT_FLAG_LITERAL_BLOCK = 1 << 1
RST_CONTEXT_FLAG_MATH = 1 << 2
RST_CONTEXT_FLAG_COMMENT = 1 << 3
class RstSpellingVisitor(docutils.nodes.NodeVisitor):
__slots__ = (
"document",
"skip_context",
)
def __init__(self, doc):
self.document = doc
self.skip_context = 0
# -----------------------------
# Visitors (docutils callbacks)
@ -400,8 +444,10 @@ class RstSpellingVisitor(docutils.nodes.NodeVisitor):
# check_spelling_body(text)
def visit_Text(self, node):
# Visiting text in a sipped context (literal for example).
if self.skip_context:
return
text = node.astext()
# print(text)
check_spelling_body(text)
def depart_Text(self, node):
@ -420,37 +466,48 @@ class RstSpellingVisitor(docutils.nodes.NodeVisitor):
self.is_emphasis = False
def visit_math(self, node):
self.skip_context |= RST_CONTEXT_FLAG_MATH
raise docutils.nodes.SkipNode
def depart_math(self, node):
pass
self.skip_context &= ~RST_CONTEXT_FLAG_MATH
def visit_literal(self, node):
self.skip_context |= RST_CONTEXT_FLAG_LITERAL
raise docutils.nodes.SkipNode
def depart_literal(self, node):
pass
self.skip_context &= ~RST_CONTEXT_FLAG_LITERAL
def visit_literal_block(self, node):
self.skip_context |= RST_CONTEXT_FLAG_LITERAL_BLOCK
raise docutils.nodes.SkipNode
def depart_literal_block(self, node):
self.skip_context &= ~RST_CONTEXT_FLAG_LITERAL_BLOCK
pass
def visit_code_block(self, node):
# No need to flag.
raise docutils.nodes.SkipNode
def depart_code_block(self, node):
pass
def visit_reference(self, node):
raise docutils.nodes.SkipNode
pass
def depart_reference(self, node):
pass
def visit_title_reference(self, node):
pass
def depart_title_reference(self, node):
pass
def visit_download_reference(self, node):
raise docutils.nodes.SkipNode
pass
def depart_download_reference(self, node):
pass
@ -458,7 +515,7 @@ class RstSpellingVisitor(docutils.nodes.NodeVisitor):
def visit_date(self, node):
# date = datetime.date(*(
# map(int, unicode(node[0]).split('-'))))
#metadata['creation_date'] = date
# metadata['creation_date'] = date
pass
# def visit_document(self, node):
@ -466,10 +523,11 @@ class RstSpellingVisitor(docutils.nodes.NodeVisitor):
# # metadata['searchable_text'] = node.astext()
def visit_comment(self, node):
self.skip_context |= RST_CONTEXT_FLAG_COMMENT
raise docutils.nodes.SkipNode
def depart_comment(self, node):
pass
self.skip_context &= ~RST_CONTEXT_FLAG_COMMENT
def visit_raw(self, node):
raise docutils.nodes.SkipNode

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# <pep8 compliant>
import os
import sys

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# <pep8 compliant>
import os
import io

View File

@ -18,8 +18,6 @@
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
__all__ = (
"role_iter",
"directive_iter",

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# <pep8 compliant>
"""
General purpose tool for remapping directory structure of RestructuredText documents.

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
# Apache License, Version 2.0
# <pep8 compliant>
"""
Remap RST title levels

View File

@ -178,7 +178,7 @@ def main(argv=None):
print("Role", role_id, "not handled!", file=sys.stderr)
sys.exit(1)
assert(line is not None)
assert (line is not None)
print("%s:%d:%d" % (fn, line, col))