Biblioteca para inserir automaticamente docstring python no estilo do Google

8

Estou procurando um pacote elisp que insira automaticamente a documentação do Python para um método. Encontrei um pacote muito próximo do meu objetivo. Mas é em texto reestruturado, não no estilo do Google.

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

Descrevendo argumentos em docstrings (guia de estilo do python do Google) https://www.chromium.org/chromium-os/python-style-guidelines#TOC-Describing-arguments-in-docstrings

Minha expectativa é quando ligo M-x sphinx-doc-googledentro da seguinte função,

def some_function(a, b, c):

Eu preciso de um resultado como este.

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

Eu sei que não é difícil de implementar sozinho. Eu só quero fazer esta pergunta para evitar a reinvenção.

sy2
fonte
Eu não acho que exista. Esse estilo não é exatamente popular na comunidade maior de Python, até onde eu sei.
lunaryorn
Obrigado. Eu pensei que era popular porque a configuração padrão da regra de inserção automática de documentos do PyCharm é o estilo do Google. Eu tinha usado o texto reestruturado por um tempo, mas não é muito legível por humanos. :(
sy2 11/01

Respostas:

8

Eu uso o pacote chamado yasnippet para algo semelhante a isso. Após algumas pequenas alterações, eu o adaptei para usar o estilo de documentação do Google:

Yasnippet Python com estilo do Google

Observe, no entanto, que isso requer alguma configuração:

O trecho em si precisa executar algum código elisp do utilitário para gerar o texto. Isso geralmente é resolvido com a criação de um arquivo chamado .yas-setup.elcom o código dentro do python-modediretório do snippet. No entanto, também é possível colocar o código em algum lugar dentro do seu .emacs.

O código para o snippet é:

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

O código para .yas-setup.elé:

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

Observe que python-split-argsé fornecido pelos trechos padrão . Ou seja: https://github.com/AndreaCrotti/yasnippet-snippets/tree/master No entanto, você os obtém por padrão ao instalar o pacote package.el.

Com tudo configurado corretamente, você poderá escrever "defg" seguido de Tabpara expandir o trecho (veja a imagem para obter um exemplo).

Ainda existe um problema ao usar esse recuo aninhado interno, por exemplo, dentro de classes ou como funções aninhadas. Nesses casos, a doutrina é recuada erroneamente por um tempo extra por algum motivo. Vou atualizar este post se conseguir consertar isso.

Agora, o trecho de código deve funcionar em outros escopos, proibindo yasnippeto recuo automático da segunda expansão.

Xaldew
fonte
Pergunta estúpida, mas como eu realmente faço isso funcionar em uma função existente? Eu digito defge isso me dá uma nova função nomeada namesem argumentos, e não vejo nenhuma maneira de automatizá-la atualizando a doutrina à medida que altero essa função. Quando olho para o meu buffer de Mensagens, vejo yas--update-mirrors: Wrong type argument: stringp, (python-args-to-google-docstring).
Autumnsault
1
Na verdade, eu encontrei isso hoje também em outro dos meus trechos, acho que pode ser um bug yasnippet. Vou ter que criar um exemplo mínimo para relatá-lo adequadamente. Também pode ser que snippets de encadeamento dessa maneira não sejam mais suportados, mas espero que não seja isso.
Xaldew
Isso ainda é um problema? Não consigo mais replicar o erro acima usando o Emacs / yasnippet mais recente.
Xaldew
Sim, ainda é problemático. Estou usando o emacs 24.5.1 (a versão mais recente do Ubuntu) e a versão mais recente do yasnippet.
Autumnsault 17/11
1
@AstroFloyd Isso está correto, o código para .yas-setup.eldeve terminar no mesmo diretório que o diretório do snippet para o modo ativo no momento. Qual é o ~/.emacs.d/snippets/python-mode/.yas-setup.elmodo python, como você apontou.
Xaldew 08/10/19
3

Como o lunaryorn mencionou, o estilo não é popular e não há pacotes.

No entanto, existe um pacote chamado sphinx-doc que irá gerar uma sequência de documentos no formato sphinx ( demo ).

Você pode modificar esse pacote para gerar seqüências de caracteres conforme sua exigência.

ChillarAnand
fonte
-1

Você pode usar esse código.

Mova o cursor no nome da sua função e, em seguida, 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
fonte