Consejos y Trucos de los Desarrolladores

Consejos para preservar la productividad y la cordura

En esta sección recogemos algunos consejos y herramientas útiles que pueden aumentar tu calidad de vida a la hora de revisar pull requests, ejecutar pruebas unitarias, etc. Algunos de estos trucos consisten en userscripts que requieren una extensión del navegador como TamperMonkey o GreaseMonkey; para configurar los userscripts debes tener una de estas extensiones instalada, habilitada y funcionando. Proporcionamos los userscripts como gists de GitHub; para instalarlos, haz clic en el botón «Raw» de la página del gist.

Pliegue y despliegue de diffs obsoletos en pull requests

GitHub oculta las discusiones en los PR cuando las líneas de código correspondientes han sido cambiadas mientras tanto. Este userscript proporciona un atajo (Control-Alt-P en el momento de escribir esto, pero mira el código para estar seguro) para desplegar todas esas discusiones ocultas a la vez, para que puedas ponerte al día.

Comprobación de pull requests como ramas de seguimiento remoto

En tu fork local, añade a tu .git/config, bajo el encabezado [remote "upstream"], la línea:

fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*

A continuación, puedes utilizar git checkout pr/PR_NUMBER para navegar hasta el código del pull-request con el número dado. (Lee más en este gist.)

Mostrar la cobertura del código en los pull requests

Para superponer los informes de cobertura de código generados por la integración continua de CodeCov, considere esta extensión del navegador. La cobertura de cada línea se mostrará como un fondo de color detrás del número de línea.

Alias e indicadores útiles de pytest

El conjunto de pruebas completo tarda bastante en ejecutarse. Para iteraciones más rápidas, es posible seleccionar un subconjunto de pruebas utilizando selectores de pytest. En particular, se puede ejecutar una sola prueba basada en su ID de nodo:

pytest -v sklearn/linear_model/tests/test_logistic.py::test_sparsify

o utilizar el parámetro -k pytest para seleccionar las pruebas en función de su nombre. Por ejemplo:

pytest sklearn/tests/test_common.py -v -k LogisticRegression

ejecutará todos los tests comunes para el estimador LogisticRegression.

Cuando una prueba unitaria falla, los siguientes trucos pueden facilitar la depuración:

  1. El argumento de la línea de comandos pytest -l indica a pytest que imprima las variables locales cuando se produce un fallo.

  2. El argumento pytest --pdb pasa al depurador de Python en caso de fallo. En cambio, para entrar en el depurador enriquecido de IPython ipdb, puedes configurar un alias de shell para:

pytest --pdbcls=IPython.terminal.debugger:TerminalPdb --capture no

Otras opciones de pytest que pueden resultar útiles son:

  • -x que sale en la primera prueba fallida

  • --lf para volver a ejecutar las pruebas que fallaron en la ejecución anterior

  • --ff para volver a ejecutar todas las pruebas anteriores, ejecutando las que fallaron primero

  • -s para que pytest no capture la salida de las declaraciones print()

  • --tb=short o --tb=line para controlar la longitud de los registros

  • --runxfail también ejecuta las pruebas marcadas como fallo conocido (XFAIL) y reporta los errores.

Dado que nuestras pruebas de integración continua darán un error si FutureWarning no se captura correctamente, también se recomienda ejecutar pytest junto con el indicador -Werror::FutureWarning.

Respuestas estándar para la revisión

Puede ser útil almacenar algunas de ellas en las respuestas guardadas de GitHub para revisarlas:

Incidencia: Preguntas sobre el uso
You are asking a usage question. The issue tracker is for bugs and new features. For usage questions, it is recommended to try [Stack Overflow](https://stackoverflow.com/questions/tagged/scikit-learn) or [the Mailing List](https://mail.python.org/mailman/listinfo/scikit-learn).

Unfortunately, we need to close this issue as this issue tracker is a communication tool used for the development of scikit-learn. The additional activity created by usage questions crowds it too much and impedes this development. The conversation can continue here, however there is no guarantee that is will receive attention from core developers.
Incidencia: Puedes actualizar los documentos
Please feel free to offer a pull request updating the documentation if you feel it could be improved.
Incidencia: Ejemplo autocontenido para el error
Please provide [self-contained example code](https://stackoverflow.com/help/mcve), including imports and data (if possible), so that other contributors can just run it and reproduce your issue. Ideally your example code should be minimal.
Incidencia: Versiones de software
To help diagnose your issue, please paste the output of:
```py
import sklearn; sklearn.show_versions()
```
Thanks.
Incidencia: Bloques de código
Readability can be greatly improved if you [format](https://help.github.com/articles/creating-and-highlighting-code-blocks/) your code snippets and complete error messages appropriately. For example:

    ```python
    print(something)
    ```
generates:
```python
print(something)
```
And:

    ```pytb
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ImportError: No module named 'hello'
    ```
generates:
```pytb
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'hello'
```
You can edit your issue descriptions and comments at any time to improve readability. This helps maintainers a lot. Thanks!
Incidencias/comentarios: Vinculación con el código
Friendly advice: for clarity's sake, you can link to code like [this](https://help.github.com/articles/creating-a-permanent-link-to-a-code-snippet/).
Incidencias/Comentarios: Vinculación con los comentarios
Please use links to comments, which make it a lot easier to see what you are referring to, rather than just linking to the issue. See [this](https://stackoverflow.com/questions/25163598/how-do-i-reference-a-specific-issue-comment-on-github) for more details.
PR-NEW: Mejor descripción y título
Thanks for the pull request! Please make the title of the PR more descriptive. The title will become the commit message when this is merged. You should state what issue (or PR) it fixes/resolves in the description using the syntax described [here](http://scikit-learn.org/dev/developers/contributing.html#contributing-pull-requests).
PR-NUEVO: Corrección #
Please use "Fix #issueNumber" in your PR description (and you can do it more than once). This way the associated issue gets closed automatically when the PR is merged. For more details, look at [this](https://github.com/blog/1506-closing-issues-via-pull-requests).
PR-NUEVO o Incidencia: Coste de mantenimiento
Every feature we include has a [maintenance cost](http://scikit-learn.org/dev/faq.html#why-are-you-so-selective-on-what-algorithms-you-include-in-scikit-learn). Our maintainers are mostly volunteers. For a new feature to be included, we need evidence that it is often useful and, ideally, [well-established](http://scikit-learn.org/dev/faq.html#what-are-the-inclusion-criteria-for-new-algorithms) in the literature or in practice. That doesn't stop you implementing it for yourself and publishing it in a separate repository, or even [scikit-learn-contrib](https://scikit-learn-contrib.github.io).
PR-WIP: ¿Qué se necesita antes de la fusión (merge)?
Please clarify (perhaps as a TODO list in the PR description) what work you believe still needs to be done before it can be reviewed for merge. When it is ready, please prefix the PR title with `[MRG]`.
PR-WIP: Se necesita una prueba de regresión
Please add a [non-regression test](https://en.wikipedia.org/wiki/Non-regression_testing) that would fail at main but pass in this PR.
PR-WIP: PEP8
You have some [PEP8](https://www.python.org/dev/peps/pep-0008/) violations, whose details you can see in the Circle CI `lint` job. It might be worth configuring your code editor to check for such errors on the fly, so you can catch them before committing.
PR-MRG: Paciencia
Before merging, we generally require two core developers to agree that your pull request is desirable and ready. [Please be patient](http://scikit-learn.org/dev/faq.html#why-is-my-pull-request-not-getting-any-attention), as we mostly rely on volunteered time from busy core developers. (You are also welcome to help us out with [reviewing other PRs](http://scikit-learn.org/dev/developers/contributing.html#code-review-guidelines).)
PR-MRG: Añadir a las novedades
Please add an entry to the change log at `doc/whats_new/v*.rst`. Like the other entries there, please reference this pull request with `:pr:` and credit yourself (and other contributors if applicable) with `:user:`.
PR: No cambies lo que no está relacionado
Please do not change unrelated lines. It makes your contribution harder to review and may introduce merge conflicts to other pull requests.

Depuración de errores de memoria en Cython con valgrind

Aunque la gestión de la memoria incorporada en python/numpy es relativamente robusta, puede llevar a penalizaciones en el rendimiento de algunas rutinas. Por esta razón, gran parte del código de alto rendimiento en scikit-learn está escrito en cython. Sin embargo, esta ganancia de rendimiento viene con una compensación: es muy fácil que surjan errores de memoria en el código de cython, especialmente en situaciones en las que ese código depende en gran medida de la aritmética de punteros.

Los errores de memoria pueden manifestarse de varias maneras. Los más fáciles de depurar suelen ser los fallos de segmentación y los errores glibc relacionados. Las variables no inicializadas pueden conducir a un comportamiento inesperado que es difícil de rastrear. Una herramienta muy útil para depurar este tipo de errores es valgrind.

Valgrind es una herramienta de línea de comandos que puede rastrear errores de memoria en una variedad de código. Sigue estos pasos:

  1. Instala valgrind en tu sistema.

  2. Descarga el archivo de supresión de valgrind de python: valgrind-python.supp.

  3. Sigue las instrucciones del archivo README.valgrind para personalizar tus supresiones de python. Si no lo haces, tendrás salidas espurias relacionadas con el intérprete de python en lugar de tu propio código.

  4. Ejecuta valgrind de la siguiente manera:

valgrind -v --suppressions=valgrind-python.supp python my_test_script.py

El resultado será una lista de todos los errores relacionados con la memoria, que hacen referencia a líneas en el código C generado por cython desde su archivo .pyx. Si examinas las líneas referenciadas en el archivo .c, verás comentarios que indican la ubicación correspondiente en tu archivo fuente .pyx. Con suerte, la salida te dará pistas sobre el origen de tu error de memoria.

Para más información sobre valgrind y el arreglo de opciones que tiene, consulta los tutoriales y la documentación en el sitio web de valgrind.

Construcción y pruebas para la plataforma ARM64 en una máquina x86_64

Las máquinas basadas en ARM son un objetivo popular para las implementaciones móviles, de arista u otras de bajo consumo de energía (incluso en la nube, por ejemplo en Scaleway o AWS Graviton).

Aquí tienes las instrucciones para configurar un entorno de desarrollo local para reproducir errores específicos de ARM o fallos de prueba en una computadora portátil o estación de trabajo host x86_64. Esto se basa en la emulación del modo de usuario de QEMU que utiliza docker para mayor comodidad (consulta https://github.com/multiarch/qemu-user-static).

Nota

Las siguientes instrucciones se ilustran para ARM64 pero también se aplican a ppc64le, después de cambiar la imagen Docker y las rutas de Miniforge apropiadamente.

Prepara una carpeta en el sistema de archivos del host y descarga las herramientas y el código fuente necesarios:

mkdir arm64
pushd arm64
wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-aarch64.sh
git clone https://github.com/scikit-learn/scikit-learn.git

Utiliza docker para instalar el modo de usuario QEMU y ejecutar un contenedor ARM64v8 con acceso a tu carpeta compartida bajo el punto de montaje /io:

docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker run -v`pwd`:/io --rm -it arm64v8/ubuntu /bin/bash

En el contenedor, instala miniforge3 para la arquitectura ARM64 (también conocida como aarch64):

bash Miniforge3-Linux-aarch64.sh
# Choose to install miniforge3 under: `/io/miniforge3`

Cada vez que reinicies un nuevo contenedor, tendrás que reiniciar el env de conda previamente instalado en /io/miniforge3:

/io/miniforge3/bin/conda init
source /root/.bashrc

ya que la carpeta de inicio /root forma parte del contenedor docker efímero. Por otro lado, cada archivo o directorio almacenado en /io es persistente.

A continuación, puedes construir scikit-learn como de costumbre (tendrás que instalar las herramientas de compilación y las dependencias utilizando apt o conda como de costumbre). La construcción de scikit-learn lleva mucho tiempo debido a la capa de emulación, sin embargo, sólo es necesario hacerlo una vez si se pone la carpeta de scikit-learn bajo el punto de montaje /io.

Luego utiliza pytest para ejecutar sólo las pruebas del módulo que te interesa depurar.