typer
typer copied to clipboard
get_app_dir documentation suggests functionality regarding config files which is not there (yet?)
First Check
- [X] I added a very descriptive title to this issue.
- [X] I used the GitHub search to find a similar issue and didn't find it.
- [X] I searched the Typer documentation, with the integrated search.
- [X] I already searched in Google "How to X in Typer" and didn't find any information.
- [X] I already read and followed all the tutorial in the docs and didn't find an answer.
- [X] I already checked if it is not related to Typer but to Click.
Commit to Help
- [X] I commit to help with one of those options 👆
Example Code
from pathlib import Path
import typer
import somesubcommand
app = typer.Typer(help="FooBar CLI")
app.add_typer(somesubcommand.app)
@app.callback(invoke_without_command=True)
def main():
app_dir = typer.get_app_dir("foobar")
app_dir_path = Path(app_dir)
app_dir_path.mkdir(parents=True, exist_ok=True)
config_path: Path = Path(app_dir) / "config.json"
if not config_path.is_file():
typer.echo("Config file doesn't exist yet. Creating new one.")
config_path.write_text('''{
"API_ENDPOINT": "http://1.2.3.4:8080",
"API_USERNAME": "foo",
"API_PASSWORD": "bar"
}
''')
typer.echo(f"Config file created at {config_path}")
typer.echo("Please alter it according to your needs.")
config_file_str = str(config_path)
typer.echo("Opening config directory")
typer.launch(config_file_str, locate=True)
if __name__ == "__main__":
app()
Description
The documentation suggests to use click's get_app_dir for storing configuration files.
This works perfectly well, but you cannot use them easily and therefore readers are mislead.
E.g. you want to use config values inside somesubcommand, you still have to read the config file.
To do this, you still have to run typer.get_app_dir
inside somesubcommand, but you need to hard-code the application name again. Not very nice :)
Wanted Solution
Improved documentation on how to read / use the config file in a nice way.
Wanted Code
from pathlib import Path
import typer
import somesubcommand
app = typer.Typer(help="FooBar CLI")
app.add_typer(somesubcommand.app)
@app.callback(invoke_without_command=True)
def main():
app_dir = typer.get_app_dir("foobar")
app_dir_path = Path(app_dir)
app_dir_path.mkdir(parents=True, exist_ok=True)
config_path: Path = Path(app_dir) / "config.json"
if not config_path.is_file():
typer.echo("Config file doesn't exist yet. Creating new one.")
config_path.write_text('''{
"API_ENDPOINT": "http://1.2.3.4:8080",
"API_USERNAME": "foo",
"API_PASSWORD": "bar"
}
''')
typer.echo(f"Config file created at {config_path}")
typer.echo("Please alter it according to your needs.")
config_file_str = str(config_path)
typer.echo("Opening config directory")
typer.launch(config_file_str, locate=True)
# maybe something like this?
typer.load_config(config_file_str)
# one would access the values then in other files by
#
# import typer.CONFIG
# CONFIG["API_ENDPOINT"]
if __name__ == "__main__":
app()
Alternatives
State somewhere, that getting the application directory is great, but that it does not help when you want to read the config file.
Operating System
Linux, macOS
Operating System Details
Operating system should not affect this topic.
Typer Version
0.5.0
Python Version
3.10.5
Additional Context
You do great stuff!
get_app_dir
is only supposed to give you a standard location for where files can be stored based on OS. It's not responsible for interacting with any files you store there..
You might want to reconsider how you're handling creating/reading the config file. For example, for a single file, you can move that logic to the global space outside of Typer commands and callbacks. For a CLI package, you could set up config files in your packages __init__.py
. That way you can create and reference your settings object (configparser, Pydantic, whatever else you like to use) from a central location.
I don't think Typer forcing a user into any particular format for loading settings is a good idea but you might want to check out Pydantic's BaseSettings
Thanks for the help @daddycocoaman and thanks for closing the issue @tibeer ! ☕🍰