プロジェクト

全般

プロフィール

Python3.12環境で出るSyntaxWarning対応

  • Ubuntu24.04, Python3.12環境へ、OpenRTM-Python 2.0.2版をインストールし、サンプルRTCを実行した時に確認した
    $ python3 ConsoleIn.py 
    /usr/lib/python3/dist-packages/OpenRTM_aist/PortBase.py:2464: SyntaxWarning: invalid escape sequence '\p'
      """ 
    /usr/lib/python3/dist-packages/OpenRTM_aist/PortBase.py:2470: SyntaxWarning: invalid escape sequence '\p'
      """ 
    
  • 指摘されたPortBase.pyのコード部分
    2463         def __init__(self, id_):
    2464             """ 
    2465              \param id_(string)
    2466             """ 
    2467             self._id = id_
    
  • これは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.