epsy / clize Goto Github PK
View Code? Open in Web Editor NEWCLIze: Turn Python functions into command-line interfaces
Home Page: http://clize.readthedocs.io/
License: MIT License
CLIze: Turn Python functions into command-line interfaces
Home Page: http://clize.readthedocs.io/
License: MIT License
Hi,
Thanks for this project....
I am reading examples from documentation and get problem/error trying to use dictionnary as alternate commands list.
Following is the code (mainly copied from documentation) and the errors i get.
What i am doing wrong ?
from clize import ArgumentError, Parameter, run
VERSION = "0.2"
#------------------------------------------------------------------------------
def echo(*text:Parameter.REQUIRED,
prefix:'p'='', suffix:'s'='', reverse:'r'=False, repeat:'n'=1):
"""Echoes text back
:param text: The text to echo back
:param reverse: Reverse text before processing
:param repeat: Amount of times to repeat text
:param prefix: Prepend this to each line in word
:param suffix: Append this to each line in word
"""
text = ' '.join(text)
if 'spam' in text:
raise ArgumentError("I don't want any spam!")
if reverse:
text = text[::-1]
text = text * repeat
if prefix or suffix:
return '\n'.join(prefix + line + suffix for line in text.split('\n'))
return text
#------------------------------------------------------------------------------
def version():
"""Show the version"""
return (f"version={VERSION}")
#------------------------------------------------------------------------------
def build_date(*,show_time=False):
"""Show the build date for this version"""
print("Build date: 17 August 1979", end='')
if show_time:
print(" afternoon, about tea time")
print()
#------------------------------------------------------------------------------
if __name__ == '__main__':
# next is OK
# run(echo, alt=[version, build_date])
# this not working
run(echo, alt=
{ "totally_not_the_version": version,
"birth": build_date
})
Tested with python 3.6.9 and 3.9.0
cd /home/user/MyPyProjs/Py390/CliTests
venv_activate
(venv) > python clize_t01.py
Traceback (most recent call last):
File "/home/user/MyPyProjs/Py390/CliTests/clize_t01.py", line 51, in <module>
run(echo, alt={
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/sigtools/modifiers.py", line 161, in __call__
return self.func(*args, **kwargs)
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/runner.py", line 395, in run
ret = cli(*args)
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/runner.py", line 261, in __call__
func, name, posargs, kwargs = self.read_commandline(args)
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/runner.py", line 271, in read_commandline
ba = self.signature.read_arguments(args[1:], args[0])
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/util.py", line 121, in __get__
ret = obj.__dict__[self.key] = self.func(obj)
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/runner.py", line 220, in signature
return parser.CliSignature.from_signature(
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/parser.py", line 1143, in from_signature
return cls(
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/parser.py", line 1107, in __init__
for param in _develop_extras(parameters):
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/parser.py", line 1052, in _develop_extras
for param in params:
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/runner.py", line 252, in _process_alt
for name, func in util.dict_from_names(alt).items():
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/util.py", line 104, in dict_from_names
receiver.update((x.__name__, x) for x in maybe_iter(obj))
File "/home/user/MyPyProjs/Py390/CliTests/venv/lib/python3.9/site-packages/clize/util.py", line 104, in <genexpr>
receiver.update((x.__name__, x) for x in maybe_iter(obj))
AttributeError: 'str' object has no attribute '__name__'
I'm using clize with attrs>=20.3.0. requirements are currently conflict between clize and attrs.
Any plan for update attrs>=19.1.0,<20
to attrs>=19.1.0,<21
?
I don't understand, how I can disable multiple help, if my program contains multiple files.
For example, I have a folder with 4 files:
config.py
(see #33):import logbook
import sys
log = logbook.Logger("Sasha Logbook")
def clize_log_level(*, logbook_level: 'll'="NOTICE"):
"""Change log levels via command line.
User select, which logging messages to see. See about 6 log levels here:
https://logbook.readthedocs.io/en/stable/quickstart.html
:param logbook_level: user select logging level
"""
if logbook_level == "DEBUG":
logbook.StreamHandler(sys.stdout,
level=logbook.DEBUG).push_application()
elif logbook_level == "ERROR":
logbook.StreamHandler(sys.stdout,
level=logbook.ERROR).push_application()
else:
logbook.StreamHandler(sys.stdout,
level=logbook.NOTICE).push_application()
first_test.py
:from clize import run
from config import clize_log_level
from config import log
run(clize_log_level, exit=False)
log.debug("First test + debug message")
log.notice("First test + notice message")
log.error("First test + error message")
first_test_variable = True
second_test.py
:from clize import run
from config import clize_log_level
from config import log
run(clize_log_level, exit=False)
log.debug("Second test + debug message")
log.notice("Second test + notice message")
log.error("Second test + error message")
second_test_variable = True
run_tests.py
:from clize import run
from config import clize_log_level
from config import log
from first_test import first_test_variable
from second_test import second_test_variable
if first_test_variable and second_test_variable is True:
log.debug("Run tests + debug message")
log.notice("Run tests + notice message")
log.error("Run tests + error message")
If I run run_tests.py
, run first_test.py
and second_test.py
. Logging messages from first_test.py
and second_test.py
return.
The program works as expected:
D:\SashaClize>python run_tests.py --ll=DEBUG
[2018-01-06 15:21:38.251565] DEBUG: Sasha Logbook: First test + debug message
[2018-01-06 15:21:38.251565] NOTICE: Sasha Logbook: First test + notice message
[2018-01-06 15:21:38.251565] ERROR: Sasha Logbook: First test + error message
[2018-01-06 15:21:38.252565] DEBUG: Sasha Logbook: Second test + debug message
[2018-01-06 15:21:38.253197] NOTICE: Sasha Logbook: Second test + notice message
[2018-01-06 15:21:38.253332] ERROR: Sasha Logbook: Second test + error message
[2018-01-06 15:21:38.253457] DEBUG: Sasha Logbook: Run tests + debug message
[2018-01-06 15:21:38.253556] NOTICE: Sasha Logbook: Run tests + notice message
[2018-01-06 15:21:38.253556] ERROR: Sasha Logbook: Run tests + error message
D:\SashaClize>python run_tests.py --ll=ERROR
[2018-01-06 15:22:01.131626] ERROR: Sasha Logbook: First test + error message
[2018-01-06 15:22:01.132525] ERROR: Sasha Logbook: Second test + error message
[2018-01-06 15:22:01.133558] ERROR: Sasha Logbook: Run tests + error message
One problem: help menu show for me 2 times:
D:\SashaClize>python run_tests.py --help
Usage: run_tests.py [OPTIONS]
Change log levels via command line.
User select, which logging messages to see. See about 6 log levels here: https://logbook.readthedocs.io/en/stable/quickstart.html
Options:
--logbook-level, --ll=STR user select logging level (default: NOTICE)
Other actions:
-h, --help Show the help
Usage: run_tests.py [OPTIONS]
Change log levels via command line.
User select, which logging messages to see. See about 6 log levels here: https://logbook.readthedocs.io/en/stable/quickstart.html
Options:
--logbook-level, --ll=STR user select logging level (default: NOTICE)
Other actions:
-h, --help Show the help
If I have more <number>_test
files, I have more help repeats.
How I need edit in my code, that don't see help multiple times?
Thanks.
Create and help install bash and zsh-compatible autocompletion scripts.
The docs currently use sigtools.modifiers
decorators to augment parameters with annotations or to make them keyword-only. I'm suspecting this distracts users from the examples' main points.
Given:
I suggest adjusting the examples so they make use of keyword-only parameters and annotations, and using "note" sections destined to users stuck with Python 2 or trying to keep compatibility with it.
In most programs, what I use, I can get version, use --version
and -v
command line arguments without additional parameters.
D:\SashaPythonista>python SashaAscent.py --version
Do Nothing version 0.2
or
D:\SashaPythonista>python SashaAscent.py -v
0.2
I don't understand, how I can to create the same behavior, if I write a program, use Clize.
from clize import run
VERSION = "0.2"
def program_version(version):
print(VERSION)
run(program_version)
That get a version, I need input version
, not --version
:
D:\SashaPythonista>python SashaAscent.py version
0.2
D:\SashaPythonista>python SashaAscent.py --version
SashaAscent.py: Unknown option '--version'
Usage: SashaAscent.py version
from clize import run
VERSION = "0.2"
def program_version(b="VERSION", *, version:'v'=True):
"""Show the version"""
if version is True:
b = "0.2"
print(b)
run(program_version)
I need input -v b
, not -v
:
D:\SashaPythonista>python SashaAscent.py -v b
0.2
from clize import run
VERSION = "0.2"
def do_nothing():
"""Does nothing"""
return "I did nothing, I swear!"
def version():
"""Show the version"""
print(VERSION)
run(do_nothing, alt=version)
It works for --version
,
D:\SashaPythonista>python SashaAscent.py --version
0.2
but I don't find, how I can to create alias -v
.
It works nice.
from clize import run
VERSION = "0.2"
def do_nothing():
"""Does nothing"""
return "I did nothing, I swear!"
def version():
"""Show the version"""
print(VERSION)
def v():
"""Show the version"""
print(VERSION)
run(do_nothing, alt=[version, v])
But in --help
menu -v
is not --version
alias.
Actual:
D:\SashaPythonista>python SashaAscent.py --help
Usage: SashaAscent.py
Does nothing
Other actions:
-h, --help Show the help
--version Show the version
-v Show the version
Expected:
D:\SashaPythonista>python SashaAscent.py --help
Usage: SashaAscent.py
Does nothing
Other actions:
-h, --help Show the help
-v, --version Show the version
Thanks.
My CLI program successful work for disk C, but not for disk D.
Possibly, it Clize bug, not bug in my program.
https://github.com/Kristinita/SashaPythonTest
my simple program check, contains <body>
in .txt
files in folder or no.
It that I want in #35.
I have 2 folders with similar content:
SashaPythonTestOnDiskC
— on disk C,SashaPythonTestOnDiskD
— on disk D.Content of SashaPythonTestOnDiskC
and SashaPythonTestOnDiskD
folders:
C:\SashaPythonTestOnDiskC>tree /f
C:.
BodyExists.txt
NoBody.txt
BodyExists.txt
file:
<body>
NoBody.txt
file:
No
I install my project:
setup.py install
I run command sashatest
in console.
For C:\SashaPythonTestOnDiskC
:
C:\SashaPythonTestOnDiskC>sashatest --help
Usage: ..\Python36\Scripts\sashatest [OPTIONS]
Change log levels via command line.
User select, which logging messages to see. See about 6 log levels here: https://logbook.readthedocs.io/en/stable/quickstart.html
Options:
--logbook-level, --ll=STR user select logging level (default: NOTICE)
Other actions:
-h, --help Show the help
--version Show version.
-v Alternative show version.
C:\SashaPythonTestOnDiskC>sashatest
[2018-01-20 17:44:13.035785] ERROR: eric_body logbook: File NoBody.txt not contain <body>.
[2018-01-20 17:44:13.036806] ERROR: eric_body logbook: Not all files contains <body>. Please, correct your files.
[2018-01-20 17:44:13.036806] ERROR: run_tests logbook: Failure!
C:\SashaPythonTestOnDiskC>sashatest --ll=DEBUG
[2018-01-20 17:52:41.227187] DEBUG: eric_body logbook: BodyExists.txt contains <body>
[2018-01-20 17:52:41.228178] ERROR: eric_body logbook: File NoBody.txt not contain <body>.
[2018-01-20 17:52:41.228178] ERROR: eric_body logbook: Not all files contains <body>. Please, correct your files.
[2018-01-20 17:52:41.228178] ERROR: run_tests logbook: Failure!
For D:\SashaPythonTestOnDiskD
:
D:\SashaPythonTestOnDiskD>sashatest
Traceback (most recent call last):
File "C:\Python36\Scripts\sashatest-script.py", line 11, in <module>
load_entry_point('sashatest==0.0.1', 'console_scripts', 'sashatest')()
File "C:\Python36\lib\site-packages\sashatest-0.0.1-py3.6.egg\sashatest\__main__.py", line 18, in main
run(clize_log_level, alt=[version, v], exit=False)
File "C:\Python36\lib\site-packages\sigtools\modifiers.py", line 158, in __call__
return self.func(*args, **kwargs)
File "C:\Python36\lib\site-packages\clize\runner.py", line 353, in run
args = fix_argv(sys.argv, sys.path, module)
File "C:\Python36\lib\site-packages\clize\runner.py", line 284, in fix_argv
name = get_executable(argv[0], argv[0])
File "C:\Python36\lib\site-packages\clize\runner.py", line 303, in get_executable
rel = os.path.relpath(path)
File "C:\Python36\lib\ntpath.py", line 585, in relpath
path_drive, start_drive))
ValueError: path is on mount 'C:', start on mount 'D:'
Thanks.
The following code doesn't work as expected when a value is provided:
from clize import run
from clize.converters import file
def write_config(*args, output: file(mode='w')='-'):
"""Write out a sample config file.
:param output: the path to the file to write.
"""
with output as fp:
fp.write("hi!\n")
if __name__ == '__main__':
run(write_config)
What I expected was the default would be not be used, but in this case it is always used even if I pass a parameter. For example:
$ python test.py --output=/tmp/test
hi!
AFAICS changes made to clize.parser.CliBoundArguments
in c2b5b85 have created the problem.
I have a function definition with a parameter of type typing.List[str]
. I'd like for this to be handled in the CLI as an argument that supports multiple entries either --foo arg1 arg2 arg3
or preferably --foo arg1 --foo arg2 --foo arg3
. Is this possible with Clize? If so, what's the best way to accomplish this?
Salut @epsy. 👋
It seems that if you have two @argument_decorator
decorated functions and want to use one inside the other, it's currently impossible.
Intuitively, I'd have expected it to work by:
@argument_decorator
def foo(bar):
return bar
@argument_decorator
def baz(qux):
return foo(qux)
@argument_decorator
def foo(bar):
return bar
@argument_decorator
def baz(qux: foo):
return qux
What's your recommandation on this? Would you see yourself implement one of those two examples?
Hi,
$ pip show clize
Name: clize
Version: 4.0.3
Summary: Turn functions into command-line interfaces
Home-page: https://github.com/epsy/clize
Author: Yann Kaiser
Author-email: [email protected]
License: MIT
Location: .../lib/python3.6/site-packages
Requires: docutils, six, sigtools, od, attrs
Here is a sample program to reproduce the traceback.
from sigtools.wrappers import decorator
from clize import run
@decorator
def f(a, *args, name=False, **kwargs):
args = args
return a(*args, **kwargs)
@f
def g():
pass
run(g)
Here is the crash :
$ python -m pdb my-sigtool.py --help
Traceback (most recent call last):
File "my-sigtool.py", line 16, in <module>
run(g)
File ".../lib/python3.6/site-packages/sigtools/modifiers.py", line 158, in __call__
return self.func(*args, **kwargs)
File ".../lib/python3.6/site-packages/clize/runner.py", line 360, in run
ret = cli(*args)
File ".../lib/python3.6/site-packages/clize/runner.py", line 220, in __call__
return func(*posargs, **kwargs)
File ".../lib/python3.6/site-packages/clize/runner.py", line 220, in __call__
return func(*posargs, **kwargs)
File ".../lib/python3.6/site-packages/sigtools/modifiers.py", line 158, in __call__
return self.func(*args, **kwargs)
File ".../lib/python3.6/site-packages/clize/help.py", line 887, in cli
help = self.get_help()
File ".../lib/python3.6/site-packages/clize/help.py", line 896, in get_help
return self.builder(self.subject, self.owner)
File ".../lib/python3.6/site-packages/clize/help.py", line 449, in from_subject
ret.add_from_parameter_sources(subject)
File ".../lib/python3.6/site-packages/clize/help.py", line 491, in add_from_parameter_sources
for func in func_signature.sources[pname]:
KeyError: 'args'
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> .../lib/python3.6/site-packages/clize/help.py(491)add_from_parameter_sources()
-> for func in func_signature.sources[pname]:
(Pdb) pp func_signature.sources
{'+depths': {<function g at 0x7f700f11f950>: 3,
<function _SimpleWrapped.__call__ at 0x7f70113f89d8>: 0,
<function f at 0x7f7011d7d950>: 2,
functools.partial(<function f at 0x7f7011d7d950>, <function g at 0x7f700f11f950>): 1},
'name': [<function f at 0x7f7011d7d950>]}
(Pdb)
I expect a more insightful error. I'm wondering wheither the bug is in clize or sigtools.
I found a workaround : i edit kwargs
instead of varargs.
Currently Clize converts each Python parameter to a Parameter
instance by calling a function and using its result:
This makes it impossible to use parameters.multi
with parameters.one_of
, for instance. This is counter-intuitive and also quite unfortunate.
To fix this, the parameter converter should collect callables from the annotations designated as "post-converters". Once the parameter converter has completed creating a Parameter
instance, it should post-process this parameter with each post-converter in order. Each post converters does some changes and returns a Parameter
instance, much like decorators.
Example post-converters:
parameter.one_of
, parameter.mapped
, (both already existing as parameter converters)argument_decorator
, (already existing as parameter converter)argparse
calls it metavar)UNDOCUMENTED
and LAST_OPTION
could be refactored as post-converters.The documentation will need additional clarification on the roles of parameter converters, post-converters and value converters, possibly with a drawing :)
Is this project alive / still maintained? I really like what I see but I can't use it if this project is not maintained anymore...
Usefulness and API to be determined.
Clize currently supports sharing behavior and parameters through decorators. They offer flexibility in that they can be used arbitrarily, at the cost of limiting usage of those parameters to only after all arguments that designate subcommands. example:
$ prog command --quiet # ok because command is decorated with @with_output_control
$ prog --quiet command # not ok because only command's decorators know of --quiet
This feature request proposes a more elaborate API be devised for creating groups of commands, one that allows for behavior and parameters to be processed at the group level.
Either in the first example or a standalone Python concepts
page before the first part of the tutorial.
title says it all
I tried to find the instructions on how to add my entry point for the function call to setup.py, but the docs do not mention setup or setup.py?
In many cases, several names are needed to invoke the same command.
It would be nice to have a way to specify an alias for a command, and have the alias mentioned in the help, without the need to define repeated entries in a command dictionary, and without the redefined function appearing several times in the help message.
For instance, doing this:
# 1.py
import clize
def foo():
"Function foo"
pass
def bar():
"Function bar"
pass
if __name__ == '__main__':
clize.run(dict(foo=foo, bar=bar, foo2=foo))
produces
Usage: 1.py command [args...]
Commands:
foo Function foo
bar Function bar
foo2 Function foo
The desired outcome (by whatever method is implemented) would be more like
Usage: 1.py command [args...]
Commands:
foo Function foo (alias: foo2)
bar Function bar
While repeated_test
helps leverage large amounts of test cases succinctly, it is rather opaque to the uninitiated. The contribution guidelines for Clize should have an intro or link to such a document in repeated_test
's documentation.
The user reference should document the name translation that occurs when converting functions to CLIs. The tutorials should refer to this section when talking about option names and subcommand names. It should be highlighted that translation does not apply in parameter names in docstrings.
Initially reported as #17.
repeated_test
relies on unittest2
, which is longer compatible with python 3.10.
Both packages haven't been maintained in 5 years.
They should be dropped.
related: epsy/sigtools#26
$ prog --queit
prog: Unknown parameter --queit
prog: Did you mean "--quiet" ?
The latest version available on conda-forge is 4.2.1, but this is quite out of date. Would be nice to have version 5 available. It looks like there are pull requests open, but no-one has merged them: https://github.com/conda-forge/clize-feedstock/pulls
parameters.argument_decorator
currently ignores the annotations from the main parameter of the decorator function. This makes it impossible to use value converters for instance.
Currently Clize supports docstrings in docutils/Sphinx format and in its own legacy docstring format.
This could be done in one of two ways:
As it is if you write the following and no value is supplied, the function code will just receive the string 'default.json`. Instead, it should receive the same kind of value as it would if a value was supplied.
def fun(f: converters.file() = 'default.json'):
...
This may involve changes to parser's ParameterWithValue
[x] Bug (Typo)
overriden
, however expect to see overridden
.suplied
, however expect to see supplied
.succesfully
, however expect to see successfully
.sigatures
, however expect to see signatures
.regularily
, however expect to see regularly
.previoous
, however expect to see previous
.preferrable
, however expect to see preferable
.preceeded
, however expect to see preceded
.inteteger
, however expect to see integer
.insigna
, however expect to see insignia
.documenation
, however expect to see documentation
.contiue
, however expect to see continue
.contraints
, however expect to see constraints
.Semi-automated issue generated by
https://github.com/timgates42/meticulous/blob/master/docs/NOTE.md
To avoid wasting CI processing resources a branch with the fix has been
prepared but a pull request has not yet been created. A pull request fixing
the issue can be prepared from the link below, feel free to create it or
request @timgates42 create the PR. Alternatively if the fix is undesired please
close the issue with a small comment about the reasoning.
https://github.com/timgates42/clize/pull/new/bugfix_typos
Thanks.
Example:
>>> from clize import parser
>>> a=parser.CliSignature([])
>>> b=a.read_arguments([], "thing")
>>> str(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/moshez/src/caparg/build/caparg/lib/python3.6/site-packages/attr/_make.py", line 814, in repr_
for name in attr_names
File "/home/moshez/src/caparg/build/caparg/lib/python3.6/site-packages/attr/_make.py", line 814, in <genexpr>
for name in attr_names
AttributeError: 'CliBoundArguments' object has no attribute 'namedparam'
Expected instead useful string return value.
Technically this is a regression from Clize 2.4, although it never had translations back then.
This request proposes strings in Clize be actually marked, and a French translation to be made (by me, presumably).
Additionally, Clize should provide facilities for users to translate function and decorator docstrings so that client code can translate their --help
messages.
I was trying to figure out from the docs how to support custom types (even pathlib
's Path
) as well as python's type hints. Any pointers would be very appreciated.
For type hints, it looks like the values after the colon (:
) are being used by both clize and the typing library. I also want to use the typing library to indicate something is optional to the API, while also have it exposed with clize on the command line. For example:
from clize import run, Parameter
from typing import Optional
def double(*, number: ('n', Optional[int]) = 2):
'''
Doubles the number
:param number: the number to double
'''
print(2 * number)
if __name__ == '__main__':
run(double)
The documentation gives an example of how to create aliases:
def echo(*text:Parameter.REQUIRED,
prefix:'p'='', suffix:'s'='', reverse:'r'=False, repeat:'n'=1):
...
This, however, causes most linters to warn:
Unresolved reference 'p'
for all the aliases thus defined.
Since Python 3.9, typing.Annotated
is available to add metadata to annotations, so this could be defined as
def echo(*text:Parameter.REQUIRED,
prefix: Annotated[str, 'p'] ='',
suffix: Annotated[str, 's'] = '',
reverse: Annotated[str, 'r'] = False,
repeat: Annotated[int, 'n'] = 1,
):
...
and linters wouldn't complain.
Hi,
is there any way to set negative number as argument ?
# -*- coding: utf-8 -*-
from clize import ArgumentError, Parameter, run
def cli_main(arg:float, *, debug:'d'=False):
"""cli_main
:param arg: arg parameter
:param debug: debug flag
"""
return (arg,debug)
if __name__ == '__main__' :
run (cli_main)
>python cli.py --help
Usage: cli.py [OPTIONS] arg
cli_main
Arguments:
arg arg paramter (type: FLOAT)
Options:
-d, --debug debug flag
Other actions:
-h, --help Show the help
>python cli.py -10.0
cli.py: Unknown option '-1'
Usage: cli.py [OPTIONS] arg
I don't understand, how I can change one variable from command line.
For example, I have a file, where I use Logbook logging.
import logbook
import sys
logbook.StreamHandler(sys.stdout,
level=logbook.WARNING).push_application()
log = logbook.Logger("Sasha Logbook")
log.debug("Debug message")
log.warning("Warning message")
log.error("Error message")
If I run this file in console, I get output:
D:\SashaPythonista>python SashaLogbook.py
[2018-01-01 17:55:47.063625] WARNING: Sasha Logbook: Warning message
[2018-01-01 17:55:47.064624] ERROR: Sasha Logbook: Error message
Output, if logbook.StreamHandler(sys.stdout, level=logbook.DEBUG).push_application()
:
[2018-01-01 17:55:46.994054] DEBUG: Sasha Logbook: Debug message
[2018-01-01 17:57:26.982679] WARNING: Sasha Logbook: Warning message
[2018-01-01 17:57:26.983677] ERROR: Sasha Logbook: Error message
And so on.
If:
D:\SashaPythonista>python SashaLogbook.py level=DEBUG
[2018-01-01 17:55:46.994054] DEBUG: Sasha Logbook: Debug message
[2018-01-01 17:55:47.063625] WARNING: Sasha Logbook: Warning message
[2018-01-01 17:55:47.064624] ERROR: Sasha Logbook: Error message
If:
D:\SashaPythonista>python SashaLogbook.py level=WARNING
[2018-01-01 17:57:26.982679] WARNING: Sasha Logbook: Warning message
[2018-01-01 17:57:26.983677] ERROR: Sasha Logbook: Error message
And so on.
I try to add Clize:
import logbook
import sys
from clize import run
log = logbook.Logger("Sasha Logbook")
def test(level="WARNING"):
if level == "DEBUG":
logbook.StreamHandler(sys.stdout,
level=logbook.DEBUG).push_application()
if level == "WARNING":
logbook.StreamHandler(sys.stdout,
level=logbook.WARNING).push_application()
if level == "ERROR":
logbook.StreamHandler(sys.stdout,
level=logbook.ERROR).push_application()
run(test)
log.debug("Debug message")
log.warning("Warning message")
log.error("Error message")
If I replace run(test)
to test()
, Logbook messages print to console. But if I use run(test)
, I haven't output in console.
D:\SashaPythonista>python SashaLogbook.py --help
Usage: SashaLogbook.py [level]
Arguments:
level (default: WARNING)
Other actions:
-h, --help Show the help
D:\SashaPythonista>python SashaLogbook.py level=DEBUG
D:\SashaPythonista>python SashaLogbook.py level=ERROR
Thanks.
I don't understand, how I can disable print()
in output, if I run command with --help
or --version
.
For example, I have SashaClizePrint.py
file, based on my previous questions:
"""Demo code for #38.
Variables:
VARIABLE {bool} -- True or False
VERSION {str} -- version number
"""
import logbook
import sys
from clize import run
VARIABLE = True
VERSION = "0.1"
LOG = logbook.Logger("summary logbook")
def clize_log_level(*, logbook_level: 'll'="NOTICE"):
"""Change log levels via command line.
User select, which logging messages to see. See about 6 log levels here:
https://logbook.readthedocs.io/en/stable/quickstart.html
:param logbook_level: user select logging level
"""
if logbook_level == "DEBUG":
logbook.StreamHandler(sys.stdout,
level=logbook.DEBUG).push_application()
elif logbook_level == "NOTICE":
logbook.StreamHandler(sys.stdout,
level=logbook.NOTICE).push_application()
elif logbook_level == "ERROR":
logbook.StreamHandler(sys.stdout,
level=logbook.INFO).push_application()
def version():
"""Show version.
For details see:
https://clize.readthedocs.io/en/stable/dispatching.html#alternate-actions
"""
print(VERSION)
def main():
run(clize_log_level, alt=[version], exit=False)
if VARIABLE:
LOG.debug("Success!")
print("Success!")
else:
LOG.error("Failure!")
print("Failure!")
if __name__ == '__main__':
main()
I want, that Success!
print, if I run this file.
D:\Киролайна>python SashaClizePrint.py
[2018-01-22 10:59:34.455838] NOTICE: summary logbook: Success!
Success!
D:\Киролайна>python SashaClizePrint.py --ll=ERROR
Success!
But I don't want Success!
in console, if I want get help or version.
D:\Киролайна>python SashaClizePrint.py --help
Usage: SashaClizePrint.py [OPTIONS]
Change log levels via command line.
User select, which logging messages to see. See about 6 log levels here: https://logbook.readthedocs.io/en/stable/quickstart.html
Options:
--logbook-level, --ll=STR user select logging level (default: NOTICE)
Other actions:
-h, --help Show the help
--version Show version.
Success!
D:\Киролайна>python SashaClizePrint.py --version
0.1
Success!
In real, I want beautiful colored output instead of print("Success!")
, for example, as here.
I don't find, how I can log this output.
Thanks.
Say I have mycommand foo
and mycommand bar
. The way clize is written now, I have to write, when invoking mycommand
, either ./mycommand foo --debug
or ./mycommand bar --debug
and can't write ./mycommand --debug foo
. It'd be nice to be able to somehow specify common arguments that applied to all commands in a dispatch set.
Clize is geared towards letting code still be used as code, but the legacy of clize's docstring format impairs this.
Most notably, they cannot be properly parsed by sphinx.ext.autodoc as it is. A sphinx extension could be devised for this. However it is more preferable for Clize to support sphinx/docutils fields since it falls in line with the goal of not needing to learn anything new to use Clize.
Special care needs to be given towards the following:
It could be acceptable to diminish the flexibility of sections to just one per decorator.
Optionally, a directive could be added to format a function to be documented as a command-line interface.
Also, sphinx's contributed napoleon extension could be used to support Google- and Numpy-style docstrings.
if object of type pathlib.Path
is used as function argument, clize will complain:
ValueError: Cannot find value converter for default value PosixPath('/foo/bar'). Please specify one as an annotation.
If the default value's type should be used to convert the value, make sure it is decorated with clize.parser.value_converter()
how about add the converter in clize by default? Many of the standard lib in Python3 already changed to support pathlib
One thing that annoys me a lil bit is that install_requires has various deps that are only needed for testing.
Perhaps clize could move them to tests_require or install them specifically just for CI? What are your thoughts on this?
Is it possible to get shell autocompletion work with clize?
The decorator would allow the use of async functions by running them using loop.run_until_complete. This should be implemented in a way that doesn't prevent execution if asyncio isn't present. (import within the decorator will do)
I'm having a hard time interpreting what's wrong based on the error message. Can anyone throw me a bone? Or maybe it's a bug?
Here's all the code you need.
from pathlib import Path
from typing import List, Optional, Union
from clize import run
def clize_demo(
one_path_or_many_paths: Union[Path, List[Path]],
optional_path: Optional[Path] = None,
optional_int: Optional[int] = None,
bool_with_default: bool = False,
):
pass
if __name__ == "__main__":
run(clize_demo)
Here's what you get when you try it out.
(venv-clize) me@neato:~/repos/clive-demo$ python wow.py
Traceback (most recent call last):
File "wow.py", line 17, in <module>
run(clize_demo)
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/sigtools/modifiers.py", line 158, in __call__
return self.func(*args, **kwargs)
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/runner.py", line 363, in run
ret = cli(*args)
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/runner.py", line 219, in __call__
func, name, posargs, kwargs = self.read_commandline(args)
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/runner.py", line 229, in read_commandline
ba = self.signature.read_arguments(args[1:], args[0])
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/util.py", line 128, in __get__
ret = obj.__dict__[self.key] = self.func(obj)
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/runner.py", line 195, in signature
return parser.CliSignature.from_signature(
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/parser.py", line 998, in from_signature
return cls(
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/parser.py", line 962, in __init__
for param in _develop_extras(parameters):
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/parser.py", line 907, in _develop_extras
for param in params:
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/parser.py", line 1001, in <genexpr>
(cls.convert_parameter(param)
File "/home/me/virtualenvs/venv-clize/lib/python3.8/site-packages/clize/parser.py", line 1013, in convert_parameter
if Parameter.IGNORE in annotations:
File "/usr/lib/python3.8/typing.py", line 261, in inner
return func(*args, **kwds)
File "/usr/lib/python3.8/typing.py", line 685, in __getitem__
params = tuple(_type_check(p, msg) for p in params)
File "/usr/lib/python3.8/typing.py", line 685, in <genexpr>
params = tuple(_type_check(p, msg) for p in params)
File "/usr/lib/python3.8/typing.py", line 149, in _type_check
raise TypeError(f"{msg} Got {arg!r:.100}.")
TypeError: Parameters to generic types must be types. Got 0.
OrderedDict is a new class added to Python 2.7, so Clize is not compatible with Python 2.6.
To solve this issue, you can install a backport:
pip install ordereddict
and patch Clize by replacing:
from collections import OrderedDict
by
try:
from collections import OrderedDict
except ImportError:
# python 2.6 or earlier, use backport
from ordereddict import OrderedDict
I will propose an pull request.
Hi team, I have tried getting my head around using clize and I came across unexpected behaviour with function names that use capitals. For a start, what is the rational for altering the function names, ie. converting all to lower case and replying underscores? To me it defeats the point of having a CLI that corresponds to my code as closely as possible. I'm guessing it's a Windows related problem. But here is the buggy thing about it. Mini example from the docs, with a camel-cased function name:
import clize
def addThis():
return "OK I will remember that."
def list_():
"""Lists the existing entries."""
return "Sorry I forgot it all :("
if __name__=='__main__':
clize.run(addThis, list_)
On the command line:
$> python testclize.py --help
Usage: testclize.py command [args...]
Commands:
addThis
list Lists the existing entries.
Great, addThis
is a command. But then:
$> python testclize.py addThis
testclize.py: Unknwon command "addthis"
$> python testclize.py addthis
testclize.py: Unknwon command "addthis"
What am I missing here?
Tested on both py2.7 and 3.5 under Linux SLES 11.3 (64_x86).
There is a new clize version 4.1.1 on pypi, but suspiciously no corresponding tag or commits in this repository. A mistake or has the official repository been moved somewhere else?
Given that Clize now supports most decorators and docstring formats, the time seems right to introduce this idea again:
$ python -m clize some_module.some_function arguments for --that function
would be (roughly) equivalent to the Python code:
from some_module import some_function
some_function('arguments', 'for', that='function')
Additionally, an entry point can be added to setup so that you can use clize ...
instead of python -m clize ...
.
Tips:
some_function
may not be directly importable, e.g. some_module.SomeClass.some_classmethod
Usage:
line of the --help
output needs to match what was entered.This code in 1.py:
import clize
def main(*, update:'U'=False, uranus:'u'=False):
pass
if __name__ == '__main__':
clize.run(main)
produces this result:
> 1.py -h
ValueError: parameters '--update' and '--uranus' use a duplicate alias '-u'
In previous versions this worked.
Tested in Windows 7, Python 3.6.2, clize 4.0.3
Please, could you update Pypi with version which supports sub commands? Thank you!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.