Biblioteca para insertar automáticamente la cadena de documentos de Python en el estilo de Google

9

Estoy buscando un paquete elisp que inserte automáticamente la cadena de documentación de Python para un método. Encontré un paquete, que está muy cerca de mi propósito. Pero está en texto reestructurado, no en el estilo de Google.

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

Describiendo argumentos en docstrings (guía de estilo de Google Python) https://www.chromium.org/chromium-os/python-style-guidelines#TOC-Describing-arguments-in-docstrings

Mi expectativa es cuando llamo M-x sphinx-doc-googledentro de la siguiente función,

def some_function(a, b, c):

Necesito un resultado como este.

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

Sé que no es difícil de implementar por mí mismo. Solo quiero hacer esta pregunta para evitar la reinvención.

sy2
fuente
No creo que la haya. Hasta donde yo sé, este estilo no es exactamente popular en la comunidad más grande de Python.
lunaryorn
Gracias. Pensé que es popular porque la configuración predeterminada de la regla de inserción automática de cadenas de documentos de PyCharm es el estilo de Google. Había usado texto reestructurado por un tiempo, pero no es muy legible para los humanos. :(
sy2

Respuestas:

9

Yo uso el paquete llamado yasnippet para algo similar a esto. Después de algunos cambios menores, lo adapté para usar el estilo de Google Docstring:

Google diseñó Python yasnippet

Sin embargo, tenga en cuenta que requiere cierta configuración:

El fragmento en sí necesita ejecutar algún código de utilidad elisp para generar el texto. Esto generalmente se resuelve creando un archivo llamado .yas-setup.elcon el código dentro del python-modedirectorio de fragmentos. Sin embargo, también es posible colocar el código en algún lugar dentro de su .emacslugar.

El código para el fragmento es:

# -*- 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)))}

El código para el .yas-setup.eles:

(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"))))

Tenga en cuenta que python-split-argslo proporcionan los fragmentos estándar . Es decir: https://github.com/AndreaCrotti/yasnippet-snippets/tree/master Sin embargo, los obtiene de forma predeterminada cuando instala el paquete package.el.

Con todo configurado correctamente, debería poder escribir "defg" seguido de Tabexpandir el fragmento (vea la imagen para ver un ejemplo).

Todavía hay un problema con el uso de esta sangría anidada, por ejemplo, dentro de clases o como funciones anidadas. En esos casos, la cadena de documentos se sangra erróneamente un tiempo extra por alguna razón. Actualizaré esta publicación si logro arreglar eso.

El fragmento ahora debería funcionar dentro de otros ámbitos al prohibir yasnippetla sangría automática de la segunda expansión.

Xaldew
fuente
1
Pregunta estúpida, pero ¿cómo hago para que esto funcione en una función existente? Escribo defgy me da una nueva función nombrada namesin argumentos, y no veo ninguna forma de automatizarlo actualizando la cadena de documentación a medida que cambio esa función. Cuando miro mi búfer de mensajes, veo yas--update-mirrors: Wrong type argument: stringp, (python-args-to-google-docstring).
Autumnsault
1
De hecho, también encontré esto hoy en otro de mis fragmentos, creo que puede ser un error yasnippet. Sin embargo, tendré que crear un ejemplo mínimo para informarlo correctamente. También puede ser que el encadenamiento de fragmentos de esta manera ya no sea compatible, pero espero que no sea así.
Xaldew
¿Sigue siendo un problema? Ya no puedo replicar el error anterior usando el último Emacs / yasnippet.
Xaldew
Sí, sigue siendo problemático. Estoy usando emacs 24.5.1 (la última versión de Ubuntu) y la última versión de yasnippet.
Autumnsault
1
@AstroFloyd Eso es correcto, el código para .yas-setup.eldebe terminar en el mismo directorio que el directorio de fragmentos para el modo actualmente activo. Lo cual es ~/.emacs.d/snippets/python-mode/.yas-setup.elpara el modo python como usted señaló.
Xaldew
3

Como lunaryorn mencionó que el estilo no es popular y no hay paquetes.

Sin embargo, hay un paquete llamado sphinx-doc que generará una cadena de documentos en formato sphinx ( demo ).

Puede modificar ese paquete para generar cadenas según sus requisitos.

ChillarAnand
fuente
-1

Puedes usar este código.

Mueva el cursor sobre el nombre de su función y luego 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
fuente