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.
- swopy-0.1.1/.github/dependabot.yaml +18 -0
- swopy-0.1.1/.github/workflows/ci.yaml +80 -0
- swopy-0.1.1/.github/workflows/publish.yaml +37 -0
- swopy-0.1.1/.github/workflows/tag-and-release.yaml +76 -0
- swopy-0.1.1/.gitignore +17 -0
- swopy-0.1.1/.pre-commit-config.yaml +23 -0
- swopy-0.1.1/.python-version +1 -0
- swopy-0.1.1/PKG-INFO +119 -0
- swopy-0.1.1/README.md +104 -0
- swopy-0.1.1/pyproject.toml +123 -0
- swopy-0.1.1/scripts/startup.sh +6 -0
- swopy-0.1.1/scripts/upgrade-python.sh +8 -0
- swopy-0.1.1/swopy/__init__.py +17 -0
- swopy-0.1.1/swopy/py.typed +0 -0
- swopy-0.1.1/swopy/swopy.py +126 -0
- swopy-0.1.1/swopy/system.py +139 -0
- swopy-0.1.1/swopy/systems/__init__.py +3 -0
- swopy-0.1.1/swopy/systems/arabic.py +65 -0
- swopy-0.1.1/swopy/systems/egyptian.py +115 -0
- swopy-0.1.1/swopy/systems/roman.py +351 -0
- swopy-0.1.1/tests/helpers.py +37 -0
- swopy-0.1.1/tests/test_swopy.py +167 -0
- swopy-0.1.1/tests/test_systems.py +146 -0
- swopy-0.1.1/tox.toml +40 -0
- swopy-0.1.1/uv.lock +403 -0
|
@@ -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,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
|
+
]
|
|
File without changes
|