Hello, I have a proposal to improve support of __main__.py (python -m foobar) invocation to argparse.ArgumentParser
You can find attached a PEP draft. Unfortunately, I'm not very confident on how to add that PEP and ... honnestly not very used to github. In short, can you help me and advise on this? Thanks a lot and best regards, Michaël Hooreman
PEP: 9999 Title: Add support of __main__.py to argparse.ArgumentParser.prog Version: $Revision$ Last-Modified: $Date$ Author: Michaël Hooreman <mich...@hooreman.be> Status: Draft Type: Standards track Content-Type: text/x-rst Created: 23-Aug-2019 Python-Version: 3.7 Post-History: None Introduction ============ The standard library's ``argparse.ArgumentParser`` uses by default ``sys.argv[0]`` for his ``prog`` property. It means that when using the ``python -m foobar`` invocation, which calls under the hood the ``foobar.__main__`` module, the ``prog`` will be ``__main__.py``, giving as usage: ``usage: __main__.py [-h] ...``. This PEP proposes an enhancement on the ``ArgumentParser`` to build more accurate usage information in this case. Implementation proposal ======================= This paragraph gives a proposal of patch. A better implementation would obviously impact the implementation of ``ArgumentParser.prog``. .. code-block:: python import argparse class ArgumentParser(argparse.ArgumentParser): def __init__(self, *args, **kwargs): argparse.ArgumentParser.__init__(self, *args, **kwargs) self._fixProg() def _fixProg(self): """Fixes the prog if this is __main__.py Identify the module used by comparing the file of __main__.py to the sys.path. Implementation details: ----------------------- The current directory, if found in the sys.path, is considered as a last ressort: if this is not the case, and if we run a package while being somewhere in his hierarchy, we will have a false result ... which won't work if our packages uses relative imports. Applies: -------- It only impact self.prog if the initial self.prog is __main__.py. In the other cases, it returs immediately. Returns: -------- Nothing Assertions: ----------- - The file name of __main__ is ... __main__.py - -m option is used - A POSIX operating system is used (see limitations in the PEP) Other exceptions: ----------------- - ValueError if the __main__ package cannot be identified """ def gen(): mainFile = pathlib.Path( sys.modules['__main__'].__file__ ).resolve() assert mainFile.name == self.prog, \ "Expecting {self.prog}, got {mainFile.name}" libdirs = sys.path pwdIsLib = os.getcwd() in libdirs libdirs = [d for d in sys.path if d != os.getcwd()] if pwdIsLib: libdirs.append(os.getcwd()) for libdir in libdirs: libdir = pathlib.Path(libdir).resolve() if str(mainFile).startswith(str(libdir)): remaining = mainFile.relative_to(libdir) remaining = remaining.parent # to drop the __init__.py while remaining.name: yield remaining.name remaining = remaining.parent return if self.prog != '__main__.py': return elts = list(gen())[::-1] if not elts: raise ValueError("Cannot identify qualified __main__ package") # This block is not portable assert os.name == 'posix', "/proc used: only for POSIX" with open(f'/proc/{os.getpid()}/cmdline') as fh: ll = fh.read().split('\0') executable = ll[0] mIx = [i for i, x in enumerate(ll) if x == '-m'] assert len(mIx) == 1, f"Cannot find position of -m in {ll}" mIx = mIx[0] pyOptns = ll[1:(mIx + 1)] self.prog = f"{executable} {' '.join(pyOptns)} {'.'.join(elts)}" Advantages ========== More accurate command line usage with ``argparse`` for ``python -m`` invocations. Limitations =========== We need to identify the way python was invoked in order to produce an usage similar to what has been used by the caller. We found no way to do that using standard library features, so that we are using the ``/proc`` file system. It means that the current proposal is limited to POSIX operating systems. Copyright ========= This document has been placed in the public domain. .. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 coding: utf-8 End:
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/VEGHR5GACYW7M6RVNEC323L2V43WJIKP/ Code of Conduct: http://python.org/psf/codeofconduct/