Skip to content

Commit

Permalink
Add Python library (#3)
Browse files Browse the repository at this point in the history
* feat: Add minimal Python library

* doc: Fix README Python comments

* feat: Add skeleton pyproject.toml / poetry.lock

* test: Add Python README test

* feat: Add CI for Python

* docs: Update README

* chore: Add --dev deps for black, flake8, and isort

* chore: Lint / format Python code
  • Loading branch information
scizzorz authored Jan 11, 2023
1 parent 8935c2d commit 83011ba
Show file tree
Hide file tree
Showing 9 changed files with 507 additions and 1 deletion.
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ jobs:
- uses: actions/checkout@v3

- run: bin/cargo test --all-features --all-targets --locked

python:
name: Test (Python)
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest
- name: Test
run: |
pytest
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/.hermit

/target
__pycache__
*.pyc
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ exit(Code::Forbidden);
exit(Code::Unavailable);
```

#### Python

```python
import exit

exit.Code.Forbidden.exit()
exit.Code.Unavailable.exit()
```

See [the complete list of exit codes](#the-codes).

### About
Expand Down
2 changes: 1 addition & 1 deletion exit.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const (
// Exit Codes 80-99 are reserved for user errors.
const (
// UsageError indicates that the program exited unsuccessfully
// because it was was used incorrectly.
// because it was used incorrectly.
//
// Examples: a required argument was omitted or an invalid value
// was supplied for a flag.
Expand Down
119 changes: 119 additions & 0 deletions exit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
"""
Defines semantic exit codes which may be used by Command Line tools to aid in
debugging and instrumentation.
This package defines exit codes in two ranges. Exit Codes 80-99 indicate a user error
of some sort. Exit Codes 100-119 indicate software or system error of some sort.
"""

import sys
from enum import Enum


# Code is the exit code that is passed to the system call `exit` when the
# program terminates. Conventionally, the value zero indicates success and all
# other values (1-255) indicate failure.
class Code(Enum):
# there doesn't really appear to be any convention about letter casing
# here, so I'm adopting the Go format

# Indicates that the program exited successfully.
OK = 0

# Indicates that the program exited unsuccessfully but gives no extra
# context as to what the failure was.
NotOK = 1

# Exit Codes 80-99 are reserved for user errors.

# Indicates that the program exited unsuccessfully because it was used
# incorrectly.
#
# Examples: a required argument was omitted or an invalid value was
# supplied for a flag.
UsageError = 80

# Indicates that the program exited unsuccessfully because an unrecognized
# subcommand was invoked.
#
# This is intended for CLI multi-tools. When you run a command that doesn't
# exist from the shell, the shell exits 127. This is distinct from that
# value in that the command itself exists but the subcommand does not (e.g.
# `git nope` could exit 81).
UnknownSubcommand = 81

# Indicates that the program exited unsuccessfully because a precondition
# wasn't satisfied.
#
# Examples: the user must be on a VPN before using the program or have
# a minimum version of some other software installed.
RequirementNotMet = 82

# Indicates that the program exited unsuccessfully because the user isn't
# authorized to perform the requested action.
Forbidden = 83

# Indicates that the program exited unsuccessfully because it has been
# migrated to a new location.
MovedPermanently = 84

# Exit Codes 100-119 are reserved for software or system errors.

# Indicates that the program exited unsuccessfully because of a problem in
# its own code.
#
# Used instead of 1 when the problem is known to be with the program's
# code or dependencies.
InternalError = 100

# Indicates that the program exited unsuccessfully because a service it
# depends on was not available.
#
# Examples: A local daemon or remote service did not respond, a connection
# was closed unexpectedly, an HTTP service responded with 503.
Unavailable = 101

def is_ok(self):
"""Reports whether an exit code is okay.
Returns True if the code is 0.
"""

return self.value == 0

def is_error(self):
"""Reports whether an exit code is an error.
Returns True if the code is *not* 0.
"""

return self.value != 0

def is_user_error(self):
"""Reports whether an exit code is a user error.
Returns True if the code is in the range 80-99 and False otherwise.
"""

return 80 <= self.value <= 99

def is_software_error(self):
"""Reports whether an exit code is a software error.
Returns True if the code is in the range 100-119 and False otherwise.
"""

return 100 <= self.value <= 119

def is_signal(self):
"""Reports whether an exit code is derived from a signal.
Returns True if the code is in the range 128-255 and False if not.
"""

return 128 < self.value < 255

def exit(self):
"""Invoke sys.exit() with this as an exit code."""

sys.exit(self.value)
Loading

0 comments on commit 83011ba

Please sign in to comment.