¿Cómo estructuro mi proyecto Python para permitir que los módulos con nombre se importen desde subdirectorios?

Esta es mi estructura de directorio:

Projects
    + Project_1
    + Project_2
    - Project_3
        - Lib1
            __init__.py # empty
            moduleA.py
        - Tests
            __init__.py # empty
            foo_tests.py
            bar_tests.py
            setpath.py
        __init__.py     # empty
        foo.py
        bar.py

Metas:

Tener una estructura de proyecto organizadaPoder ejecutar de forma independiente cada archivo .py cuando sea necesarioSer capaz de hacer referencia / importar tanto hermanos comoprima módulosMantenga todas las declaraciones import / from al comienzo de cada archivo.

Logré el # 1 usando la estructura anterior

Principalmente he logrado 2, 3 y 4 haciendo lo siguiente (según lo recomendado poresta excelente guía)

En cualquier paquete que necesite acceder a módulos primarios o primarios (como el directorio de Pruebas anterior) incluyo un archivo llamado setpath.py que tiene el siguiente código:

import os
import sys
sys.path.insert(0, os.path.abspath('..'))

sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('...'))

Luego, en cada módulo que necesita acceso de padre / primo, como foo_tests.py, puedo escribir una buena lista limpia de importaciones de esta manera:

import setpath      # Annoyingly, PyCharm warns me that this is an unused import statement
import foo.py

Dentro de setpath.py, las inserciones segunda y tercera no son estrictamente necesarias para este ejemplo, pero se incluyen como un paso de solución de problemas.

Mi problema es que esto solo funciona para importaciones que hacen referencia al nombre del módulo directamente, y no para importaciones que hacen referencia al paquete. Por ejemplo, dentro de bar_tests.py, ninguna de las dos declaraciones siguientes funciona cuando se ejecuta bar_tests.pydirectamente.

import setpath

import Project_3.foo.py  # Error
from Project_3 import foo  # Error

Recibo el error "ImportError: ningún módulo llamado 'Project_3'".

Lo extraño es que puedo ejecutar el archivo directamente desde PyCharm y funciona bien. Sé que PyCharm está haciendo algo de magia detrás de escena con elPython Path variable para que todo funcione, pero no puedo entender qué es. Como PyCharm simplemente ejecuta python.exe y establece algunas variables ambientales, debería ser posible clonar este comportamiento desde un script Python.

Por razones no realmente relacionadas con esta pregunta, tengo que hacer referenciabar utilizando laProject_3 Calificatorio.

Estoy abierto a cualquier solución que logre lo anterior mientras sigo cumpliendo mis objetivos anteriores. También estoy abierto a una estructura de directorio alternativa si hay una que funcione mejor. He leído elDocumento de Python sobre importaciones y paquetes pero todavía estoy perdido. Creo que una posible vía podría estar configurando manualmente el__path__ variable, pero no estoy seguro de cuál necesita ser cambiado o en qué configurarlo.

Respuestas a la pregunta(2)

Su respuesta a la pregunta