diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..762ee86 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,44 @@ +root = true + +# Language indent/EOL/charset overlap with .vscode/settings.json. +# Rulers, renderWhitespace, detectIndentation, mergeEditor, and +# language-server settings cannot be expressed here — they stay in +# settings.json. + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +# [json] +[*.json] +indent_size = 2 +indent_style = space + +# [markdown] +[*.md] +indent_size = 2 +indent_style = space + +# [python] +[*.py] +indent_size = 4 +indent_style = space + +# [shellscript] +[*.{bash,sh,zsh}] +indent_size = 2 +indent_style = space + +# [toml] +[*.toml] +indent_size = 2 +indent_style = tab + +# [yaml] +[*.{yaml,yml}] +indent_size = 2 +indent_style = space diff --git a/.gitattributes b/.gitattributes index bd35ebe..990aa80 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,9 @@ - -*.py linguist-language=Python - +*.c linguist-language=C +*.cpp linguist-language=C++ +*.h linguist-language=C +*.hpp linguist-language=C++ *.html linguist-detectable=false +*.py linguist-language=Python *.sh linguist-detectable=false *.vimrc linguist-detectable=false +makefile linguist-detectable=false diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 0f6439f..bc80c84 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -1,5 +1,9 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python +# This workflow will install Python dependencies, run tests, and smoke +# the sdist/wheel on a range of Python versions. +# +# Created: 14th September 2026 +# Updated: 14th September 2026 +# name: Python package @@ -8,16 +12,43 @@ on: branches: - master - dev - - gha - boilerplate + - idiomatic + - rc1 + - rc2 + - rc3 pull_request: - branches: - - master - - dev - - gha - - boilerplate + +permissions: + contents: read + +defaults: + run: + shell: bash jobs: + lint: + name: Lint (ruff) + runs-on: ubuntu-latest + + steps: + - name: Checking out code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.14" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install ruff + + - name: Lint with ruff + run: | + ruff check . + build: runs-on: ubuntu-latest @@ -34,32 +65,31 @@ jobs: - "3.14" steps: - - uses: actions/checkout@v4 + - name: Checking out code + uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 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 pytest 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 + - name: Build and install smoke + run: | + python -m pip install build + python -m build + python -m pip install dist/py2be-*.whl + python -c "import py2be; assert py2be.__version__ == '0.1.1'; print(py2be.__version__)" + build-py27: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 07871f2..75d68ed 100644 --- a/.gitignore +++ b/.gitignore @@ -2,19 +2,22 @@ # directories (by name) /.bin/ +/.pytest_cache/ +/.ruff_cache/ /.venv/ -/_build/ -/build/ -/dist-old/ -/dist/ -/scratch/ +build/ +dist/ +dist-old/ +scratch/ *.egg-info/ # directories (by pattern) +**/__pycache__/ + # files (by name) @@ -32,4 +35,3 @@ notes.txt *.swp *.tmp *.zip - diff --git a/.sis/project_name.txt b/.sis/project_name.txt new file mode 100644 index 0000000..edd077e --- /dev/null +++ b/.sis/project_name.txt @@ -0,0 +1 @@ +py2be diff --git a/.sis/script_info_lines.txt b/.sis/script_info_lines.txt new file mode 100644 index 0000000..4afff7a --- /dev/null +++ b/.sis/script_info_lines.txt @@ -0,0 +1,2 @@ +py2be is a simple Python library determining whether strings indicate truey or falsey values +Copyright (c) 2025-2026, Matthew Wilson and Synesis Information Systems diff --git a/.vimrc b/.vimrc index d2759e2..d07167a 100644 --- a/.vimrc +++ b/.vimrc @@ -1,7 +1,57 @@ +" Synesis Python project .vimrc — aligned with .vscode/settings.json (Python) +set nocompatible +filetype indent plugin on +syntax enable +set autoindent +set backspace=indent,eol,start +set hlsearch +set incsearch +set number + +" files.insertFinalNewline +set eol +set fixeol + +" editor.renderWhitespace: all +set list +set listchars=tab:->,trail:-,extends:>,precedes:<,nbsp:+ + +" editor.detectIndentation: false — global defaults match [python] (editor.tabSize: 4, insertSpaces: true) +set colorcolumn=76 set expandtab set shiftwidth=4 set softtabstop=4 set tabstop=4 -set tw=0 +" colorcolumn draws a full-column tint in Vim (not a VS Code-style 1px line). +" Keep it subtle via the ColorColumn highlight group; reapply after colorscheme changes. +if has('termguicolors') + " set termguicolors +endif + +function! s:ConfigureColorColumn() abort + highlight ColorColumn ctermbg=236 guibg=#2a2a2a cterm=NONE gui=NONE +endfunction + +call s:ConfigureColorColumn() +autocmd ColorScheme * call s:ConfigureColorColumn() + +" files.trimTrailingWhitespace +autocmd BufWritePre * %s/\s\+$//e + +augroup sis_python + autocmd! + + " [json] / [markdown] / [yaml] + autocmd FileType json,markdown,yaml setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 + + " [python] — match .vscode [python] tabSize 4 / insertSpaces true / rulers 50,60,76,120 + autocmd FileType python setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=50,60,76,120 + + " [shellscript] + autocmd FileType sh,bash,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 + + " [toml] + autocmd FileType toml setlocal noexpandtab tabstop=2 shiftwidth=2 softtabstop=2 +augroup END diff --git a/.vscode/settings.json b/.vscode/settings.json index 1bda13d..95b7da0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,45 +2,42 @@ "[json]": { "editor.tabSize": 2, }, + "[markdown]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, "[python]": { + "diffEditor.ignoreTrimWhitespace": false, "editor.insertSpaces": true, - "editor.rulers": [ 60, 76 ], + "editor.rulers": [ 50, 60, 76, 120 ], "editor.tabSize": 4, }, - "[ruby]": { + "[shellscript]": { "editor.insertSpaces": true, "editor.rulers": [ 60, 76 ], "editor.tabSize": 2, }, - "[rust]": { - "editor.insertSpaces": true, - "editor.rulers": [ 60, 76 ], - "editor.tabSize": 4, - }, "[toml]": { "editor.insertSpaces": false, "editor.tabSize": 2, }, - "cmake.configureOnOpen": false, + "[yaml]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, "editor.detectIndentation": false, "editor.insertSpaces": false, "editor.renderWhitespace": "all", "editor.rulers": [ 76 ], "editor.tabSize": 2, + "files.exclude": { + "**/*.egg-info": true, + "**/*.swp": true, + "**/__pycache__": true, + }, "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true, "git.mergeEditor": false, - "rust-analyzer.cargo.noDefaultFeatures": true, - "rust-analyzer.cargo.features": [ - // "implement-Truthy-for-AsStr", - "implement-Truthy-for-bool", - "implement-Truthy-for-CsStr", - "implement-Truthy-for-CsString", - "implement-Truthy-for-OsStr", - "implement-Truthy-for-OsString", - "implement-Truthy-for-str", - "implement-Truthy-for-String", - ], - "rust-analyzer.completion.autoimport.enable": false, - "rust-analyzer.showUnlinkedFileNotification": false, + "python.analysis.typeCheckingMode": "standard", + "python.languageServer": "Pylance", } diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..c12139b --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,21 @@ +# py2be - Authors + + +## Major Contributors + +| Name | GitHub | +| ----------- | --------------------------------- | +| Matt Wilson | [mwsis](https://github.com/mwsis) | + + +## Defect reports, fixes and suggestions (for which we are very grateful) + +| Name | GitHub | +| ------- | ------ | +| \ | | + + +Contributions are welcomed. + + + diff --git a/CHANGES.md b/CHANGES.md index 119e96f..20a9900 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,11 @@ # py2be - Changes +## 0.1.1 - 14th September 2026 + +* packaging, documentation, and CI modernisation (PEP 621 hybrid, canonical CI, **ruff**, helper scripts); + + ## 0.1.0 - 2nd July 2026 * modularised implementation (`constants`, `parse`, `truthy`); diff --git a/MANIFEST.in b/MANIFEST.in index 463f7fb..3ab2c47 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include LICENSE README.md CHANGES.md EXAMPLES.md TODO.md +include AUTHORS.md CHANGES.md EXAMPLES.md LICENSE NEWS.md README.md TODO.md recursive-include benchmarks *.py recursive-include examples *.py recursive-include tests *.py diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..48fbfbd --- /dev/null +++ b/NEWS.md @@ -0,0 +1,13 @@ +# py2be - News + +| Date | News Item | Details | +| ------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- | +| 14th September 2026 | [**py2be** 0.1.1](https://github.com/synesissoftware/py2be/releases/tag/0.1.1) | Packaging / CI modernisation | +| 2nd July 2026 | [**py2be** 0.1.0](https://github.com/synesissoftware/py2be/releases/tag/0.1.0) | Modularised truthy parsing and benchmarks | +| 2nd July 2026 | [**py2be** 0.0.4](https://github.com/synesissoftware/py2be/releases/tag/0.0.4) | Packaging, public API, CI, examples | +| 1st September 2025 | [**py2be** 0.0.3](https://github.com/synesissoftware/py2be/releases/tag/0.0.3) | GitHub Actions, badges, `.gitattributes` | +| 11th August 2025 | [**py2be** 0.0.2](https://github.com/synesissoftware/py2be/releases/tag/0.0.2) | Name fixes | +| 11th August 2025 | [**py2be** 0.0.1](https://github.com/synesissoftware/py2be/releases/tag/0.0.1) | Initial version | + + + diff --git a/README.md b/README.md index b65d6a1..faef798 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # py2be +Simple Python library determining whether strings indicate *truey* or *falsey* values. + ![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) @@ -8,8 +10,6 @@ [![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) -Simple Python library determining whether strings indicate *truey* or *falsey* values. - ## Table of Contents @@ -26,7 +26,9 @@ Simple Python library determining whether strings indicate *truey* or *falsey* v - [Where to get help](#where-to-get-help) - [Contribution guidelines](#contribution-guidelines) - [Dependencies](#dependencies) - - [Dev Dependencies](#dev-dependencies) + - [Efferent (fan-out)](#efferent-fan-out) + - [Development Dependencies](#development-dependencies) + - [Afferent (fan-in)](#afferent-fan-in) - [Related projects](#related-projects) - [License](#license) @@ -201,12 +203,20 @@ Defect reports, feature requests, and pull requests are welcome on https://githu ### Dependencies -**py2be** has no (non-development) dependencies. + +#### Efferent (fan-out) + +None. + + +#### Development Dependencies + +None (currently). -#### Dev Dependencies +#### Afferent (fan-in) -**py2be** has no (additional) development dependencies. +None (currently). ### Related projects diff --git a/py2be/__init__.py b/py2be/__init__.py index db0bc6f..951766b 100644 --- a/py2be/__init__.py +++ b/py2be/__init__.py @@ -8,7 +8,7 @@ __license__ = 'BSD-3-Clause' __maintainer__ = 'Matt Wilson' __status__ = 'Beta' -__version__ = '0.1.0' +__version__ = '0.1.1' from .truthy import ( str2bool, diff --git a/py2be/internal/__init__.py b/py2be/internal/__init__.py index c2fd4c8..d3905d4 100644 --- a/py2be/internal/__init__.py +++ b/py2be/internal/__init__.py @@ -1,2 +1,2 @@ -from ..parse import _str2bool +from ..parse import _str2bool as _str2bool diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..bfb3602 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,79 @@ +[build-system] +build-backend = "setuptools.build_meta" +requires = [ + "setuptools>=61.0", +] + + +[project] +authors = [ + { email = "matthew@synesis.com.au", name = "Matt Wilson" }, +] +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] +dependencies = [ +] +description = "Simple Python library determining whether strings indicate truey or falsey values" +keywords = [ + "configuration", + "environment", + "string", + "traits", +] +license = { text = "BSD-3-Clause" } +name = "py2be" +readme = "README.md" +requires-python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*" +version = "0.1.1" + +[project.urls] +"Bug Tracker" = "https://github.com/synesissoftware/py2be/issues" +Changelog = "https://github.com/synesissoftware/py2be/blob/master/CHANGES.md" +Homepage = "https://github.com/synesissoftware/py2be" +Repository = "https://github.com/synesissoftware/py2be" + +[project.optional-dependencies] +dev = [ + "pytest", + "ruff>=0.4.0", +] + + +[tool.ruff] +line-length = 76 +target-version = "py38" + +[tool.ruff.lint] +ignore = [ + "E501", +] +select = [ + "E", + "F", +] + +[tool.setuptools.packages.find] +exclude = [ + "benchmarks*", + "examples*", + "tests*", +] +include = [ + "py2be", + "py2be.*", +] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e69de29..0000000 diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index 280a5fb..b13bc2c 100755 --- a/run_all_unit_tests.sh +++ b/run_all_unit_tests.sh @@ -7,9 +7,9 @@ # calling directory # # Created: 13th February 2019 -# Updated: 2nd April 2024 +# Updated: 14th September 2026 # -# Copyright (c) Matthew Wilson, 2019-2024 +# Copyright (c) Matthew Wilson, 2019-2026 # All rights reserved # # Redistribution and use in Source and binary forms, with or without @@ -52,12 +52,182 @@ while [ -h "$Source" ]; do [[ $Source != /* ]] && Source="$Dir/$Source" done Dir="$(cd -P "$( dirname "$Source" )" && pwd)" +Basename="$(basename "$Source")" + +ProjectNameFile="$Dir/.sis/project_name.txt" +if [ -f "$ProjectNameFile" ]; then + ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +else + ProjectName=$(basename "$Dir") +fi + + +AssumePython2= +IncludePython2InSearch= +PythonCommandPath= + + +# regular command-line handling + + +while [[ $# -gt 0 ]] +do + + case "$1" in + + --assume-python2) + + AssumePython2=1 + ;; + --include-python2-in-search) + + IncludePython2InSearch=1 + ;; + --python-cmd-path|-p) + + shift + + PythonCommandPath=$1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + echo + cat << EOF +USAGE: $Basename { | --help | [ --assume-python2 ] [ --include-python2-in-search ] [ --python-cmd-path | -p ] } + +${ProjectName} unit tests + +flags/options: + + --help + shows this help and terminates + + --assume-python2 + uses the python2 command when no -p / --python-cmd-path is given + + --include-python2-in-search + includes python2 in automatic interpreter discovery (after python3 and python) + + -p + --python-cmd-path + specifies explicitly the path of the Python command to be executed (rather than discover it) +EOF + + exit 0 + ;; + *) + + >&2 echo "unrecognised argument; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# validate / discover python executable path + +if [ "x_$PythonCommandPath" = "x_" ] && [ ! -z "$AssumePython2" ]; then + + PythonCommandPath=python2 +fi + +if [ "x_$PythonCommandPath" != "x_" ]; then + + # check the given command + + if ! { [ -x "$PythonCommandPath" ] || command -v "$PythonCommandPath" > /dev/null; }; then + + >&2 echo "given python-cmd-path '$PythonCommandPath' is not executable" + + exit 1 + fi +else + + # try and find a suitable command + + # Prefer a project-local venv when present (avoids Apple/Xcode python3 on + # PATH, which must not be used for local install/test). + if [ "x_$PythonCommandPath" = "x_" ]; then + + if [ -x "$Dir/.venv/bin/python" ]; then + + PythonCommandPath="$Dir/.venv/bin/python" + + echo "found project venv python '$PythonCommandPath'" + fi + fi + + if [ "x_$PythonCommandPath" = "x_" ]; then + + if [ "y_$PYTHON_COMMAND_PATH" != "y_" ]; then + + if command -v "$PYTHON_COMMAND_PATH" > /dev/null; then + + PythonCommandPath=$PYTHON_COMMAND_PATH + fi + fi + fi + + if [ "x_$PythonCommandPath" = "x_" ]; then + + if [ "y_$PYTHON_CMD_PATH" != "y_" ]; then + + if command -v "$PYTHON_CMD_PATH" > /dev/null; then + + PythonCommandPath=$PYTHON_CMD_PATH + fi + fi + fi + + if [ "x_$PythonCommandPath" = "x_" ]; then + + PossiblePythonCommands=(python3 python) + + if [ ! -z "$IncludePython2InSearch" ]; then + + PossiblePythonCommands+=(python2) + fi + + for p in "${PossiblePythonCommands[@]}" + do + + if command -v "$p" > /dev/null; then + + PythonCommandPath=$p + + echo "found valid python command '$p'" + + break + fi + done + fi + + if [ "x_$PythonCommandPath" = "x_" ]; then + + if [ -z "$IncludePython2InSearch" ] && [ -z "$AssumePython2" ] && command -v python2 > /dev/null; then + + >&2 echo "only python2 was found on PATH; pass --include-python2-in-search to allow it during discovery, or --assume-python2 to use python2 explicitly" + + exit 1 + fi + + >&2 echo "no valid python command path discovered" + + exit 1 + fi +fi + + +# executing tests # This will operate recursively as long as each subdirectory of $Dir/tests # contains an __init__.py file (which may be empty) -python3 "$Dir/tests/run_unittest.py" +"$PythonCommandPath" -m unittest discover -s "$Dir/tests" # ############################## end of file ############################# # - diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..2a9acf1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = 1 diff --git a/setup.py b/setup.py index 55efbb4..5c6384e 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ name='py2be', python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*', - version='0.1.0', + version='0.1.1', author='Matt Wilson', author_email='matthew@synesis.com.au', @@ -16,6 +16,7 @@ 'Natural Language :: English', "Operating System :: OS Independent", "Programming Language :: Python", + "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.8", @@ -37,4 +38,3 @@ ]), url='https://github.com/synesissoftware/py2be', ) -