Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A brief usage example of how click and pydantic interact would be helpful #1

Open
ricosaurus opened this issue Apr 21, 2021 · 2 comments

Comments

@ricosaurus
Copy link

ricosaurus commented Apr 21, 2021

I am interested in configuring command-line parsing from pydantic models -- this could be very useful as I switched from standard dataclasses to pydantic, and would love to integrate these models with command line parsing. However I am having a bit of trouble trying to figure out intended use from your tests.

For example, if I attempt to replicate your test_basic_field function:

import sys
from typing import Dict, List, Tuple, Type, Any
from pydantic import BaseModel, BaseSettings

from cyto.settings import autofill

# from cyto/tests/conftest.py
class Argv:
    def __init__(self, monkeypatch: Any) -> None:
        self._monkeypatch = monkeypatch
        self._sys_argv_first = sys.argv[0]
        self.clear()

    def assign(self, *args: Any) -> None:
        """Clear existing arguments first and append the given ones."""
        self.clear()
        self.append(*args)

    def clear(self) -> None:
        self._argv = [self._sys_argv_first]
        self._update()

    def append(self, *args: Any) -> None:
        self._argv += args
        self._update()

    def _update(self) -> None:
        self._monkeypatch.setattr(sys, "argv", self._argv)

# from cyto/tests/settings/conftest.py
class MyTunesSettings(BaseSettings):
    theme: str
    volume: int = 80
    shuffle: bool = True
    translations: Dict[str, str] = {
        "repeat": "repetir",
        "shuffle": "barajar",
    }

# from cyto/tests/settings/sources/test_source_cli.py
def test_basic_field(
    mytunes_settings: Type[MyTunesSettings],
    argv: Argv,
) -> None:
    
    # Set the required field
    argv.append("--theme", "dark")
    settings = mytunes_settings()
    assert settings.theme == "dark"
    # Non-required fields get their default value
    assert settings.volume == 80
    assert settings.shuffle is True
    assert settings.translations == {
        "repeat": "repetir",
        "shuffle": "barajar",
    }
....

presumably I could create a mytunes_settings arg with

mytunes_settings = autofill(name="mytunes")(MyTunesSettings)

but I haven't figured out what the 'monkeypatch' arg for Argv should be, eg how to construct argv. Taking a stab at it, since it requires setattr that can manipulate sys.argv:

class Patch:
    def setattr(self, obj, k, v):
        setattr(obj, k, v)
    
monkeypatch = Patch()

mytunes_settings = autofill(name="mytunes")(MyTunesSettings)
argv = Argv(monkeypatch)
argv.append("--theme", "dark")
settings = mytunes_settings()
assert settings.theme == 'dark'

print(settings)

theme='dark' volume=80 shuffle=True translations={'repeat': 'repetir', 'shuffle': 'barajar'}

gets me started, but just a toy example would be immensely helpful! I'll look forward to integrating cyto.

@frederikaalund
Copy link
Member

frederikaalund commented Apr 21, 2021

Thanks for raising this issue. 👍 Let me have a look.

It's on my to-do list to make a brief usage example. Currently, we have zero documentation, so I completely understand that you're struggling with the API.

For what it's worth, I envision something like the following high-level API will work for most users:

from typing import Dict

from cyto.app import App, Settings


class MyTunesSettings(Settings):
    theme: str
    volume: int = 80
    shuffle: bool = True
    translations: Dict[str, str] = {
        "repeat": "repetir",
        "shuffle": "barajar",
    }


async def main(settings: MyTunesSettings) -> None:
    """Run the MyTunes app."""
    # Do something with the settings
    print(settings)

App.launch(main)

If you call it like ./_my_tunes.py --theme dark, you get the following output:

debug=False background=True data_directory=PosixPath('/var/appster') theme='dark' volume=80 shuffle=True translations={'repeat': 'repetir', 'shuffle': 'barajar'}

Of course, there is also a low-level API that gives you more control (and doesn't force you to use cyto.app.App). I'll write that up in the documentation. Hopefully, I'll get some time to work in it this weekend. :)

I hope that helps you. I'll leave this issue open until we have proper documentation for cyto. 👍

~Frederik

@NickCrews
Copy link

Documentation would be great. I took a look at https://github.com/mpkocher/pydantic-cli and got scared off by HOW MUCH documentation there was (if the readme needs to be that long to explain how it works, it must be too complicated :) ), and I like how succint and clean this codebase looks, but just a few examples would be great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants