Comments (28)
@justinpinkney Did you ever figure out a way to get the defaults correctly? Thanks in advance! My use case is to call the functions directly from the tests, but for every option that has a default I get something like <typer.models.OptionInfo object at 0x119787650>
instead of the default value. I suppose if I don't use the typer.Option as a default
it should work, but then I can take advantage of the --help
etc
from typer.
What about in the case I'm using the typer.Option("default")
syntax, now my function doesn't receive "default" as the default value, but instead a typer.models.OptionInfo object
Is there a way to deal with this?
from typer.
Can this issue be re-opened? It seems to be a relevant one.
Right now if we want to call a function from code we have to write duplicate functions just for the Typer CLI with Typer defaults and counterparts with regular python defaults - very ugly (
from typer.
I released this, with one more piece of functionality, as a PyPi module.
https://pypi.org/project/dtyper/
It's marked as beta, but I have complete test coverage and it's in use in a production project so far without issue.
from typer.
@tiangolo I agree that this issue should be reopened.
If one uses typer.Option
the function also requires that and not the actual type.
from typer.
I released this, with one more piece of functionality, as a PyPi module.
https://pypi.org/project/dtyper/
It's marked as beta, but I have complete test coverage and it's in use in a production project so far without issue.
That looks great, I'll try it out.
For reference, I've been using this decorator function to get the defaults:
import inspect
def set_default_values(function):
def wrapper(**kwargs):
# first, check if any of the kwargs is not included in the signature of the function and raise an error if so
for kwarg in kwargs:
if kwarg not in inspect.signature(function).parameters:
raise ValueError(f'{kwarg} is not a valid argument for {function.__name__}')
new_kwargs = {}
for default_kwarg in inspect.signature(function).parameters.values():
if default_kwarg.name in kwargs.keys():
new_kwargs[default_kwarg.name] = kwargs[default_kwarg.name]
else:
if isinstance(default_kwarg.default, typer.models.OptionInfo):
new_kwargs[default_kwarg.name] = default_kwarg.default.default
else:
new_kwargs[default_kwarg.name] = default_kwarg
return function(**new_kwargs)
if __name__ == '__main__':
return function()
else:
return wrapper
@set_default_values
@app.command ...
from typer.
+1 for this ! Still not a dead topic imo.
from typer.
from typer.
After thinking about the above for quite a while, I wrote a decorator that takes typer functions and automatically creates a callable dataclass
with the same signature and proper defaults, which in many ways is even better, because you can easily write methods and properties.
The code is not long: dcommand.py.
Here's a test that shows how to use it.
I'm using this in production in a proprietary project and it's worked very well to reduce clutter and repetition, and to share code between typer and non-typer sides - and it lets me (more or less) unit test my typer commands, which is great.
I could easily productionize it into a separate pypi module, or prepare it for release into typer if there were any interest.
from typer.
If @tiangolo pointed me to the right place, I could easily emit a pull request to add this to typer
.
from typer.
A function in a Typer app is not modified by Typer, it's still a normal function. So, you should be able to call it directly as you normally would, just make sure you pass all the parameters to it.
from typer.
I am experiencing exactly the same issue.
The problem is hidden in this statement above: "A function in a Typer app is not modified by Typer, it's still a normal function. So, you should be able to call it directly as you normally would, just make sure you pass all the parameters to it."
(Italics mine.)
I want to call a Typer function which takes seven parameters, only one of which I want to modify.
So I need to pass in seven default arguments to get the one real argument in, and if I ever change any default, I now have to change it not just in the code but at every call site.
I can see how this would be fixed in Typer. It wouldn't be trivial, you'd have to use inspection on the function, and then decorate it based on that.
from typer.
I agree this is an issue which should be fixed
from typer.
I want to support and recommend Annotated
, that will alleviate a lot of these problems.
from typer.
Hello again! This is fixed in dtyper 2.0.0 which I just released.
The major version number increase is because typer.Option
arguments are now keyword-only, when before they were positional or keyword.
While this is technically a breaking change, it's unlikely that any real world code will be affected by this, and it fixes that bug rec/dtyper#4. Named arguments are always preferred in general anyway.
I think Arguments
-> positional or keyword, Options
-> keyword only is the clearest conceptual solution but open to arguments.
Thanks for finding this, I even had a unit test testing the wrong behavior!
If you file bugs right on https://github.com/rec/dtyper/issues, I'll be less likely to miss them.
from typer.
Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues.
from typer.
@justinpinkney Did you ever figure out a way to get the defaults correctly? Thanks in advance! My use case is to call the suctions directly from the tests, by for every option that has a default I get something like
<typer.models.OptionInfo object at 0x119787650>
instead of the default value. I suppose if I don't use the typer.Option as adefault
it should work, but then I can take advantage of the--help
etc
My problem exactly, didn't find a good way around this.
from typer.
Yes, so we literally write two functions - one with typer.Option
and friends, which calls the second one, which only contains plain default values.
This way we get --help
, type casting, enum checking at runtime and all what typer offers and still have a way to call the original function
The only problem is - you know - there are two functions
How a workaround for the problem we all have may look like- Typer.add_command
automatically generates a plain version of decorated function and make it available through -say- .original
attribute
from typer.
The suggested workarounds make the code very ugly. It would be awesome if Typer can fix this
from typer.
Indeed, this shouldn't be closed. It's the biggest blemish this otherwise somewhat elegant library has.
from typer.
@rec thank you! just putting @dtyper.function
over my command works. Except one issue.
In typer you can require user to provide some option/argument by setting default to ellipsis (...
). Usually you can put requried options in the mix with optional. E.g.
@dtyper.function
@app.command()
def main(
city: str = Option("New York"),
name: str = Option(...),
)
Now this code is invalid, emitting ValueError: non-default argument follows default argument
emitting from lib inspect
.
from typer.
Now this code is invalid, emitting
ValueError: non-default argument follows default argument
emitting from libinspect
.
Arg, I am so sorry I just saw this comment from last week a few moments ago!!!
I guess it was part of this thread so I didn't look closely enough.
I filed an issue against the project rec/dtyper#4 and I will fix this perhaps tonight but otherwise tomorrow.
Sorry again!
from typer.
@tiangolo Do you mind elaborating more on how we can leverage Annotated
in this case? Thank you!
from typer.
@mirestrepo I haven't implemented it yet, but it will look more or less like this:
@app.command()
def main(
city: Annotated[str, Option("New York")],
):
print(city)
from typer.
@tiangolo hi! do you intend to implement this feature in package? i mean natively running typer commands from python code as usual functions?
from typer.
The code to do it is here and here.
from typer.
+1 for this! any plans to implement?
from typer.
It seems the solution proposed by Sebastián was implemented in the mean time and is reflected in the docs -- see https://typer.tiangolo.com/tutorial/options/help/
from typer.
Related Issues (20)
- How do I pass the None value explicitly? HOT 2
- Documentation is misleading. new `typer.run` behavior HOT 2
- See if rich 13.x is compatible HOT 4
- Using `some_type | None` syntax for type annotations causes error in python 3.11 HOT 12
- unlimited argument for an option with comma spliter HOT 1
- TAB completion is giving local directory files where command is called. HOT 2
- Support for bytes in Options and Arguments HOT 1
- Is it possible to include a Prolog in `--help` HOT 2
- Get the typer output with html format to provide it to termynal HOT 4
- how to use typer on class method __init__ with self argument, got this error: Error: Missing argument 'SELF'. HOT 2
- Support for localization of messages HOT 1
- Auto-completion when application works in 2 modes (GUI, CLI) HOT 1
- DOC: Documentation of passing multiple values in "option" vs "argument" isn't sufficiently explicit HOT 1
- SIGINT from docker is ignored HOT 4
- 🚀 Roadmap HOT 2
- Source distribution of 0.11.0 is missing the `docs_src` folder HOT 1
- 🐛 Upgrading from `typer<0.12.0` to `typer==0.12.0` breaks the install by partially removing the package/module files HOT 4
- Rich markup in generated Markdown docs
- Add CI configs to run tests on Windows and MacOS
- Rich markup in Zsh completion help lines
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typer.