A port of Go's flag package to Python
Project description
go-flag
go-flag is a port of Go's flag package to Python.
Why??
Typically, click or argparse are going to be more straightforward than using this library. But there are a few motivations for using go-flag:
- You want to write a tool in Python, which behaves like a Go program. If you are using it alongside other programs that use Go-style flags, it can make your tool feel more at home in that ecosystem.
- You're a Gopher, and want to write some Python. In that case, this library may feel more comfortable.
- You are porting a Go program. This library can help minimize the amount of effort involved in translating idioms.
Also, I think this is funny.
Usage
The simplest usage of this library involves defining some flags and running a parse:
#!/usr/bin/env python
import flag
force = flag.bool_("force", False, "force the command to execute")
count = flag.int_("count", 1, "a count")
name = flag.string("name", "Josh", "a name")
threshold = flag.float_("threshold", 1.0, "a threshold")
flag.parse()
print(dict(
force=force.deref(),
count=count.deref(),
name=name.deref(),
threshold=threshold.deref()
))
With no arguments, this will print:
$ python examples/simple.py
{'force': False, 'count': 1, 'name': 'Josh', 'threshold': 1.0}
With a number of argument, we see:
$ python examples/simple.py -count 3 -force=true -name KB -threshold 0.5
{'force': True, 'count': 3, 'name': 'KB', 'threshold': 0.5}
With the help flag, this will print:
$ python examples/simple.py -h
Usage of examples/simple.py:
-count int
a count (default 1)
-force
force the command to execute
-name string
a name (default Josh)
-threshold float
a threshold (default 1)
In this usage, these flags are instances of flag.Ptr
. But you may want to
be a little more fancy - for instance, using a class and flag.AttrRef
:
#!/usr/bin/env python
import flag
class Config:
force: bool = flag.zero.bool_
count: int = flag.zero.int_
name: str = flag.zero.string
threshold: float = flag.zero.float_
force = flag.AttrRef(Config, "force")
count = flag.AttrRef(Config, "count")
name = flag.AttrRef(Config, "name")
threshold = flag.AttrRef(Config, "threshold")
flag.bool_var(force, "force", False, "force the command to execute")
flag.int_var(count, "count", 1, "a count")
flag.string_var(name, "name", "Josh", "a name")
flag.float_var(threshold, "threshold", 1.0, "a threshold")
flag.parse()
print(
dict(
force=Config.force,
count=Config.count,
name=Config.name,
threshold=Config.threshold,
)
)
This outputs:
$ python examples/class.py -count 3 -force=true -name KB -threshold 0.5
{'force': True, 'count': 3, 'name': 'KB', 'threshold': 0.5}
The flag.KeyRef
class can implement a similar pattern with dicts.
In general, aside from the need to use classes that fake pointers and a number of data types not applicable to Python, the API should follow the same general shape as Go's flag package. For more documentation, read the source - the docstrings should be relatively complete.
Error Handling
We already saw one strange set of abstractions we needed to pretend to be
Go - the Pointer
protocol and its implementations. The other way in which
this library emulates Go is in its error handling.
Not to worry - this library raises Exceptions like God intended. But it does
have two non-overlapping classes of errors: flag.Error
and flag.Panic
. The
former emulates cases where Go would have us return an error
. The latter is
raised when emulating a Go panic.
While the internal details of how Error
s are created are unusual, the end
result is very simple error classes. In general, you can except on flag.Error
and allow raised instances of flag.Panic
to crash the program. But if you
wish to have more fine-grained control, you may with to except flag.Panic
as
well.
Development
I developed this project using uv. It is a little immature, and I honestly can't recommend it yet for production use. We will see if I stick with this stack over time.
Nevertheless, the justfile
should contain most of what you need - including
just format
, just lint
, just check
, and just test
. Note that type
checking requires node.js, because I use pyright.
License
I licensed this under a BSD-3 license, in an attempt to stay compatible with Go's license.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file go_flag-2.0.1.tar.gz
.
File metadata
- Download URL: go_flag-2.0.1.tar.gz
- Upload date:
- Size: 22.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.5.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f829fc72785ac1f93573c10953a29926b5106a0ac73239b0177f4917891881b4 |
|
MD5 | 9ad09579baa200f48c98d2bfef914f84 |
|
BLAKE2b-256 | 58fe177da4854866e2eaa635d38b666041e4e53be1492c5930295dc63873dd3f |
File details
Details for the file go_flag-2.0.1-py3-none-any.whl
.
File metadata
- Download URL: go_flag-2.0.1-py3-none-any.whl
- Upload date:
- Size: 19.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.5.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | cea4d6618775cb10da1beb08dc4a6822cdfca122b0d980aadd10405eb3573472 |
|
MD5 | d7ed19a7b78a84be11c68ed1fcd8ff07 |
|
BLAKE2b-256 | f4532e2a4bca6665bc4c5f5d9eec5e32ebeb8ee4a39fb98112e4263ea3049b15 |