Skip to main content

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:

  1. 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.
  2. You're a Gopher, and want to write some Python. In that case, this library may feel more comfortable.
  3. 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, "bool value")
flag.int_var(count, "count", 1, "int value")
flag.string_var(name, "name", "Josh", "string value")
flag.float_var(threshold, "threshold", 1.0, "float value")

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 Errors 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

go_flag-1.0.1.tar.gz (21.2 kB view details)

Uploaded Source

Built Distribution

go_flag-1.0.1-py3-none-any.whl (18.8 kB view details)

Uploaded Python 3

File details

Details for the file go_flag-1.0.1.tar.gz.

File metadata

  • Download URL: go_flag-1.0.1.tar.gz
  • Upload date:
  • Size: 21.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.2

File hashes

Hashes for go_flag-1.0.1.tar.gz
Algorithm Hash digest
SHA256 9aefd9e3ba3d19b9067b53429b644c95ebfa975684adc3657c96c6f794c8a623
MD5 09604be8bb1c9cb4e070d244cc8b0b2f
BLAKE2b-256 c1b8539cfb19449f90d1e1abd9a032930f8521ae37f48ca1e43f32fc7b5a02fc

See more details on using hashes here.

File details

Details for the file go_flag-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: go_flag-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 18.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.2

File hashes

Hashes for go_flag-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 da8b8eee6db546f07ca647349f2db4c6208c0a2400525f21309ab180cfffd450
MD5 d461fd04114855cf07cef5f90d92803e
BLAKE2b-256 5d0325ffcf6f96a6e9bf72dab58c4ba041ee4333fbc40e27e9919a3633f0e0e7

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page