Python3.12環境で出るSyntaxWarning対応¶
- これはDoxygen用に \param と記述している部分で、
- Python の文字列 → \p を無効なエスケープと解釈する
- Doxygen の構文 → \param を必要としている
- OpenRTM-aist-Pythonソース全体を置換するシェルスクリプトをChatGPTに教えてもらう
- Doxygen向けのキーワードは param 以外もあるそうなので、それらも含めて一括置換する
複数のDoxygenキーワードを一括置換するスクリプト¶
- \param等の Doxygen キーワードを 一括で「単一バックスラッシュ → 二重バックスラッシュ」に変換し、
既に \\keyword になっている箇所はスキップするスクリプト
(Perl の負の後読みを使って安全に置換します)
- 対象キーワードは初期設定で以下です(必要に応じて編集する):
param, return, brief, retval, note, warning, deprecated, tparam, sa
- fix_doxygen_escapes.sh
- bash 以外で起動されたら自動で bash で再実行するガード付き版
(Ubuntu 24.04 で動作、mapfile 非依存にし、xargs -0 で安全に全 .py を処理)
#!/usr/bin/env bash
# Convert selected Doxygen commands like \param -> \\param in Python files,
# preserving already-escaped tokens (\\param etc).
# Usage:
# ./fix_doxygen_escapes.sh [clone_dir]
#
# Default repo: OpenRTM/OpenRTM-aist-Python
# --- Re-exec with bash if not already bash ---
if [ -z "${BASH_VERSION:-}" ]; then
exec bash "$0" "$@"
fi
set -euo pipefail
REPO_URL="https://github.com/OpenRTM/OpenRTM-aist-Python.git"
CLONE_DIR="${1:-OpenRTM-aist-Python}"
# --- Customize target keywords here (no leading backslashes) ---
KEYWORDS=(
param
return
brief
retval
note
warning
deprecated
tparam
sa
)
# --------------------------------------------------------------
command -v git >/dev/null 2>&1 || { echo "ERROR: git not found."; exit 1; }
command -v perl >/dev/null 2>&1 || { echo "ERROR: perl not found."; exit 1; }
command -v grep >/dev/null 2>&1 || { echo "ERROR: grep not found."; exit 1; }
command -v find >/dev/null 2>&1 || { echo "ERROR: find not found."; exit 1; }
command -v xargs >/dev/null 2>&1 || { echo "ERROR: xargs not found."; exit 1; }
echo "Cloning repo..."
git clone --depth 1 "$REPO_URL" "$CLONE_DIR"
cd "$CLONE_DIR"
BRANCH="fix/docstring-escape-doxygen"
echo "Creating branch $BRANCH ..."
git checkout -b "$BRANCH"
echo "Building keyword regex..."
KEYWORD_RE="$(printf '%s|' "${KEYWORDS[@]}")"
KEYWORD_RE="${KEYWORD_RE%|}"
echo "Finding Python files and applying replacements for: ${KEYWORDS[*]}"
# Replace only single-backslash tokens: (?<!\\)\(backslash)(param|...)\b -> \\$1
# (negative lookbehind ensures already-escaped \\keyword are skipped)
find . -type d -name .git -prune -o \
-type d -name venv -prune -o \
-type f -name "*.py" -print0 |
xargs -0 -r perl -0777 -i -pe "s/(?<!\\\\)\\\\(${KEYWORD_RE})\\b/\\\\\\\\\\1/g"
echo "Replacement done."
echo
echo "Summary of changes:"
git status --porcelain | awk '$1 ~ /M/ {print $2}'
echo
git diff --stat || true
echo
echo "Quick scan (candidates with single backslash, for review):"
# If your grep supports PCRE (-P), this precisely lists remaining single-backslash tokens.
if grep -R --line-number -P "(?<!\\\\)\\\\(${KEYWORD_RE})\\b" --include="*.py" . >/dev/null 2>&1; then
grep -R --line-number -P "(?<!\\\\)\\\\(${KEYWORD_RE})\\b" --include="*.py" . || true
else
# Fallback: broader hint (may include already-escaped ones)
grep -R --line-number --include="*.py" -E "\\\\(${KEYWORD_RE})\\b" . || true
fi
echo
echo "Already-escaped double-backslash occurrences (for reference):"
grep -R --line-number --include="*.py" -E "\\\\\\\\(${KEYWORD_RE})\\b" . || true
echo
read -r -p "Commit changes? [y/N] " ans
if [[ "${ans:-N}" =~ ^[Yy]$ ]]; then
git add -A
git commit -m "docs: escape Doxygen \\keyword as \\\\keyword in Python docstrings (${KEYWORDS[*]})"
echo "Committed. You can now push the branch:"
echo " git push -u origin $BRANCH"
else
echo "Changes are left unstaged. Review with 'git diff' if needed."
fi
一括置換結果¶
$ ./fix_doxygen_escapes.sh
Cloning repo...
Cloning into 'OpenRTM-aist-Python'...
remote: Enumerating objects: 516, done.
remote: Counting objects: 100% (516/516), done.
remote: Compressing objects: 100% (352/352), done.
remote: Total 516 (delta 194), reused 373 (delta 151), pack-reused 0 (from 0)
Receiving objects: 100% (516/516), 766.54 KiB | 907.00 KiB/s, done.
Resolving deltas: 100% (194/194), done.
Creating branch fix/docstring-escape-doxygen ...
Switched to a new branch 'fix/docstring-escape-doxygen'
Building keyword regex...
Finding Python files and applying replacements for: param return brief retval note warning deprecated tparam sa
Replacement done.
Summary of changes:
OpenRTM_aist/CorbaNaming.py
OpenRTM_aist/CorbaPort.py
OpenRTM_aist/DataFlowComponentBase.py
OpenRTM_aist/DefaultConfiguration.py
OpenRTM_aist/ECFactory.py
OpenRTM_aist/PortBase.py
OpenRTM_aist/Process.py
OpenRTM_aist/examples/AutoTest/AutoTestIn.py
OpenRTM_aist/examples/AutoTest/AutoTestOut.py
OpenRTM_aist/examples/TkJoyStick/TkJoyStickComp.py
OpenRTM_aist/ext/ssl/test/test_SSLTransport.py
OpenRTM_aist/CorbaNaming.py | 2 +-
OpenRTM_aist/CorbaPort.py | 2 +-
OpenRTM_aist/DataFlowComponentBase.py | 2 +-
OpenRTM_aist/DefaultConfiguration.py | 2 +-
OpenRTM_aist/ECFactory.py | 2 +-
OpenRTM_aist/PortBase.py | 30 +++++++++++++++---------------
OpenRTM_aist/Process.py | 2 +-
OpenRTM_aist/examples/AutoTest/AutoTestIn.py | 6 +++---
OpenRTM_aist/examples/AutoTest/AutoTestOut.py | 4 ++--
OpenRTM_aist/examples/TkJoyStick/TkJoyStickComp.py | 2 +-
OpenRTM_aist/ext/ssl/test/test_SSLTransport.py | 2 +-
11 files changed, 28 insertions(+), 28 deletions(-)
Quick scan (candidates with single backslash, for review):
./OpenRTM_aist/CorbaPort.py:6:# \\brief CorbaPort class
./OpenRTM_aist/ECFactory.py:25:# \\param ec 破棄対象ExecutionContextのインスタンス
./OpenRTM_aist/DefaultConfiguration.py:6:# \\brief RTC manager default configuration
./OpenRTM_aist/CorbaNaming.py:7:# \\brief CORBA naming service helper class
./OpenRTM_aist/examples/TkJoyStick/TkJoyStickComp.py:78: \\brief Converting from canvas data to MobileRobotCanvas data
./OpenRTM_aist/examples/AutoTest/AutoTestIn.py:86: \\brief ModuleDescription
./OpenRTM_aist/examples/AutoTest/AutoTestIn.py:92: \\brief constructor
./OpenRTM_aist/examples/AutoTest/AutoTestIn.py:93: \\param manager Maneger Object
./OpenRTM_aist/examples/AutoTest/AutoTestOut.py:7: \\brief ModuleDescription
./OpenRTM_aist/examples/AutoTest/AutoTestOut.py:58: \\brief ModuleDescription
./OpenRTM_aist/DataFlowComponentBase.py:6:# \\brief DataFlowParticipant RT-Component base class
./OpenRTM_aist/ext/ssl/test/test_SSLTransport.py:6:# \\brief
./OpenRTM_aist/Process.py:7:# \\brief Process handling functions
./OpenRTM_aist/PortBase.py:2465: \\param id_(string)
./OpenRTM_aist/PortBase.py:2471: \\param cprof(RTC.ConnectorProfile)
./OpenRTM_aist/PortBase.py:2485: \\param port_ref(RTC.PortService)
./OpenRTM_aist/PortBase.py:2491: \\param port_ref(RTC.PortService)
./OpenRTM_aist/PortBase.py:2505: \\param p(RTC.PortService)
./OpenRTM_aist/PortBase.py:2506: \\param prof(RTC.ConnectorProfile)
./OpenRTM_aist/PortBase.py:2514: \\param p(RTC.PortService)
./OpenRTM_aist/PortBase.py:2531: \\param p(RTC.PortService)
./OpenRTM_aist/PortBase.py:2532: \\param prof(RTC.ConnectorProfile)
./OpenRTM_aist/PortBase.py:2540: \\param p(RTC.PortService)
./OpenRTM_aist/PortBase.py:2557: \\param p(OpenRTM_aist.PortBase)
./OpenRTM_aist/PortBase.py:2564: \\param p(RTC.ConnectorProfile)
./OpenRTM_aist/PortBase.py:2580: \\param name(string)
./OpenRTM_aist/PortBase.py:2581: \\param pol(RTC.PortInterfacePolarity)
./OpenRTM_aist/PortBase.py:2588: \\param prof(RTC.PortInterfaceProfile)
Already-escaped double-backslash occurrences (for reference):
./OpenRTM_aist/CorbaPort.py:6:# \\brief CorbaPort class
./OpenRTM_aist/ECFactory.py:25:# \\param ec 破棄対象ExecutionContextのインスタンス
./OpenRTM_aist/DefaultConfiguration.py:6:# \\brief RTC manager default configuration
./OpenRTM_aist/CorbaNaming.py:7:# \\brief CORBA naming service helper class
./OpenRTM_aist/examples/TkJoyStick/TkJoyStickComp.py:78: \\brief Converting from canvas data to MobileRobotCanvas data
./OpenRTM_aist/examples/AutoTest/AutoTestIn.py:86: \\brief ModuleDescription
./OpenRTM_aist/examples/AutoTest/AutoTestIn.py:92: \\brief constructor
./OpenRTM_aist/examples/AutoTest/AutoTestIn.py:93: \\param manager Maneger Object
./OpenRTM_aist/examples/AutoTest/AutoTestOut.py:7: \\brief ModuleDescription
./OpenRTM_aist/examples/AutoTest/AutoTestOut.py:58: \\brief ModuleDescription
./OpenRTM_aist/DataFlowComponentBase.py:6:# \\brief DataFlowParticipant RT-Component base class
./OpenRTM_aist/ext/ssl/test/test_SSLTransport.py:6:# \\brief
./OpenRTM_aist/Process.py:7:# \\brief Process handling functions
./OpenRTM_aist/PortBase.py:2465: \\param id_(string)
./OpenRTM_aist/PortBase.py:2471: \\param cprof(RTC.ConnectorProfile)
./OpenRTM_aist/PortBase.py:2485: \\param port_ref(RTC.PortService)
./OpenRTM_aist/PortBase.py:2491: \\param port_ref(RTC.PortService)
./OpenRTM_aist/PortBase.py:2505: \\param p(RTC.PortService)
./OpenRTM_aist/PortBase.py:2506: \\param prof(RTC.ConnectorProfile)
./OpenRTM_aist/PortBase.py:2514: \\param p(RTC.PortService)
./OpenRTM_aist/PortBase.py:2531: \\param p(RTC.PortService)
./OpenRTM_aist/PortBase.py:2532: \\param prof(RTC.ConnectorProfile)
./OpenRTM_aist/PortBase.py:2540: \\param p(RTC.PortService)
./OpenRTM_aist/PortBase.py:2557: \\param p(OpenRTM_aist.PortBase)
./OpenRTM_aist/PortBase.py:2564: \\param p(RTC.ConnectorProfile)
./OpenRTM_aist/PortBase.py:2580: \\param name(string)
./OpenRTM_aist/PortBase.py:2581: \\param pol(RTC.PortInterfacePolarity)
./OpenRTM_aist/PortBase.py:2588: \\param prof(RTC.PortInterfaceProfile)
Commit changes? [y/N]
Changes are left unstaged. Review with 'git diff' if needed.