Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 42 additions & 12 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ name: Python package

on:
push:
branches: [ "master", "dev", "gha" ]
branches:
- master
- dev
- gha
- boilerplate
pull_request:
branches: [ "master", "dev", "gha" ]
branches:
- master
- dev
- gha
- boilerplate

jobs:
build:
Expand All @@ -17,34 +25,56 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.13"
- "3.12"
- "3.11"
- "3.10"
- "3.9"
- "3.8"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"

steps:
- uses: actions/checkout@v4

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

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

- name: Install package
run: |
python -m pip install -e .
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with unittest
run: |
python tests/run_unittest.py
- name: Test with pytest
run: |
pytest

build-py27:

runs-on: ubuntu-latest
container:
image: python:2.7-slim
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
python -m pip install --upgrade "pip<21" setuptools mock
- name: Compile library modules
run: |
python -m compileall py2be
- name: Test with unittest
run: |
python3 -m unittest discover tests
python tests/run_unittest.py
env:
PYTHONPATH: ${{ github.workspace }}
17 changes: 15 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@

# directories (by name)

build/
dist/
/.bin/
/.venv/

/_build/
/build/
/dist-old/
/dist/
/scratch/

*.egg-info/


# directories (by pattern)


# files (by name)

.DS_Store

notes.txt


# files (by pattern)

*~
Expand All @@ -19,4 +31,5 @@ dist/
*.swo
*.swp
*.tmp
*.zip

21 changes: 21 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
# **py2be** Changes


## 0.0.4 - 2nd July 2026

* added top-level `__all__` documenting the public API;
* removed `tests` and `examples` from installable packages;
* added `python_requires` for Python 2.7 and Python 3.8+;
* added **MANIFEST.in**;
* aligned **build_dist.sh** with **build_dist_uv.sh** (system Python);
* added **build_dist_uv.sh** (build + `twine check`);
* added **tests/test_package.py**;
* added **tests/run_unittest.py** and Python 2.7 compatibility shims in **tests/__init__.py**;
* expanded unit tests (`str2bool`, whitespace-padded stock terms);
* extended GitHub Actions workflow (Python 2.7 job, Python 3.14, pytest);
* fix project URL;
* README polish (installation, Python version compatibility, Components/API reference, CI badges, examples, URL(s));
* fixed pytest import failure (removed repo-root `__init__.py`; `pip install -e .` in CI; **pytest.ini**);
* README: explicit Python 2.7 compatibility claim; documented `unicode` / `bytes` input policy;
* added **examples/truthy_strings.py** and **EXAMPLES.md**;
* added `Programming Language :: Python :: 3.14` classifier;
* added **tests/test_bytes_rejection.py** (bytes / `bytearray` not classified on Python 3; Py2.7 text inputs);


## 0.0.3 - 1st September 2025

* GitHub Actions;
Expand Down
8 changes: 8 additions & 0 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# py2be Examples

| Name | Source | Summary |
| ---- | ------ | ------- |
| **truthy_strings** | [examples/truthy_strings.py](./examples/truthy_strings.py) | Classify stock and padded strings with `str2bool()`, `string_is_falsey()`, `string_is_truey()`, and `string_is_truthy()` |


<!-- ########################### end of file ########################### -->
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
py2be - BSD 3-Clause License

Copyright (c) 2025, Matthew Wilson and Synesis Information Systems
Copyright (c) 2025-2026, Matthew Wilson and Synesis Information Systems
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include LICENSE README.md CHANGES.md EXAMPLES.md TODO.md
recursive-include examples *.py
recursive-include tests *.py
146 changes: 122 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,117 @@

![Language](https://img.shields.io/badge/Python-3776AB?style=flat&logo=python&logoColor=white)
[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
[![PyPI version](https://badge.fury.io/py/py2be.svg)](https://badge.fury.io/py/py2be)
[![GitHub release](https://img.shields.io/github/v/release/synesissoftware/py2be.svg)](https://github.com/synesissoftware/py2be/releases/latest)
![Python](https://img.shields.io/badge/Python-2.7%20%7C%203.8+-lightgrey)
[![CI](https://github.com/synesissoftware/py2be/actions/workflows/python-package.yml/badge.svg)](https://github.com/synesissoftware/py2be/actions/workflows/python-package.yml)
[![Last Commit](https://img.shields.io/github/last-commit/synesissoftware/py2be)](https://github.com/synesissoftware/py2be/commits/master)
[![PyPI version](https://badge.fury.io/py/py2be.svg)](https://badge.fury.io/py/py2be)

Simple Python library determining whether strings indicate truey or falsy values.
Simple Python library determining whether strings indicate *truey* or *falsey* values.


## Table of Contents <!-- omit in toc -->

- [Introduction](#introduction)
- [Installation \& usage](#installation--usage)
- [Python version compatibility](#python-version-compatibility)
- [Text string inputs (`unicode` / `bytes`)](#text-string-inputs-unicode--bytes)
- [Terminology](#terminology)
- [Components](#components)
- [Functions](#functions)
- [Examples](#examples)
- [Project Information](#project-information)
- [Where to get help](#where-to-get-help)
- [Contribution guidelines](#contribution-guidelines)
- [Dependencies](#dependencies)
- [Dev Dependencies](#dev-dependencies)
- [Related projects](#related-projects)
- [License](#license)


## Introduction

**to-be** is a library providing facilities for determine whether the truthyness of strings. It implemented in several languages: **py2be** is the **Python** implementation.
**to-be** is a library providing facilities for determining whether the truthyness of strings. It is implemented in several languages: **py2be** is the **Python** implementation.

**py2be** explicitly supports **Python 2.7** — not other Python 2.x releases — and **Python 3.8+**. This is enforced at install time via `python_requires` in **setup.py** and exercised in GitHub Actions on **Python 2.7** and **Python 3.8–3.14**.

## Table of Contents <!-- omit in toc -->

## Installation & usage

Install via **pip** or **pip3**, as in:

```
$ pip3 install py2be
```

Use via **import**:

```Python
import py2be
```

or import the functions you need:

```Python
from py2be import (
str2bool,
string_is_falsey,
string_is_truey,
string_is_truthy,
)
```

- [Introduction](#introduction)
- [Terminology](#terminology)
- [Project Information](#project-information)
- [Where to get help](#where-to-get-help)
- [Contribution guidelines](#contribution-guidelines)
- [Dependencies](#dependencies)
- [Dev Dependencies](#dev-dependencies)
- [Related projects](#related-projects)
- [License](#license)

### Python version compatibility

**py2be** is intended to run on **Python 2.7** and **Python 3.8+** only. Versions in the Python 3.0–3.7 range are excluded by `python_requires`.

| Python version | Support |
| -------------- | ------- |
| **2.7** | Supported (the only Python 2 release supported) |
| **3.0 – 3.7** | Not supported |
| **3.8+** | Supported |

| Requirement | Applies to |
| ----------- | ---------- |
| Python **2.7** or **3.8+** | All public APIs (`str2bool`, `string_is_falsey`, `string_is_truey`, `string_is_truthy`) |

The public API surface is listed in `py2be.__all__`.


### Text string inputs (`unicode` / `bytes`)

All public functions take a single string argument `s`. The library classifies **text** only; binary buffers are not accepted.

| Input | Python 2.7 | Python 3.8+ |
| ----- | ------------ | ----------- |
| `unicode` / text `str` | Supported | Supported (`str`) |
| `str` (byte string) | Supported for ASCII stock terms (e.g. `"true"`, `"no"`) | N/A — `str` is text |
| `bytes`, `bytearray`, and other non-text types | Not supported — behaviour is undefined; decode to text first | Not supported — behaviour is undefined; decode to text first |
| `None` | `str2bool(None)` returns `None`; the boolean predicates return `False` | Same |

On **Python 3**, passing `bytes` (for example `b"true"`) will not match stock terms and is not a supported use case. Decode explicitly before calling, for example `s.decode("utf-8")` or `s.decode("ascii")`.

On **Python 2.7**, prefer `unicode` literals (e.g. `u"true"`) for non-ASCII configuration values. ASCII `str` literals work for the stock vocabulary because they match the internal comparison tables directly.

Trimming uses `str.strip()` / `unicode.strip()`; only leading and trailing whitespace is removed before lower-case matching.


## Terminology

The term "*truthy*" is an unhelpfully overloaded term in the programming world, insofar as it is used to refer to the notion of "truthyness" - whether something can be _deemed to be_ interpretable as truth - and also the true side of that interpretation. In this library, the former interpretation is used, leaving us with the following terms:

* "*truthy*" - whether something can be can be _deemed to be_ interpretable as having truth;
* "*truthy*" - whether something can be _deemed to be_ interpretable as having truth (and, thus, will be *falsey* or *truey*);
* "*falsey*" - whether an object can be _deemed to be_ interpretable as being false;
* "*truey*" - whether an object can be _deemed to be_ interpretable as being true;

For example, consider the following **Python** program:

```Python
from py2be import (
string_is_falsey,
string_is_truey,
string_is_truthy,
string_is_falsey,
string_is_truey,
string_is_truthy,
)

s1 = "no"
Expand All @@ -51,18 +121,47 @@ s3 = "orange"

# "no" is validly truthy, and is falsey
assert string_is_falsey(s1)
assert !string_is_truey(s1)
assert not string_is_truey(s1)
assert string_is_truthy(s1)

# "True" is validly truthy, and is truey
assert !string_is_falsey(s2)
assert not string_is_falsey(s2)
assert string_is_truey(s2)
assert string_is_truthy(s2)

# "orange" is not validly truthy, and is neither falsey nor truey
assert !string_is_falsey(s3)
assert !string_is_truey(s3)
assert !string_is_truthy(s3)
assert not string_is_falsey(s3)
assert not string_is_truey(s3)
assert not string_is_truthy(s3)
```


## Components

### Functions

The following public functions are defined in the current version:

| Function | Purpose |
| -------- | ------- |
| `str2bool(s)` | Classifies `s` as unrecognised (`None`), falsey (`False`), or truey (`True`). |
| `string_is_falsey(s)` | Indicates that `s`, when trimmed, is classified as truthy and is deemed falsey. |
| `string_is_truey(s)` | Indicates that `s`, when trimmed, is classified as truthy and is deemed truey. |
| `string_is_truthy(s)` | Indicates that `s`, when trimmed, is classified as truthy (and is deemed either falsey or truey). |

**NOTE:** `string_is_falsey(x) == not string_is_truey(x)` is **not** guaranteed (for example, when `x` is not classified as truthy, both predicates return `False`).

Stock falsey terms (after optional trimming and case folding) include `0`, `false`, `no`, and `off`. Stock truey terms include `1`, `true`, `yes`, and `on`. Several common capitalisations and mixtures of case are recognised without lower-casing first.


## Examples

Examples are provided in the `examples` directory. A detailed list of them is provided in [EXAMPLES.md](./EXAMPLES.md).

To run the stock string classification example:

```
$ python examples/truthy_strings.py
```


Expand Down Expand Up @@ -90,7 +189,7 @@ Defect reports, feature requests, and pull requests are welcome on https://githu

### Related projects

* [**to-be**](https://github.com/synesissoftware/to-be) (**C**);
* [**2be**](https://github.com/synesissoftware/2be) (**C**);
* [**to_be.Ruby**](https://github.com/synesissoftware/to_be.Ruby);
* [**to-be.Rust**](https://github.com/synesissoftware/to-be.Rust);

Expand All @@ -101,4 +200,3 @@ Defect reports, feature requests, and pull requests are welcome on https://githu


<!-- ########################### end of file ########################### -->

14 changes: 14 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,24 @@

## Table of Contents <!-- omit in toc -->

- [Project improvements](#project-improvements)
- [Functional improvements](#functional-improvements)
- [Performance improvements](#performance-improvements)


## Project improvements

* [x] **build_dist.sh** and **build_dist_uv.sh** (build + `twine check`);
* [x] **MANIFEST.in**;
* [x] `python_requires` (Python 2.7 and Python 3.8+);
* [x] Python 2.7 test infrastructure (`tests/__init__.py`, `tests/run_unittest.py`, `tests/test_package.py`);
* [x] expanded unit tests and GitHub Actions (Python 2.7, pytest, Python 3.14);
* [x] README polish (installation, compatibility table, API reference);
* [x] README: explicit Python 2.7 claim; `unicode` / `bytes` policy;
* [x] **EXAMPLES.md** and **examples/truthy_strings.py**;
* [x] **tests/test_bytes_rejection.py** (documented `unicode` / `bytes` policy);


## Functional improvements

* \<none>
Expand Down
Loading
Loading