Skip to content

Commit

Permalink
Autocomplete enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
anguelos committed Mar 7, 2020
1 parent 56a73fc commit 625c65a
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 25 deletions.
File renamed without changes.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,16 @@ my_program -anInt 34 -aFloat=2.3 -aBoolean -anotherBoolean=False
* Automatic help generation
* Params usable as dictionary or struct
* Can read environmental variables as well
* macro-parameters
* macro-parameters
* fast autocomplete generation

### Autocomplete

Static autocomplete for any program using fargv can be enabled with a single command.

The following command enables autocomplete for fargv_demo.py in the current shell where it is run.
```bash
source <(./examples/fargv_demo.py -bash_autocomplete)
```
fargv_demo.py should be an executable file employing the shebang (#!/usr/bin/env python3) or something equivalent.
For a temporary solution, the autocomplete bash code can go in a script in /etc/bash_completion.d or in .bashrc.
Empty file modified examples/fargv_demo.py
100644 → 100755
Empty file.
Empty file modified examples/fargv_demo_noequal.py
100644 → 100755
Empty file.
69 changes: 53 additions & 16 deletions fargv/argv_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,48 @@
from collections import namedtuple


def fargv(default_switches, argv=None, use_enviromental_variables=True, return_named_tuple=False,
def generate_bash_autocomplete(default_switches, full_filename=None):
"""Creates bash code for autocomplete
:param default_switches:
:param full_filename: The filename of the current program. If None, sys.argv[0] is used.
:return: A string with bash commands that enable autocomplete
"""
commands = " ".join([f"-{k}" for k in default_switches.keys()])
fname = full_filename.split("/")[-1]
name = fname.split(".")[0]
autocomplete_script = f"""# Static autocomplete generator.
#
# Enable in current shell:
# source <({full_filename} -bash_autocomplete)
#
# Or add the following code in a file in /etc/bash_completion.d
_myscript_tab_complete_{name} () {{
local cur prev opts
COMPREPLY=()
cur="${{COMP_WORDS[COMP_CWORD]}}"
prev="${{COMP_WORDS[COMP_CWORD-1]}}"
words="{commands}"
COMPREPLY=( $(compgen -W "${{words}}" -- ${{cur}}) )
return 0
}}
complete -F _myscript_tab_complete_{name} {fname}
"""
return autocomplete_script


def fargv(default_switches, argv=None, use_enviromental_variables=True, return_named_tuple=True,
spaces_are_equals=True):
"""Parse the argument list and create a dictionary with all parameters.
Argument types:
Strings
Integers
Floating Point
Booleans
Choices: defined as tuples.
Strings: The most generic parameter type. If you need more specific data types, you run eval on a string type.
Integers: Anything that can be used to construct an int from a string.
Floating Point: Anything that can be used to construct a float from a string.
Booleans: If set with out a parameter, it is switched to True. Other wise a case incensitive value of true or
false
Choices: Defined as tuples in the parameter dictionary.
:param default_switches: A dictionary with parameters as keys and default values as elements. If the value is a
collection of two elements who's second element is a string.
Expand All @@ -36,13 +68,14 @@ def fargv(default_switches, argv=None, use_enviromental_variables=True, return_n
if use_enviromental_variables:
for k, default_v in list(default_switches.items()):
if k in list(os.environ.keys()):
if hasattr(default_v, '__len__') and len(v) == 2 and isinstance(v[1], str):
if hasattr(default_v, '__len__') and len(default_v) == 2 and isinstance(default_v[1], str):
default_switches[k] = (type(default_v[0])(os.environ[k]), default_v[1])
else:
default_switches[k] = type(default_v)(os.environ[k])

new_default_switches = {}
switches_help = {"help": "Print help and exit."}
switches_help = {"help": "Print help and exit.",
"bash_autocomplete": "Print a set of bash commands that enable autocomplete for current program."}

for k, v in list(default_switches.items()):
if (not isinstance(v, str)) and hasattr(v, '__len__') and len(v) == 2 and isinstance(v[1], str):
Expand All @@ -54,7 +87,7 @@ def fargv(default_switches, argv=None, use_enviromental_variables=True, return_n
default_switches = new_default_switches
del new_default_switches

default_switches = dict(default_switches, **{"help": False})
default_switches = dict(default_switches, **{"help": False, "bash_autocomplete": False})

if argv is None:
argv = sys.argv
Expand Down Expand Up @@ -85,7 +118,7 @@ def fargv(default_switches, argv=None, use_enviromental_variables=True, return_n
if type(val) is tuple:
argv_switches[key] = default_switches[key][0]

argv_switches.update([[arg[1:arg.find("=")], arg[arg.find("=") + 1:]] for arg in argv if arg[0] == "-"])
argv_switches.update({arg[1:arg.find("=")]: arg[arg.find("=") + 1:] for arg in argv if arg[0] == "-"})

if spaces_are_equals:
positionals = [arg for arg in argv if len(arg) and arg[0] != "-"]
Expand All @@ -96,16 +129,15 @@ def fargv(default_switches, argv=None, use_enviromental_variables=True, return_n
if set(argv_switches.keys()) > set(default_switches.keys()):
help_str = "\n" + argv[0] + " Syntax:\n\n"
for k in list(default_switches.keys()):
help_str += "\t-%s=%s %s Default %s.\n" % (
k, repr(type(default_switches[k])), switches_help[k], repr(default_switches[k]))
help_str += "\n\nUrecognized switches: " + repr(tuple(set(default_switches.keys()) - set(argv_switches.keys())))
help_str += f"\t-{k} = {type(default_switches[k])} {switches_help[k]} Default {repr(default_switches[k])}.\n"
help_str += "\n\nUnrecognized switches: " + repr(tuple(set(default_switches.keys()) - set(argv_switches.keys())))
help_str += "\nAborting.\n"
sys.stderr.write(help_str)
sys.exit(1)

# Setting argv element to the value type of the default.
for k in argv_switches.keys():
if type(default_switches[k]) != type(argv_switches[k]):
if not isinstance(default_switches[k], type(argv_switches[k])):
argv_switches[k] = str2type[type(default_switches[k])](argv_switches[k])

help_str = "\n" + argv[0] + " Syntax:\n\n"
Expand All @@ -116,7 +148,7 @@ def fargv(default_switches, argv=None, use_enviromental_variables=True, return_n
help_str += "\nAborting.\n"

# replace {blabla} with argv_switches["balbla"] values
replacable_values = ["{" + k + "}" for k in list(argv_switches.keys())]
# replacable_values = ["{" + k + "}" for k in list(argv_switches.keys())]
while len(re.findall("{[a-z0-9A-Z_]+}", "".join([v for v in list(argv_switches.values()) if isinstance(v, str)]))):
for k, v in list(argv_switches.items()):
if isinstance(v, str):
Expand All @@ -125,7 +157,12 @@ def fargv(default_switches, argv=None, use_enviromental_variables=True, return_n
if argv_switches["help"]:
sys.stderr.write(help_str)
sys.exit()
del argv_switches["help"]
elif argv_switches["bash_autocomplete"]:
sys.stdout.write(generate_bash_autocomplete(default_switches, sys.argv[0]))
sys.exit()
else:
del argv_switches["help"]
del argv_switches["bash_autocomplete"]

if return_named_tuple:
argv_switches = namedtuple("Parameters", argv_switches.keys())(*argv_switches.values())
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ home-page = https://github.com/anguelos/fargv
description = A very easy to use argument parser.
long-description = file: README.md
license = MIT
license-file = COPYING
license-file = LICENSE.txt
platform = any
keywords = {argv, CLI, argument}
classifiers =
Expand Down
24 changes: 17 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
from distutils.core import setup

import setuptools
#import setuptools
from setuptools import setup, Extension

setup(
name='fargv',
version='0.1.0',
version='0.1.1',
packages=['fargv'],
license='Creative Commons Attribution-Noncommercial-Share Alike license',
long_description=open('README.md').read(),
license='MIT',
author='Anguelos Nicolaou',
author_email='[email protected]',
url='https://github.com/anguelos/fargv',
)
description = "A very easy to use argument parser.",
long_description_content_type="text/markdown",
long_description=open('README.md').read(),
download_url = 'https://github.com/anguelos/fargv/archive/0.1.1.tar.gz',
keywords = ["argv", "CLI", "argument"],
classifiers=[
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Topic :: Scientific/Engineering"],
install_requires=[],
)

0 comments on commit 625c65a

Please sign in to comment.