Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

loader.py: Wrong directory inserted into sys.path for modules

Abierto
#969 1 comentario 3 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
45/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Estancado
Stack tecnológico
python
Área
cli

Línea de trabajo

Read invoke/loader.py, especially load and the path insertion around the referenced line, and compare module and package resolution. Update the inserted path so package-based tasks can import sibling modules such as barutils, then add tests covering both tasks.py and tasks/init.py cases.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Background

In loader.py, invoke uses this load function to load the tasks collection. This function attempts to detect whether tasks is a module or a package:

https://github.com/pyinvoke/invoke/blob/07b836f2663bb073a7bcef3d6c454e1dc6b867ae/invoke/loader.py#L49-L96

It first sets enclosing_dir to be the parent directory of whatever file the import resolved to (this is tasks.py for modules, and __init__.py within the package directory for packages). Then, it checks if the discovered ModuleSpec has a non-empty entry for .parent, which would indicate that the imported tasks is a package. If it is a package, it sets module_parent to be one level above enclosing_dir. If it is not a package, module_parent is set to be enclosing_dir.

Bug

This is all correct, however the path that gets inserted into the path is always enclosing_dir, not module_parent. If we have:

foo
| -- pyinvoke
     | -- tasks.py

and then resolve the ModuleSpec for tasks, we correctly insert /foo/pyinvoke into the path. However, if we have:

foo
| -- pyinvoke
     | -- tasks
          | -- __init__.py

we end up inserting /foo/pyinvoke/tasks into the path, which is wrong, the path inserted should still be /foo/pyinvoke.

Note: #944 is similar but predates the refactor to load that happened in 2.1.3. In https://github.com/pyinvoke/invoke/commit/aa8b815d7a7a43c8ac814c6deb9c4555b8ac6b9e logic was added to fix the search path for config files, but that did not extend to search path for packages.

Note 2: This is all fine and dandy for most use cases where everything lives in tasks or tasks.py. This only broke because we have the following structure:

foo
| -- pyinvoke
    | -- tasks
        | -- __init__.py
        | -- foo_task.py
    | -- barutils
        | -- __init__.py
        | -- bar.py

From within foo_task.py we have from barutils.bar import bartender, which won't work when the inserted path is /foo/pyinvoke/tasks/ since barutils isn't in tasks.

Solution?

I'd like to propose that in:

https://github.com/pyinvoke/invoke/blob/07b836f2663bb073a7bcef3d6c454e1dc6b867ae/invoke/loader.py#L85

we replace enclosing_dir with module_parent.

@bitprophet if this fix seems reasonable I can put in a PR and add some tests for this.

Lenguaje dominante
Python
Estrellas
4.8k
Forks
412
Métricas de merge de PR
Sin PR fusionados en 30 d

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de pyinvoke/invoke

Todos los issues de pyinvoke/invoke

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.