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
7 changes: 3 additions & 4 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ jobs:
needs:
- quick-test
runs-on: ubuntu-latest
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- name: Checkout
# see https://github.com/actions/checkout
Expand All @@ -70,7 +72,4 @@ jobs:
run: python -m build
- name: Publish package
# see https://github.com/pypa/gh-action-pypi-publish
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 # v1.4.2
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

All notable changes to this project will be documented in this file.

## Unreleased

<!-- unreleased things below this line -->

## v1.1.0 - 2025-07-18

Original release: <https://github.com/willynilly/rfc3987-syntax/releases/tag/v1.1.0>

* Features
* Added add support for IRI-reference and absolute-IRI
* Bugs
* Fixed single quote sub-delimiter

## v1.0.0 - 2025-05-18

Original release: <https://github.com/willynilly/rfc3987-syntax/releases/tag/v1.0.0>
71 changes: 0 additions & 71 deletions CITATION.cff

This file was deleted.

1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
MIT License

Copyright (c) 2025 Will Riley
Copyright (c) 2026 Jan Kowalleck — modifications and maintenance.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# rfc3987-syntax
# rfc3987-syntax2

Helper functions to parse and validate the **syntax** of terms defined in **[RFC 3987](https://www.rfc-editor.org/info/rfc3987)** — the IETF standard for Internationalized Resource Identifiers (IRIs).

> [!NOTE]
> This is a maintained fork of <https://github.com/willynilly/rfc3987-syntax>.

## 🎯 Purpose

The goal of `rfc3987-syntax` is to provide a **lightweight, permissively licensed Python module** for validating that strings conform to the **ABNF grammar defined in RFC 3987**. These helpers are:
The goal of `rfc3987-syntax2` is to provide a **lightweight, permissively licensed Python module** for validating that strings conform to the **ABNF grammar defined in RFC 3987**. These helpers are:

- ✅ Strictly aligned with the **syntax rules of RFC 3987**
- ✅ Built using a **permissive MIT license**
Expand All @@ -17,7 +19,7 @@ The goal of `rfc3987-syntax` is to provide a **lightweight, permissively license

## 📄 License, Attribution, and Citation

**`rfc3987-syntax`** is licensed under the [MIT License](LICENSE), which allows reuse in both open source and commercial software.
**`rfc3987-syntax2`** is licensed under the [MIT License](LICENSE), which allows reuse in both open source and commercial software.

This project:

Expand Down Expand Up @@ -46,15 +48,15 @@ ChatGPT 40 was used during the original development process. Errors may exist du
## 📦 Installation

```bash
pip install rfc3987-syntax
pip install rfc3987-syntax2
```

## 🛠 Usage

### List all supported "terms" (i.e., non-terminals and terminals within ABNF production rules) used to validate the syntax of an IRI according to RFC 3987

```python
from rfc3987_syntax import RFC3987_SYNTAX_TERMS
from rfc3987_syntax2 import RFC3987_SYNTAX_TERMS

print("Supported terms:")
for term in RFC3987_SYNTAX_TERMS:
Expand All @@ -64,7 +66,7 @@ for term in RFC3987_SYNTAX_TERMS:
### Syntactically validate a string using the general-purpose validator

```python
from rfc3987_syntax import is_valid_syntax
from rfc3987_syntax2 import is_valid_syntax

if is_valid_syntax(term='iri', value='http://github.com'):
print("✓ Valid IRI syntax")
Expand All @@ -79,8 +81,8 @@ if not is_valid_syntax(term='iri_reference', value='bob'):
### Alternatively, use term-specific helpers to validate RFC 3987 syntax.

```python
from rfc3987_syntax import is_valid_syntax_iri
from rfc3987_syntax import is_valid_syntax_iri_reference
from rfc3987_syntax2 import is_valid_syntax_iri
from rfc3987_syntax2 import is_valid_syntax_iri_reference

if is_valid_syntax_iri('http://github.com'):
print("✓ Valid IRI syntax")
Expand All @@ -95,7 +97,7 @@ if is_valid_syntax_iri_reference('bob'):
### Get the Lark parse tree for a syntax validation (useful for additional semantic validation)

```python
from rfc3987_syntax import parse
from rfc3987_syntax2 import parse

ptree: ParseTree = parse(term="iri", value="http://github.com")

Expand Down
36 changes: 22 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,59 @@ requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "rfc3987-syntax"
version = "1.1.0"
name = "rfc3987-syntax2"
version = "1.1.0rc2"
description = "Helper functions to syntactically validate strings according to RFC 3987."
readme = "README.md"
requires-python = ">=3.9"
license = "MIT"
license-files = ["LICEN[CS]E*"]
keywords = ["RFC 3987", "RFC3987", "validator", "syntax", "parser"]
authors = [
{ name = "Will Riley", email = "wanderingwill@gmail.com" },
{ name = "Jan Kowalleck" }
{ name = "Jan Kowalleck" },
{ name = "Will Riley", email = "wanderingwill@gmail.com" }
]
classifiers = [
# ALPHA - not all features of RFC 3987 are implemented, yet
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Intended Audience :: Education",
"Intended Audience :: Information Technology",
"Intended Audience :: Science/Research",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: Apache Software License",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Topic :: Scientific/Engineering",
"Topic :: Software Development",
"Topic :: Utilities"
]
dependencies = ["lark>=1.2.2"]

[project.urls]
Homepage = "https://github.com/willynilly/rfc3987-syntax"
Documentation = "https://github.com/willynilly/rfc3987-syntax#readme"
Issues = "https://github.com/willynilly/rfc3987-syntax/issues"
Source = "https://github.com/willynilly/rfc3987-syntax"
Homepage = "https://github.com/jkowalleck/rfc3987-syntax2"
Documentation = "https://github.com/jkowalleck/rfc3987-syntax2#readme"
Issues = "https://github.com/jkowalleck/rfc3987-syntax2/issues"
Source = "https://github.com/jkowalleck/rfc3987-syntax2"

[project.optional-dependencies]
testing = [
"pytest>=8.3.5",
]

[tool.pytest.ini_options]
pythonpath = [
"src"
pythonpath = ["src"]

[tool.hatch.build.targets.sdist]
exclude = [
"/.*",
"/_*",
]
include = [
"/src",
"/tests"
]

[tool.hatch.build.targets.sdist.force-include]
"CITATION.cff" = "src/rfc3987_syntax/CITATION.cff"
[tool.hatch.build.targets.wheel]
packages = ["src/rfc3987_syntax2"]
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from pathlib import Path

from rfc3987_syntax.utils import load_grammar
from .utils import load_grammar

RFC3987_SYNTAX_PARSER_TYPE: str = "earley"
RFC3987_SYNTAX_GRAMMAR_PATH: Path = Path(__file__).parent / "syntax_rfc3987.lark"
Expand Down
File renamed without changes.
9 changes: 5 additions & 4 deletions tests/test_syntax.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from pathlib import Path
import rfc3987_syntax as h
import json
import pytest

import rfc3987_syntax2 as sut


@pytest.fixture
def valid_syntax_data():
Expand All @@ -19,21 +20,21 @@ def invalid_syntax_data():
def test_is_valid_syntax(valid_syntax_data):
for term, valid_examples in valid_syntax_data.items():
for valid_example in valid_examples:
actual = h.is_valid_syntax(term=term, value=valid_example["value"])
actual = sut.is_valid_syntax(term=term, value=valid_example["value"])
print("")
print(
f"Testing {term} with {valid_example['value']} : {valid_example['reason']}"
)
assert (
actual is True
actual is True
), f"Failed term: {term} for '{valid_example['value']}' : {valid_example['reason']}"
assert True


def test_not_is_valid_syntax(invalid_syntax_data):
for term, invalid_examples in invalid_syntax_data.items():
for invalid_example in invalid_examples:
actual = h.is_valid_syntax(term=term, value=invalid_example["value"])
actual = sut.is_valid_syntax(term=term, value=invalid_example["value"])
print("")
print(
f"Testing {term} with {invalid_example['value']} : {invalid_example['reason']}"
Expand Down
Loading