swopy 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "uv"
4
+ # Look for `uv.lock` file in the root directory.
5
+ directory: "/"
6
+ # Check the registry for updates every day (weekdays)
7
+ schedule:
8
+ interval: "weekly"
9
+
10
+ - package-ecosystem: "github-actions"
11
+ # Workflow files stored in the default location of `.github/workflows`
12
+ # You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
13
+ directory: "/"
14
+ schedule:
15
+ interval: "weekly"
16
+ allow:
17
+ - dependency-type: "direct"
18
+ - dependency-type: "indirect"
@@ -0,0 +1,80 @@
1
+ name: Checks
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [ "main" ]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ name: test with ${{ matrix.env }} on ${{ matrix.os }}
13
+ runs-on: ${{ matrix.os }}
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ env:
18
+ - "3.15.0a5"
19
+ - "3.14.3"
20
+ - "3.14.2"
21
+ - "3.14.1"
22
+ - "3.14.0"
23
+ - "3.13"
24
+ os:
25
+ - ubuntu-latest
26
+ - macos-latest
27
+ - windows-latest
28
+ steps:
29
+ - name: Harden the runner (Audit all outbound calls)
30
+ uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
31
+ with:
32
+ egress-policy: audit
33
+
34
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
35
+
36
+ - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
37
+ id: check_changes
38
+ with:
39
+ filters: |
40
+ relevant:
41
+ - '**/*.py'
42
+ - '**/*.toml'
43
+ - '**/*.lock'
44
+ - '.python-version'
45
+
46
+ - name: Skip message
47
+ if: ${{ !(steps.check_changes.outputs.relevant == 'true') }}
48
+ run: echo "Skipping Python checks - no relevant changes detected"
49
+
50
+ - name: Install the latest version of uv
51
+ if: steps.check_changes.outputs.relevant == 'true'
52
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v6.8.0
53
+ with:
54
+ enable-cache: true
55
+ cache-dependency-glob: "pyproject.toml"
56
+
57
+ - name: Add .local/bin to Windows PATH
58
+ if: steps.check_changes.outputs.relevant == 'true' && runner.os == 'Windows'
59
+ shell: bash
60
+ run: echo "$USERPROFILE/.local/bin" >> $GITHUB_PATH
61
+
62
+ - name: Install tox
63
+ if: steps.check_changes.outputs.relevant == 'true'
64
+ run: uv tool install --python-preference only-managed --python 3.14 tox --with tox-uv --with tox-gh
65
+
66
+ - name: Install Python
67
+ if: steps.check_changes.outputs.relevant == 'true'
68
+ run: uv python install --python-preference only-managed ${{ matrix.env }}
69
+
70
+ - name: Setup test suite
71
+ if: steps.check_changes.outputs.relevant == 'true'
72
+ run: tox run -vv --notest --skip-missing-interpreters false
73
+ env:
74
+ TOX_GH_MAJOR_MINOR: ${{ matrix.env }}
75
+
76
+ - name: Run test suite
77
+ if: steps.check_changes.outputs.relevant == 'true'
78
+ run: tox run --skip-pkg-install
79
+ env:
80
+ TOX_GH_MAJOR_MINOR: ${{ matrix.env }}
@@ -0,0 +1,37 @@
1
+ name: Publish to PyPI and Docker
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ run:
13
+ name: "Build and publish release"
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ id-token: write # Required for OIDC authentication
17
+ contents: read
18
+
19
+ steps:
20
+ - name: Harden the runner (Audit all outbound calls)
21
+ uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
22
+ with:
23
+ egress-policy: audit
24
+
25
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
28
+ - name: Set up Python
29
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
30
+ with:
31
+ python-version-file: ".python-version"
32
+ - name: Build
33
+ run: uv build
34
+ - name: Publish to PyPI test
35
+ run: uv publish --index testpypi
36
+ - name: Publish
37
+ run: uv publish
@@ -0,0 +1,76 @@
1
+ name: Version Bump and Release
2
+
3
+ on:
4
+ workflow_dispatch: # Allow manual triggering
5
+ push:
6
+ branches: ["main"]
7
+ paths-ignore:
8
+ - '.github/**'
9
+ - 'scripts/**'
10
+ - 'tests/**'
11
+ - '.gitignore'
12
+ - '.pre-commit-config.yaml'
13
+ - 'pyproject.toml'
14
+ - 'tox.toml'
15
+ - 'uv.lock'
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ bump-version-and-release:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - name: Harden the runner (Audit all outbound calls)
25
+ uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
26
+ with:
27
+ egress-policy: audit
28
+
29
+ - name: Checkout repository
30
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
31
+ with:
32
+ fetch-depth: 0 # Fetch all history for proper tag creation
33
+ token: ${{ secrets.BOT_TOKEN }}
34
+ - name: Install uv
35
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
36
+
37
+ - name: Current version
38
+ id: current_version
39
+ run: |
40
+ CURRENT_VERSION=$(uv version | awk '{print $2}')
41
+ PATCH=$("$CURRENT_VERSION" | cut -d '.' -f 2)
42
+ echo "patch=$PATCH" >> $GITHUB_OUTPUT
43
+
44
+ # If a new minor or major version tag has been pushed then don't
45
+ # bump the patch version.
46
+ - name: Bump version
47
+ if: steps.current_version.outputs.patch != '0'
48
+ run: |
49
+ uv version --bump patch
50
+
51
+ - name: New version
52
+ id: new_version
53
+ run: |
54
+ NEW_VERSION=$(uv version | awk '{print $2}')
55
+ echo "tag=$NEW_VERSION" >> $GITHUB_OUTPUT
56
+
57
+ - name: Commit version change
58
+ run: |
59
+ git config --local user.email "218805929+amati-bot@users.noreply.github.com"
60
+ git config --local user.name "amati[bot]"
61
+ git commit uv.lock pyproject.toml -m "Bump version to ${{ steps.new_version.outputs.tag }}"
62
+ git push origin
63
+
64
+ - name: Create and push tag
65
+ run: |
66
+ git tag ${{ steps.new_version.outputs.tag }}
67
+ git push --tags
68
+
69
+ - name: Create GitHub Release
70
+ env:
71
+ GH_TOKEN: ${{ secrets.BOT_TOKEN }}
72
+ run: |
73
+ gh release create ${{ steps.new_version.outputs.tag }} \
74
+ --title "${{ steps.new_version.outputs.tag }}" \
75
+ --generate-notes \
76
+ --latest
swopy-0.1.1/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+ .coverage
9
+ .hypothesis/
10
+
11
+ # Virtual environments
12
+ .venv
13
+
14
+
15
+ # MacOS
16
+ .DS_Store
17
+ tests/.DS_Store
@@ -0,0 +1,23 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ # Ruff version.
4
+ rev: v0.14.13
5
+ hooks:
6
+ # Run the linter.
7
+ - id: ruff-check
8
+ args: [--fix]
9
+ # Run the formatter.
10
+ - id: ruff-format
11
+ - repo: https://github.com/gitleaks/gitleaks
12
+ rev: v8.28.0
13
+ hooks:
14
+ - id: gitleaks
15
+ - repo: https://github.com/koalaman/shellcheck-precommit
16
+ rev: v0.7.2
17
+ hooks:
18
+ - id: shellcheck
19
+ args: [-x]
20
+ - repo: https://github.com/fpgmaas/deptry.git
21
+ rev: 0.24.0
22
+ hooks:
23
+ - id: deptry
@@ -0,0 +1 @@
1
+ 3.14.3
swopy-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: swopy
3
+ Version: 0.1.1
4
+ Summary: A collection of numeral system converters.
5
+ Author-email: Ben <2551337+ben-alexander@users.noreply.github.com>
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Programming Language :: Python :: 3.14
11
+ Classifier: Topic :: Software Development
12
+ Classifier: Typing :: Typed
13
+ Requires-Python: >=3.13
14
+ Description-Content-Type: text/markdown
15
+
16
+ # Swopy
17
+
18
+ A Python library for converting between different numeral systems.
19
+
20
+ ## Overview
21
+
22
+ Swopy provides a simple and extensible interface to convert numbers between various numeral systems, including Roman numerals and Egyptian hieroglyphic numerals. The library supports bidirectional conversion—you can convert from any supported system to any other.
23
+
24
+ ## Supported Numeral Systems
25
+
26
+ * [Roman](swopy/systems/roman.py), in the forms
27
+ * Early, supporting integers between 1 and 899
28
+ * Standard, supporting integers between 1 and 3,999
29
+ * Apostrophus, supporting integers between 1 and 100,000
30
+ * [Egyptian](umberology/systems/egyptian.py), supporting integers between 1 and 1,000,000/many
31
+ * Arabic, supporting integers between `-int(sys.float_info.max)` and `int(sys.float_info.max)`
32
+
33
+ ## Installation
34
+
35
+ Install the package:
36
+
37
+ ```bash
38
+ pip install swopy # or
39
+ uv add swopy
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ ### Basic Conversion
45
+
46
+ ```python
47
+ from swopy import Swopy, systems
48
+
49
+ converter = Swopy()
50
+
51
+ # Convert integer Roman numeral to Egyptian hieroglyphic
52
+ converter.convert('IX', systems.roman.Standard, systems.egyptian.Egyptian)
53
+ # '𓏺𓏺𓏺𓏺𓏺𓏺𓏺𓏺𓏺'
54
+
55
+ # Convert Apostrophus to an Arabic integer
56
+ converter.convert('IↃI', systems.roman.Apostrophus, systems.arabic.Arabic)
57
+ # 501
58
+ ```
59
+
60
+ ### Available Systems
61
+
62
+ ```python
63
+ from swopy import Swopy, get_all_systems
64
+ import pprint
65
+ systems = get_all_systems()
66
+ pprint.pprint(systems)
67
+ #{'arabic.Arabic': <class 'swopy.systems.arabic.Arabic'>,
68
+ # 'egyptian.Egyptian': <class 'swopy.systems.egyptian.Egyptian'>,
69
+ # 'roman.Apostrophus': <class 'swopy.systems.roman.Apostrophus'>,
70
+ # 'roman.Early': <class 'swopy.systems.roman.Early'>,
71
+ # 'roman.Standard': <class 'swopy.systems.roman.Standard'>}
72
+
73
+ converter = Swopy()
74
+ converter.convert(42, systems['arabic.Arabic'], systems['roman.Early'])
75
+ # 'XLII'
76
+
77
+ ```
78
+
79
+ ### Error Handling
80
+
81
+ The library validates numbers against the acceptable range for each system:
82
+
83
+ ```python
84
+ from swopy import Swopy, systems
85
+
86
+ converter = Swopy()
87
+
88
+ # This will raise ValueError (4000 is outside the valid range)
89
+ try:
90
+ result = converter.convert(4000, systems.arabic.Arabic, systems.roman.Standard)
91
+ except ValueError as e:
92
+ print(f"Conversion failed: {e}")
93
+ # Conversion failed: Number must be less than or equal to 3999.
94
+ ```
95
+
96
+ ## Requirements
97
+
98
+ - Python 3.13 or higher
99
+
100
+ ## Development
101
+
102
+ ### Dependencies
103
+
104
+ Development dependencies are managed through `pyproject.toml`:
105
+
106
+ ```bash
107
+ # Install development dependencies
108
+ sh scripts/startup.sh
109
+ ```
110
+
111
+ Dev tools include:
112
+ - pytest / pytest-cov: Testing framework
113
+ - ruff: Fast Python linter and formatter
114
+ - pyright: Static type checker
115
+ - deptry: Dependency validation
116
+ - hypothesis: Property-based testing
117
+ - pre-commit: Git hooks framework
118
+ - tox, with tox-uv: Test runner
119
+ - uv
swopy-0.1.1/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # Swopy
2
+
3
+ A Python library for converting between different numeral systems.
4
+
5
+ ## Overview
6
+
7
+ Swopy provides a simple and extensible interface to convert numbers between various numeral systems, including Roman numerals and Egyptian hieroglyphic numerals. The library supports bidirectional conversion—you can convert from any supported system to any other.
8
+
9
+ ## Supported Numeral Systems
10
+
11
+ * [Roman](swopy/systems/roman.py), in the forms
12
+ * Early, supporting integers between 1 and 899
13
+ * Standard, supporting integers between 1 and 3,999
14
+ * Apostrophus, supporting integers between 1 and 100,000
15
+ * [Egyptian](umberology/systems/egyptian.py), supporting integers between 1 and 1,000,000/many
16
+ * Arabic, supporting integers between `-int(sys.float_info.max)` and `int(sys.float_info.max)`
17
+
18
+ ## Installation
19
+
20
+ Install the package:
21
+
22
+ ```bash
23
+ pip install swopy # or
24
+ uv add swopy
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### Basic Conversion
30
+
31
+ ```python
32
+ from swopy import Swopy, systems
33
+
34
+ converter = Swopy()
35
+
36
+ # Convert integer Roman numeral to Egyptian hieroglyphic
37
+ converter.convert('IX', systems.roman.Standard, systems.egyptian.Egyptian)
38
+ # '𓏺𓏺𓏺𓏺𓏺𓏺𓏺𓏺𓏺'
39
+
40
+ # Convert Apostrophus to an Arabic integer
41
+ converter.convert('IↃI', systems.roman.Apostrophus, systems.arabic.Arabic)
42
+ # 501
43
+ ```
44
+
45
+ ### Available Systems
46
+
47
+ ```python
48
+ from swopy import Swopy, get_all_systems
49
+ import pprint
50
+ systems = get_all_systems()
51
+ pprint.pprint(systems)
52
+ #{'arabic.Arabic': <class 'swopy.systems.arabic.Arabic'>,
53
+ # 'egyptian.Egyptian': <class 'swopy.systems.egyptian.Egyptian'>,
54
+ # 'roman.Apostrophus': <class 'swopy.systems.roman.Apostrophus'>,
55
+ # 'roman.Early': <class 'swopy.systems.roman.Early'>,
56
+ # 'roman.Standard': <class 'swopy.systems.roman.Standard'>}
57
+
58
+ converter = Swopy()
59
+ converter.convert(42, systems['arabic.Arabic'], systems['roman.Early'])
60
+ # 'XLII'
61
+
62
+ ```
63
+
64
+ ### Error Handling
65
+
66
+ The library validates numbers against the acceptable range for each system:
67
+
68
+ ```python
69
+ from swopy import Swopy, systems
70
+
71
+ converter = Swopy()
72
+
73
+ # This will raise ValueError (4000 is outside the valid range)
74
+ try:
75
+ result = converter.convert(4000, systems.arabic.Arabic, systems.roman.Standard)
76
+ except ValueError as e:
77
+ print(f"Conversion failed: {e}")
78
+ # Conversion failed: Number must be less than or equal to 3999.
79
+ ```
80
+
81
+ ## Requirements
82
+
83
+ - Python 3.13 or higher
84
+
85
+ ## Development
86
+
87
+ ### Dependencies
88
+
89
+ Development dependencies are managed through `pyproject.toml`:
90
+
91
+ ```bash
92
+ # Install development dependencies
93
+ sh scripts/startup.sh
94
+ ```
95
+
96
+ Dev tools include:
97
+ - pytest / pytest-cov: Testing framework
98
+ - ruff: Fast Python linter and formatter
99
+ - pyright: Static type checker
100
+ - deptry: Dependency validation
101
+ - hypothesis: Property-based testing
102
+ - pre-commit: Git hooks framework
103
+ - tox, with tox-uv: Test runner
104
+ - uv
@@ -0,0 +1,123 @@
1
+ [project]
2
+ name = "swopy"
3
+ version = "0.1.1"
4
+ description = "A collection of numeral system converters."
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ authors = [
8
+ { name = "Ben", email = "2551337+ben-alexander@users.noreply.github.com" }
9
+ ]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Intended Audience :: Developers",
13
+ "Programming Language :: Python :: 3 :: Only",
14
+ "Programming Language :: Python :: 3.14",
15
+ "Topic :: Software Development",
16
+ "Typing :: Typed",
17
+ ]
18
+ license = "MIT"
19
+ license-files = ["LICENSE"]
20
+ dependencies = []
21
+
22
+
23
+ [dependency-groups]
24
+ dev = [
25
+ "deptry",
26
+ "hypothesis",
27
+ "pre-commit",
28
+ "pyright",
29
+ "pytest",
30
+ "pytest-cov",
31
+ "ruff",
32
+ ]
33
+
34
+ [tool.coverage.run]
35
+ relative_files=true
36
+ omit=[
37
+ "tests/*",
38
+ ]
39
+
40
+ [tool.deptry.package_module_name_map]
41
+ hypothesis="hypothesis"
42
+ pre_commit="pre_commit"
43
+ pyright="pyright"
44
+ pytest="pytest"
45
+ pytest-cov="pytest_cov"
46
+ ruff="ruff"
47
+
48
+ [tool.pyright]
49
+ reportMissingTypeStubs=false
50
+ reportMissingImports=false # Ignore external dependencies
51
+ typeCheckingMode="strict"
52
+ include = ["swopy"]
53
+
54
+ [tool.pytest.ini_options]
55
+ doctest_optionflags = "NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ELLIPSIS"
56
+ addopts = "--strict-markers"
57
+ markers = [
58
+ "external: requires external dependencies"
59
+ ]
60
+
61
+ [tool.uv]
62
+ package = true
63
+
64
+ [build-system]
65
+ requires = ["hatchling"]
66
+ build-backend = "hatchling.build"
67
+
68
+ [tool.hatch.build.targets.wheel]
69
+ packages = ["swopy"]
70
+ include = [
71
+ "/swopy/py.typed",
72
+ ]
73
+
74
+ [[tool.uv.index]]
75
+ name = "pypi"
76
+ url = "https://pypi.org/simple/"
77
+ default = true
78
+
79
+ [[tool.uv.index]]
80
+ name = "testpypi"
81
+ url = "https://test.pypi.org/legacy/"
82
+ publish-url = "https://test.pypi.org/legacy/"
83
+
84
+ [tool.ruff]
85
+ line-length = 88
86
+
87
+ [tool.ruff.lint]
88
+ select = [
89
+ "A", # flake8-builtins
90
+ "ARG", # flake8-arguments
91
+ "B", # flake8-bugbear
92
+ "C4", # flake8-comprehensions
93
+ "C90", # McCabe complexity
94
+ "DTZ", # flake8-datetimez
95
+ "E", # pycodestyle errors
96
+ "ERA", # eradicate (commented out code)
97
+ "F", # pyflakes
98
+ "I", # isort
99
+ "ISC", # flake8-implicit-str-concat
100
+ "PL", # Pylint
101
+ "PLC", # Pylint - Convention
102
+ "PLE", # Pylint - Error
103
+ "PTH", # flake8-pathlib
104
+ "PLR", # Pylint - Refactor
105
+ "PLW", # Pylint - warnings
106
+ "RUF", # ruff-specific rules
107
+ "S", # flake8-bandit
108
+ "SIM", # flake8-simplify
109
+ "T20", # flake8-print
110
+ "UP", # pyupgrade
111
+ "W", # pycodestyle warnings
112
+ "YTT", # flake8-2020
113
+ ]
114
+ extend-fixable = ["UP015"]
115
+
116
+ [tool.ruff.lint.isort]
117
+ known-first-party=["swopy"]
118
+
119
+ [tool.ruff.lint.per-file-ignores]
120
+ # Disable certain checks in tests
121
+ "tests/**/*.py" = [
122
+ "S101", # Allow assert
123
+ ]
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ uv python install
3
+ . .venv/bin/activate
4
+ uv sync
5
+ pre-commit install
6
+ uv tool install tox --with tox-uv
@@ -0,0 +1,8 @@
1
+ #!/bin/sh
2
+
3
+ deactivate || true
4
+ uv self update
5
+ . .venv/bin/activate
6
+ uv python upgrade
7
+ uv python pin "$1"
8
+ uv sync --all-groups
@@ -0,0 +1,17 @@
1
+ from . import systems
2
+ from .swopy import (
3
+ Denotation,
4
+ Numeral,
5
+ Swopy,
6
+ System,
7
+ get_all_systems,
8
+ )
9
+
10
+ __all__ = [
11
+ "Denotation",
12
+ "Numeral",
13
+ "Swopy",
14
+ "System",
15
+ "get_all_systems",
16
+ "systems",
17
+ ]
File without changes