How to restart my Python script if I run it with “python -m”?

14
February 07, 2019, at 04:00 AM

I run my Python script with

python3.7 -m opencryptobot.START -lvl 20

opencryptobot is a folder here and START is a module. At some point I'd like to restart the script with this code:

os.execl(sys.executable, sys.executable, *sys.argv)

I use this code because it worked perfectly for my other scripts that I don't execute with the -m argument. So the above code will be executed at some point and then I get this error:

ModuleNotFoundError: No module named 'opencryptobot'

Which sounds correct since opencryptobot is just a folder and not a module. I played around with various versions of os.exec to see if I’m able to restart it but nothing really works.

So my question is, how can I restart my script if I run it the way I do?

This is a minimal version of my folder structure:

.
├── LICENSE
├── Pipfile
├── Pipfile.lock
├── README.md
├── opencryptobot
│   ├── START.py
│   ├── config.py
│   ├── constants.py
│   ├── database.py
│   ├── emoji.py
│   ├── plugin.py
│   ├── plugins
│   │   ├── about.py
│   │   ├── admin.py
│   │   └── alltimehigh.py
│   ├── ratelimit.py
│   ├── telegrambot.py
│   └── utils.py
└── start.sh

I execute START from the root folder.

Answer 1

sys.argv does not start with -m opencryptobot.START. The module name is removed from the sys.argv list altogether while resolving the opencryptobot.START module filename (sys.argv is set to ['-m', '-lvl', '20'] until there is a filename) and then '-m' is replaced with the full filename of the module.

From the -m switch documentation:

If this option is given, the first element of sys.argv will be the full path to the module file (while the module file is being located, the first element will be set to "-m").

In effect, Python is simulating running a script, as if you ran python /path/to/opencrytobot/START.py ...; only the __package__ context is kept so you can still use package-relative imports such as from . import ....

So to recreate your original command-line, use '-m', __spec__.name, *sys.argv[1:] as the argument list beyond sys.executable:

os.execl(sys.executable, sys.executable, '-m', __spec__.name, *sys.argv[1:])

You can't use __name__, unfortunately, as that has been set to '__main__' when using -m. However, the __spec__ object set on your module does know what the full qualified name is for the current module, so we can re-use that here.

Note that even though there is no __init__.py file in opencryptobot, by using -m you are telling Python that opencryptobot is really an implicit namespace package. If that wasn't the intention here, then don't use -m to load your script.

Demo:

$ ls -1 opencryptobot/
START.py
$ cat opencryptobot/START.py
import sys
import os
if __name__ == '__main__':
    print('Running as the __main__ script')
    print('sys.argv:', sys.argv)
    print('__spec__.name:', __spec__.name)
    if 'restarted' not in sys.argv:
        print('Respawning:')
        # add an extra command-line option to stop respawning a second time
        os.execl(sys.executable, sys.executable, '-m', __spec__.name, *sys.argv[1:], 'restarted')
$ python3.7 -m opencryptobot.START -lvl 20
Running as the __main__ script
sys.argv: ['/.../opencryptobot/START.py', '-lvl', '20']
__spec__.name: opencryptobot.START
Respawning:
Running as the __main__ script
sys.argv: ['/.../opencryptobot/START.py', '-lvl', '20', 'restarted']
__spec__.name: opencryptobot.START
READ ALSO
Android custom TextInputLayout style?

Android custom TextInputLayout style?

I'm new to android and java! And i don't know how to create custom TextInputLayoutI checked Material Design and found nice styles but this is not what i need

25
Activity return to a previous fragment

Activity return to a previous fragment

I have a MainActivity that calls a fragment called AccreditedNetworkFragment (code 1)This in turn instantiates a NetworkViewAdapter (code 2) that calls another AccreditedNetworkRegionFragment (code 3) fragment

8
How to access log error details when using 'android.debug.obsoleteApi=true' in gradle.properties file

How to access log error details when using 'android.debug.obsoleteApi=true' in gradle.properties file

I am new to contributing to open source projectsI am working on a project in Android Studio

38
Where exactly role based access control checks user's permissions in MVC pattern?

Where exactly role based access control checks user's permissions in MVC pattern?

I am implementing role-based access control in my simple PHP applicationI am not using any frameworks

44