Split parse args into filesystem tree for complex projects.
Project description
argparse_tree
Let the commandline arguments be distributed along the source directory, which can be collected into one with a single collection as a parent before initialising the command.
Installation
Using pip
pip install argparse_tree
Using pip
but with a cloned repository
git clone "https://github.com/bvraghav/argparse_tree"
cd argparse_tree
pip install .
Usage
A detailed usage can be found in the folder
example
. The crux of the matter is
illustrated below:
parser = ArgumentParser(
parents=collect_parsers(
'*_style1.py', 'style2/*.py',
parent_package = __package__
),
)
parser.add_argument(
'-v', '--verbose', action='store_true',
help="Verbosity switch."
)
add_commands(
parser, '*_command.py',
parent_package=__package__,
action=load_module_subparser_action(
'*_command.py', __package__
),
)
Inside of style2/generic.py
parser.add_argument(
'--style2', choices=collect_keys('style2/*.py'),
action=load_module_action('*.py', __package__)
)
Four functions namely,
collect_parsers
,
collect_keys
,
add_commands
, and
load_module_subparser_action
are utilized to achieve the desired behaviour, that is
- To have a set of argument groups collected from a set of files following a convenvention in names;
- To allow, non-homogeneity in such groups; and
- To extend this behaviour for sub-parsers.
Convention
A set of files, each containing a function
cli_args
that returns
parser information, are grouped together using a
certain convention in their file names, for example,
using a suffix say,*_data.py
may represent different
datasets. The arguments generic to all datasets may be
written to generic_data.py
. They are all collected
using the function collect_parsers
.
The convention may have simple been altered to follow a
prefixed format, say data/*.py
--- should work
equally well.
collect_parsers
collect_parsers(
*patterns,
root=None,
parent_package=None
)
Glob the ROOT
folder with PATTERNS
, one at a time,
and collect their parsers. If not specified, ROOT
is
computed, using the inspect
API, to be the folder
where the caller script resides.
PARENT_PACKAGE
is the name of package corresponding
to ROOT
folder. If not specified, PARENT_PACKAGE
is
not used.
collect_keys
collect_keys(
pattern,
root=None,
mod_to_key=utils.mod_to_key
)
Glob the ROOT
folder with PATTERN
and create a key
corresponding to each module. Key is computed using
MOD_TO_KEY
functional, which follows the same
signature as
utils.mod_to_key
.
add_commands
add_commands(
parser, pattern,
*,
root=None,
parent_package=None,
dest='command',
action=None,
mod_to_key=utils.mod_to_key
)
Create subcommands to cli using PARSER
, one
corresponding to each PATTERN
. Command name is
computed using MOD_TO_KEY
functional, which follows
the same signature as
utils.mod_to_key
.
The same convention as
collect_parsers
is followed for
PATTERN
, ROOT
, and PARENT_PACKAGE
.
DEST
and ACTION
are forwarded to
argparse.ArgumentParser.add_subparsers
.
load_module_subparser_action
load_module_subparser_action(
pattern,
package=None,
key_to_mod=utils.key_to_mod
)
Create an argparse.Action
to load a module
corresponding to a user-given key, based on PATTERN
,
and PACKAGE
using a decoder KEY_TO_MOD
functional,
which follows the same signature as
utils.key_to_mod
.
In case it is desirable to load a module corresponding
to value in user-specified argument, at the time of
parsing the args, use this as value of action
in
argparser.ArgumentParser.add_argument
.
Update
Version >= 0.1.3 : Code issues separate actions
corresponding to store
action and subparser
action,
as load_module_store_action
and
load_module_subparser_action
respectively. BREAKING: load_module_action
is an
alias for load_module_store_action
.
Motivation
The core idea behind this project is to exploit this argparse functionality:
local_parser = argparse.ArgumentParser()
local_parser.add_argument('--foo')
global_parser = argparse.ArgumentParser(
parents=[local_parser, ...]
)
The proof of concept can be seen in this code.
For example in machine learning training routines, there can be many models, many solvers, many datasets, each with different set of options. We can have something like:
## generic_dataset.py
def cli_parser() :
from argparse import ArgumentParser
parser = ArgumentParser(add_help=False)
group = parser.add_argument_group(
'Generic Dataset Options'
)
group.add_arguemnt('--foo')
return parser
And similarly add cli parsers for a_dataset.py
,
b_dataset.py
and so forth. Here, we have followed the
norm of suffxing dataset
to each python module. We
can collect them into the global parser as follows:
from argparse import
import argparse_tree as Atree
def cli_parser() :
parser = ArgumentParser(
parents=Atree.collect(['*_dataset.py'])
)
parser.add_argument(
'--verbose', help="Verbosity switch."
)
return parser
We can also have an option of collection from any pattern. For example,
data/*.py
for any module in folderdata
.- Any other pattern compatible with
pathllib.Path.glob
Scratchpad
Can an instance initializer know the caller file path
Here is an experiment which has an affirmative result.
## alpha.py ##
## ----------------------------------------------------
class A :
def __init__(self) :
from pathlib import Path
import inspect
f = inspect.stack().pop(1)
# print(f.filename)
self.p = Path(f.filename)
## beta.py ##
## ----------------------------------------------------
from alpha import A
print (A().p)
The idea is the use this behaviour and search the caller's parent path for the relevant module patterns.
This may be interesting; but it is always better to provide an unambiguous argument instead of inspect!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file argparse_tree-0.1.3.post6.tar.gz
.
File metadata
- Download URL: argparse_tree-0.1.3.post6.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/2.0.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/49.2.0.post20200714 requests-toolbelt/0.9.1 tqdm/4.47.0 CPython/3.8.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e4c3181548e7bc8850890e2e7bd9edc0ceeb80472bfc9f32d1d09e5b59d0aff8 |
|
MD5 | e06c550626cee576ff0a385b5da7a5b0 |
|
BLAKE2b-256 | e7794df8442aa01c2a068b1a10b4685b96c4854acda44b81aa6df4cb8df053b3 |
File details
Details for the file argparse_tree-0.1.3.post6-py3-none-any.whl
.
File metadata
- Download URL: argparse_tree-0.1.3.post6-py3-none-any.whl
- Upload date:
- Size: 9.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/2.0.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/49.2.0.post20200714 requests-toolbelt/0.9.1 tqdm/4.47.0 CPython/3.8.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a8a498faeb6d9fa5fa30f9535c4cf0e85d3e00e22af87a265995b98f1d416044 |
|
MD5 | 5a66f20895c6fa8ee79b0ee352693a97 |
|
BLAKE2b-256 | 88748d8fd4539aaa0dc25440d69ce71540c66ef9b5f4b6fa079bd748a52e52d3 |