Bibliothek zum automatischen Einfügen von Python-Dokumentstrings im Google-Stil

8

Ich suche ein elisp-Paket, das automatisch Python docstring für eine Methode einfügt. Ich habe ein Paket gefunden, das meinem Zweck sehr nahe kommt. Aber es ist in restrukturiertem Text, nicht im Google-Stil.

sphinx-doc.el https://github.com/naiquevin/sphinx-doc.el

Beschreiben von Argumenten in Docstrings (Google Python Style Guide) https://www.chromium.org/chromium-os/python-style-guidelines#TOC-Describing-arguments-in-docstrings

Meine Erwartung ist, wenn ich M-x sphinx-doc-googleinnerhalb der folgenden Funktion aufrufe:

def some_function(a, b, c):

Ich brauche so ein Ergebnis.

def some_function(a, b, c):
    """
    Args:
        a:
        b:
        c:
    Returns:
    """

Ich weiß, dass es nicht schwierig ist, mich selbst umzusetzen. Ich möchte diese Frage nur stellen, um die Neuerfindung zu vermeiden.

sy2
quelle
Ich glaube nicht. Soweit ich weiß, ist dieser Stil in der größeren Python-Community nicht gerade beliebt.
Mondhorn
Vielen Dank. Ich fand es beliebt, weil die Standardeinstellung der automatischen Einfügungsregel für Dokumentzeichenfolgen von PyCharm der Google-Stil ist. Ich hatte eine Weile restrukturierten Text verwendet, aber er ist nicht sehr gut lesbar. :(
Sy2

Antworten:

8

Ich benutze das Paket namens yasnippet für etwas Ähnliches. Nach einigen geringfügigen Änderungen habe ich es angepasst, um stattdessen den Google Docstring-Stil zu verwenden:

Python-Yasnippet im Google-Stil

Beachten Sie jedoch, dass einige Einstellungen erforderlich sind:

Das Snippet selbst muss einen Dienstprogramm-Elisp-Code ausführen, um den Text zu generieren. Dies wird normalerweise gelöst, indem eine Datei .yas-setup.elmit dem Code im python-modeSnippet-Verzeichnis erstellt wird. Es ist jedoch auch möglich, den Code .emacsstattdessen irgendwo in Ihrem zu platzieren.

Der Code für das Snippet lautet:

# -*- mode: snippet -*-
# Insert Google style docstring and function definition.
# name: Python Google style Docstring
# key: defg
# type: snippet
# contributor: Xaldew
# --
def ${1:name}($2):
    \"\"\"$3
    ${2:$(python-args-to-google-docstring yas-text t)}
    ${5:Returns:
        $6
}
    \"\"\"
    ${0:$$(let ((beg yas-snippet-beg)
                (end yas-snippet-end))
        (yas-expand-snippet
          (buffer-substring-no-properties beg end) beg end
              (quote ((yas-indent-line nil) (yas-wrap-around-region nil))))
            (delete-trailing-whitespace beg (- end 1)))}

Der Code für .yas-setup.ellautet:

(defun python-args-to-google-docstring (text &optional make-fields)
  "Return a reST docstring format for the python arguments in yas-text."
  (let* ((indent (concat "\n" (make-string (current-column) 32)))
         (args (python-split-args text))
     (nr 0)
         (formatted-args
      (mapconcat
       (lambda (x)
         (concat "   " (nth 0 x)
             (if make-fields (format " ${%d:arg%d}" (cl-incf nr) nr))
             (if (nth 1 x) (concat " \(default " (nth 1 x) "\)"))))
       args
       indent)))
    (unless (string= formatted-args "")
      (concat
       (mapconcat 'identity
          (list "" "Args:" formatted-args)
          indent)
       "\n"))))

Beachten Sie, dass python-split-argsdies durch die Standard- Snippets bereitgestellt wird . Dh: https://github.com/AndreaCrotti/yasnippet-snippets/tree/master Diese erhalten Sie jedoch standardmäßig, wenn Sie das Paket über installieren package.el.

Wenn alles richtig eingerichtet ist, sollten Sie in der Lage sein, "defg" zu schreiben und anschließend Tabdas Snippet zu erweitern (ein Beispiel finden Sie im Bild).

Es gibt immer noch ein Problem bei der Verwendung dieser in verschachtelten Einrückungen, z. B. innerhalb von Klassen oder als verschachtelte Funktionen. In diesen Fällen wird die Dokumentzeichenfolge aus irgendeinem Grund fälschlicherweise um eine zusätzliche Zeit eingerückt. Ich werde diesen Beitrag aktualisieren, wenn ich das behebe.

Das Snippet sollte jetzt in anderen Bereichen funktionieren, indem verhindert wird, dass yasnippetdie zweite Erweiterung automatisch eingerückt wird.

Xaldew
quelle
Dumme Frage, aber wie mache ich das eigentlich für eine vorhandene Funktion? Ich tippe defgund es gibt mir eine neue Funktion nameohne Argumente, und ich sehe keine Möglichkeit, die Aktualisierung der Dokumentzeichenfolge zu automatisieren, wenn ich diese Funktion ändere. Wenn ich mir meinen Nachrichtenpuffer ansehe, sehe ich yas--update-mirrors: Wrong type argument: stringp, (python-args-to-google-docstring).
Autumnsault
1
Ich bin dem heute auch in einem anderen meiner Schnipsel begegnet, ich denke, es könnte ein Fehler sein yasnippet. Ich muss ein minimales Beispiel erstellen, um es richtig zu melden. Es kann auch sein, dass das Verketten von Snippets auf diese Weise nicht mehr unterstützt wird, aber ich hoffe, das ist es nicht.
Xaldew
Ist das noch ein Problem? Ich kann den obigen Fehler nicht mehr mit dem neuesten Emacs / Yasnippet replizieren.
Xaldew
Ja, es ist immer noch problematisch. Ich verwende Emacs 24.5.1 (die neueste Ubuntu-Version) und die neueste Version von Yasnippet.
Autumnsault
1
@AstroFloyd Das ist richtig, der Code für .yas-setup.elsollte im selben Verzeichnis wie das Snippet-Verzeichnis für den derzeit aktiven Modus landen. Welches ist ~/.emacs.d/snippets/python-mode/.yas-setup.elfür den Python-Modus, wie Sie betont haben.
Xaldew
3

Wie Lunaryorn erwähnte, ist Stil nicht beliebt und es gibt keine Pakete.

Es gibt jedoch ein Paket namens sphinx-doc, das eine Dokumentzeichenfolge im Sphinx-Format ( Demo ) generiert .

Sie können dieses Paket ändern, um Zeichenfolgen gemäß Ihren Anforderungen zu generieren.

ChillarAnand
quelle
-1

Sie können diesen Code verwenden.

Bewegen Sie den Cursor auf Ihren Funktionsnamen und dann auf F9.

 (defun chomp (str)
        "Chomp leading and tailing whitespace from STR."
        (let ((s (if (symbolp str) (symbol-name str) str)))
          (replace-regexp-in-string
           "\\(^[[:space:]\n]*\\|[[:space:]\n]*$\\)" "" s)))
 (defun get-function-definition(sentence)
    (if (string-match "def.*(.*):" sentence)
        (match-string 0 sentence)))
 (defun get-parameters(sentence)
    (setq y (get-function-definition sentence))
    (if y
        (if (string-match "(.*)" y)
            (match-string 0 y))))
 (autoload 'thing-at-point "thingatpt" nil t) ;; build-in librairie
 (defun python-insert-docstring()
        (interactive)
        (setq p (get-parameters (thing-at-point 'sentence)))
        (forward-line 1)
        (insert "    \"\"\"\n")
        (insert "\tArgs:\n")
        (setq params (split-string p "[?\,?\(?\)?\ ]"))
        (while params
          (if (/= (length (chomp (car params))) 0)
              (progn
                (insert "        ")
                (insert (chomp (car params)))
                (insert ": \n")))
          (setq params (cdr params)))
        (insert "    Returns:\n    \"\"\"\n"))
      (global-set-key (kbd "<f9>") 'python-insert-docstring)
djangoliv
quelle