Запуск Python за несколько строк до моего script

Мне нужно запустить script foo.py, но мне нужно также вставить некоторые строки отладки для запуска до кода в foo.py. В настоящее время я просто помещаю эти строки в foo.py, и я стараюсь не делать это с Git, но мне не нравится это решение.

Что я хочу - это отдельный файл bar.py, который я не фиксирую для Git. Затем я хочу запустить:

python /somewhere/bar.py /somewhere_else/foo.py

Что я хочу, чтобы это сделать, сначала запустите некоторые строки кода в bar.py, а затем запустите foo.py как __main__. Он должен быть в том же процессе, в котором выполнялись строки bar.py, иначе строки отладки не помогут.

Есть ли способ сделать bar.py сделать это?

Кто-то предложил это:

import imp
import sys

# Debugging code here

fp, pathname, description = imp.find_module(sys.argv[1])
imp.load_module('__main__', fp, pathname, description)

Проблема в том, что, поскольку он использует механизмы импорта, мне нужно быть в той же папке, что и foo.py, чтобы запустить это. Я не хочу этого. Я хочу просто ввести полный путь к foo.py.

Также: Решение должно работать с файлами .pyc.

Ответ 1

Python имеет механизм запуска кода при запуске; site.

"This module is automatically imported during initialization."

Модуль сайта попытается импортировать модуль с именем sitecustomize до импорта __main__. Он также попытается импортировать модуль с именем usercustomize, если ваша среда проинструктирует его.

Например, вы можете поместить файл sitecustomize.py в папку своего сайта, содержащую это:

import imp

import os

if 'MY_STARTUP_FILE' in os.environ:
    try:
        file_path = os.environ['MY_STARTUP_FILE']
        folder, file_name = os.path.split(file_path)
        module_name, _ = os.path.splitext(file_name)
        fp, pathname, description = imp.find_module(module_name, [folder])
    except Exception as e:
        # Broad exception handling since sitecustomize exceptions are ignored
        print "There was a problem finding startup file", file_path
        print repr(e)
        exit()

    try:
        imp.load_module(module_name, fp, pathname, description)
    except Exception as e:
        print "There was a problem loading startup file: ", file_path
        print repr(e)
        exit()
    finally:
        # "the caller is responsible for closing the file argument" from imp docs
        if fp:
            fp.close()

Затем вы можете запустить script следующим образом:

MY_STARTUP_FILE=/somewhere/bar.py python /somewhere_else/foo.py
  • Вы можете запустить любой script перед foo.py без необходимости добавлять код в reimport __main__.
  • Запустите export MY_STARTUP_FILE=/somewhere/bar.py и не нужно ссылаться на него каждый раз

Ответ 2

Вы можете использовать execfile(), если файл .py и uncompyle2, если файл .pyc.

Скажем, у вас есть файловая структура вроде:

test|-- foo.py
    |-- bar
         |--bar.py   

foo.py

import sys

a = 1
print ('debugging...')

# run the other file
if sys.argv[1].endswith('.py'): # if .py run right away
    execfile(sys.argv[1], globals(), locals())
elif sys.argv[1].endswith('.pyc'): # if .pyc, first uncompyle, then run
    import uncompyle2
    from StringIO import StringIO
    f = StringIO()
    uncompyle2.uncompyle_file(sys.argv[1], f)
    f.seek(0)
    exec(f.read(), globals(), locals())

bar.py

print a
print 'real job'

И в test/, если вы это сделаете:

$ python foo.py bar/bar.py
$ python foo.py bar/bar.pyc

Оба, выводятся одинаково:

debugging...
1
real job

Также см. ответ .

Ответ 3

Вероятно, у вас есть что-то вроде:

if __name__ == '__main__':
    # some code

Вместо этого напишите свой код в функции main() в foo, а затем выполните:

if __name__ == '__main__':
    main()

Затем в баре вы можете импортировать foo и вызвать foo.main().

Дополнительно, если вам нужно изменить рабочий каталог, вы можете использовать метод os.chdir(path), например. os.chdir('path/of/bar').

Ответ 4

bar.py должен вести себя как сам интерпретатор Python и запускать foo.py (или foo.pyc, как вы просили об этом), как если бы это был основной script. Это удивительно сложно. Мое 90% -ное решение для этого выглядит так:

def run_script_as_main(cmdline):
    # It is crucial to import locally what we need as we
    # later remove everything from __main__
    import sys, imp, traceback, os
    # Patch sys.argv
    sys.argv = cmdline
    # Clear the __main__ namespace and set it up to run
    # the secondary program
    maindict = sys.modules["__main__"].__dict__
    builtins = maindict['__builtins__']
    maindict.clear()
    maindict['__file__'] = cmdline[0]
    maindict['__builtins__'] = builtins
    maindict['__name__'] = "__main__"
    maindict['__doc__'] = None
    # Python prepends a script location to sys.path
    sys.path[0] = os.path.dirname(os.path.abspath(cmdline[0]))
    # Treat everything as a Python source file, except it
    # ends in '.pyc'
    loader = imp.load_source
    if maindict["__file__"].endswith(".pyc"):
        loader = imp.load_compiled
    with open(cmdline[0], 'rb') as f:
        try:
            loader('__main__', maindict["__file__"], f)
        except Exception:
            # In case of an exception, remove this script from the
            # stack trace; if you don't care seeing some bar.py in
            # traceback, you can leave that out.
            ex_type, ex_value, ex_traceback = sys.exc_info()
            tb = traceback.extract_tb(ex_traceback, None)[1:]
            sys.stderr.write("Traceback (most recent call last):\n")
            for line in traceback.format_list(tb):
                sys.stderr.write(line)
            for line in traceback.format_exception_only(ex_type, ex_value):
                sys.stderr.write(line)

Это напоминает поведение по умолчанию интерпретатора Python относительно близко. Он устанавливает глобальные глобальные системы __name__, __file__, sys.argv, вставляет расположение script в sys.path, очищает глобальное пространство имен и т.д.

Скопируйте этот код в bar.py или импортируйте его где-нибудь и используйте его так:

if __name__ == "__main__":
    # You debugging setup goes here
    ...
    # Run the Python program given as argv[1]
    run_script_as_main(sys.argv[1:])

Затем, учитывая это:

$ find so-foo-bar
so-foo-bar
so-foo-bar/debugaid
so-foo-bar/debugaid/bar.py
so-foo-bar/foo.py

и foo.py выглядит следующим образом:

import sys

if __name__ == "__main__":
    print "My name is", __name__
    print "My file is", __file__
    print "My command line is", sys.argv
    print "First 2 path items", sys.path[:2]
    print "Globals", globals().keys()
    raise Exception("foo")

... running foo.py через bar.py дает вам следующее:

    $ python so-foo-bar/debugaid/bar.py so-foo-bar/foo.py
    My name is __main__
    My file is so-foo-bar/foo.py
    My command line is ['so-foo-bar/foo.py']
    First 2 path items ['~/so-foo-bar', '/usr/local/...']
    Globals ['__builtins__', '__name__', '__file__', 'sys', '__package__', '__doc__']
    Traceback (most recent call last):
      File "so-foo-bar/foo.py", line 9, in 
        raise Exception("foo")
    Exception: foo

Хотя я предполагаю, что run_script_as_main не хватает в некоторых интересных деталях, он довольно близок к тому, как Python будет запускать foo.py.

Ответ 5

foo.py не обязательно должна находиться в той же папке, что и в основной папке. Используйте

export PYTHONPATH=$HOME/dirWithFoo/:$PYTHONPATH

Чтобы добавить путь, который foo находится в пути Python. Теперь вы можете

from foo import myfunc

myfunc()

И сделайте myfunc делать все, что захочет

Ответ 6

Вы пробовали это?

bar.py

imp.load_source('__main__', '../../foo.py')

для меня он запускает все, что находится в foo.py(до и внутри main)

После, может быть, что вы делаете в bar.py, может быть более сложным, чем мой основной тест.

Хорошая вещь с load_source заключается в том, что она импортирует .pyc, если она уже существует, или инициирует "компиляцию".py, а затем импортирует .pyc.

Ответ 7

Это решение для меня хорошо работает:

#!/usr/bin/env python

import imp
import sys
import os.path

file_path = sys.argv.pop(1)
assert os.path.exists(file_path)

folder, file_name = os.path.split(file_path)

###############################################################################
#                                                                             #

# Debugging cruft here

#                                                                             #
###############################################################################


module_name, _ = os.path.splitext(file_name)
sys.path.append(folder)
imp.load_module('__main__', *imp.find_module(module_name))

Ответ 8

Предполагая, что вы используете Bash, как насчет:

python <(cat /somewhere/bar.py /somewhere_else/foo.py)