File: GETTING_STARTED.md

package info (click to toggle)
python-nubia 0.2.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 772 kB
  • sloc: python: 4,182; makefile: 9; sh: 1
file content (140 lines) | stat: -rw-r--r-- 4,791 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# Getting Started

## Basic concepts
The building blocks of a simple Nubia-based application are three pieces:

* [Nubia plugin](###Plugin)
* Application [context](###Context)
* [Commands](###Commands) and their [arguments](###Arguments)


### Plugin
A Nubia plugin is an object that implements `nubia.PluginInterface`.
It gives you the ability to configure the behaviour of different aspects of your program.
Take a look into `example/nubia_plugin.py` to see an example of a very simple Nubia plugin.
The table below gives a short overiew of `nubia.PluginInterface`' most important methods.

| Method | Responsibility |
| --- | --- |
| `get_commands` | Provides the list of commands exposed via Nubia |
| `get_opts_parser` | Provides the top-level argument parser that handles common arguments |
| `create_context` | Provides a context object |
| `get_status_bar` | Provides a status bar |
| `get_prompt_tokens` | Provides prompt tokens for interactive prompt |

### Context
A _context_ is an object that extends `nubia.Context` class.
It’s a singleton object that holds state and configuration for your program and can be easily accessed from your code.

```python
from nubia import context

ctx = context.get_context()
```

The context should be the only place you store your shared state and configuration into.
For more details about context and how to use it, please read context documentation. <TODO context>

### Commands
Any Python function can be exposed as a Nubia command by applying `@command` decorator on top of it.

``` python
from nubia import command

@command
def foo_bar() -> int:  # becomes a `foo-bar` command
    return 42
```

By default, Nubia automatically generates a command name from the corresponding function name.
Nubia translates both `snake_case` or `CamelCase` names into `kebab-case` names (see the examples below).
However, it's possible to override this behaviour by explicitly supplying the command name.
<TODO aliases>

``` python
from nubia import command

@command("moo")
def foo_bar() -> int:  # becomes a `moo` command
    return 42
```


#### Subcommands
When building complex CLI interfaces (e.g. similar to `git`), one may need to group the commands according to their purpose.

Nubia supports this by allowing Python classes to act as super commands.
Applying the `@command` decorator to the class itself indicates that:

* It denotes a super command
* Its public instance methods are automatically treated as subcommands

``` python
from nubia import command

@command
class Daemon:
    """
    This is a set of commands that run daemons
    """
    @command
    def start(self) -> None:  # becomes a `daemon start` subcommand
        "Help message of start"
        # Starting the daemon
        ...

    @command
    def stop(self) -> None:  # becomes a `daemon stop` subcommand
        "Help message of stop"
        # Stopping the daemon
        ...
```

Furthermore, the `__init__` arguments are options that will be available for
both sub-commands, each sub-command can have its own additional options by
defining these are arguments to their respective functions.

### Arguments
Function (or method) arguments are converted into command options automatically.
You can use the `@argument` decorator to add more metadata to the generated
command option if you like. But before we get to that, let's talk about some
rules first:
- Function arguments that have default values are _optional_. If the command is
executed without supplying a value, you will receive this default value as
defined in the function signature.
- Function arguments that do not have default values are required.
- All arguments are _options_ by default, this means that you need to pass
`--argument-name` when running the command (in CLI mode). If you would like to
have the argument supplied as a positional value, you need to set
`positional=True` in the `@argument` decorator as indicated in this example
- `description` parameter of `@argument` decorator is mandatory.

```python
import typing

@command
@argument("hostnames", description="Hostname for the server you want to start",
    positional=True)
def start_server(hostnames: typing.List[str]):
    """
    Starts a server or more
    """
    pass
```

Since `hostnames` is defined as a `typing.List`, we expect the user to pass
multiple values. A single value will automatically be lifted into a list of
a single value `(x -> [x])`. Lists in CLI mode are space-separated values

```
my-program start-server server.com server2.com
```

In interactive, you can do any of the following:

```
my-program start-server server1.com
my-program start-server [server1.com, server2.com]
my-program start-server ["server1.com", "server2.com"]
my-program start-server hostnames=["server1.com", "server2.com"]
```