Ejecutar el progtwig python desde otro progtwig python (con ciertos requisitos)

Digamos que tengo dos scripts de python A.py y B.py Estoy buscando una forma de ejecutar B desde dentro de A de tal manera que:

  1. B cree que es __main__ (para que se __main__ código en un if __name__=="__main__" en B)
  2. B no es en realidad __main__ (por lo que no lo hace, por ejemplo, sobrescribe la entrada "__main__" en sys.modules)
  3. Las excepciones generadas dentro de B se propagan a A (es decir, se pueden capturar con una cláusula de except en A).
  4. Esas excepciones, si no se detectan, generan un número de línea de referencia de rastreo correcto dentro de B.

He probado varias técnicas, pero ninguna parece satisfacer todos mis requisitos.

  • el uso de herramientas del módulo de subproceso significa que las excepciones en B no se propagan a A.
  • execfile("B.py", {}) ejecuta B, pero no cree que sea principal.
  • execfile("B.py", {'__name__': '__main__'}) hace que B.py piense que es principal, pero también parece arruinar la excepción de la impresión de rastreo, de modo que las trazas de retorno se refieran a líneas dentro de A (es decir, el verdadero __main__ ).
  • el uso de imp.load_source con __main__ como nombre casi funciona, excepto que en realidad modifica sys.modules, por lo que pisa el valor existente de __main__

¿Hay alguna manera de conseguir lo que quiero?

(La razón por la que hago esto es porque estoy limpiando algo en una biblioteca existente. Esta biblioteca no tiene un conjunto de pruebas real, solo un conjunto de scripts “de ejemplo” que producen cierta salida. Estoy tratando de aprovechar estos como pruebas para garantizar que mi limpieza no afecte la capacidad de la biblioteca para ejecutar estos ejemplos, por lo que deseo ejecutar cada secuencia de comandos de ejemplo desde mi conjunto de pruebas. Me gustaría poder ver las excepciones de estas secuencias de comandos dentro de la secuencia de comandos de prueba. la secuencia de comandos de prueba puede informar el tipo de falla, en lugar de solo informar una SubprocessError genérica cada vez que una secuencia de comandos de ejemplo genere alguna excepción.)

Su caso de uso tiene sentido, pero sigo pensando que sería mejor que refactorizara las pruebas para que se puedan realizar externamente.

¿Pruebas guiones tienen algo como esto?

 def test(): pass if __name__ == '__main__': test() 

Si no es así, tal vez debería convertir sus pruebas a llamar a una función como test . Luego, desde tu script de prueba principal, puedes simplemente:

 import test1 test1.test() import test2 test2.test() 

Proporcionar una interfaz común para ejecutar pruebas, que las pruebas utilizan. Tener un gran bloque de código en una verificación __main__ no es una buena cosa.

Lamento no haber respondido a la pregunta que hizo, pero creo que esta es la solución correcta sin alejarme demasiado del código de prueba original.

Responder a mi propia pregunta porque el resultado es bastante interesante y podría ser útil para otros:

Resulta que estaba equivocado: execfile("B.py", {'__name__': '__main__'} es el camino a seguir después de todo. Produce correctamente las trazas de respuesta. Lo que estaba viendo con números de línea incorrectos no estaba excepciones pero advertencias . Estas advertencias se produjeron usando warnings.warn("blah", stacklevel=2) . Se stacklevel=2 argumento stacklevel=2 permite que se generen advertencias de desaprobación en lugares donde se utiliza el objeto desaprobado, en lugar de Llamada de advertencia (ver la documentación ).

Sin embargo, parece que el archivo execfile-d no cuenta como un “nivel de stack” para este propósito, y es invisible para propósitos de nivel de stack. Entonces, si el código en el nivel superior de un módulo execfile-d provoca una advertencia con el nivel de stack 2, la advertencia no se muestra en el número de línea correcto en el archivo fuente execfile-d; en su lugar, aparece en el número de línea correspondiente del archivo que ejecuta el execfile.

Esto es desafortunado, pero puedo vivir con él, ya que solo son advertencias, por lo que no afectarán el rendimiento real de las pruebas. (Al principio no me di cuenta de que eran solo las advertencias las que se vieron afectadas por los desajustes en el número de línea, porque había muchas advertencias y excepciones entremezcladas en la salida de la prueba).