Skip to content

Commit 8c6ef9e

Browse files
authored
Merge pull request #1 from truehazker/feature/initial-setup
feat: ✨ initial project structureand setup
2 parents aa01983 + 2823c3e commit 8c6ef9e

20 files changed

+2846
-0
lines changed

.github/workflows/ci.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- develop
8+
pull_request:
9+
branches:
10+
- main
11+
- develop
12+
13+
jobs:
14+
lint:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: astral-sh/setup-uv@v4
19+
- run: uv sync --dev
20+
- run: uv run ruff check src tests
21+
- run: uv run ruff format --check src tests
22+
23+
typecheck:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- uses: actions/checkout@v4
27+
- uses: astral-sh/setup-uv@v4
28+
- run: uv sync --dev
29+
- run: uv run basedpyright src
30+
31+
test:
32+
runs-on: ubuntu-latest
33+
strategy:
34+
matrix:
35+
python-version: ["3.11", "3.12", "3.13"]
36+
steps:
37+
- uses: actions/checkout@v4
38+
- uses: astral-sh/setup-uv@v4
39+
with:
40+
python-version: ${{ matrix.python-version }}
41+
- run: uv sync --dev
42+
- run: uv run pytest
43+

.github/workflows/publish.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Publish
2+
3+
on:
4+
release:
5+
types:
6+
- published
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
environment: pypi
12+
permissions:
13+
id-token: write
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: astral-sh/setup-uv@v4
17+
- run: uv build
18+
- uses: pypa/gh-action-pypi-publish@release/v1
19+

.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Python-generated files
2+
__pycache__/
3+
*.py[oc]
4+
build/
5+
dist/
6+
wheels/
7+
*.egg-info
8+
.pytest_cache/
9+
.ruff_cache/
10+
.mypy_cache/
11+
.coverage
12+
htmlcov/
13+
*.log
14+
15+
# Virtual environments
16+
.venv
17+
venv/
18+
env/
19+
20+
# IDE
21+
.vscode/
22+
.idea/
23+
*.swp
24+
*.swo
25+
*~
26+
.DS_Store

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 truehazker
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

examples/basic_usage.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Basic usage example."""
2+
3+
from pydantic_settings import BaseSettings
4+
5+
from pyenvalid import validate_settings
6+
7+
8+
class Settings(BaseSettings):
9+
database_url: str
10+
api_key: str
11+
port: int = 8080
12+
13+
14+
settings = validate_settings(Settings)
15+
print(f"Connected to {settings.database_url}")

examples/with_env_file.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Load settings from .env file."""
2+
3+
from pydantic_settings import BaseSettings, SettingsConfigDict
4+
5+
from pyenvalid import validate_settings
6+
7+
8+
class Settings(BaseSettings):
9+
model_config = SettingsConfigDict(env_file=".env")
10+
11+
secret_key: str
12+
database_url: str
13+
14+
15+
settings = validate_settings(Settings)

examples/with_literals.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Constrained values with Literal types."""
2+
3+
from typing import Literal
4+
5+
from pydantic_settings import BaseSettings
6+
7+
from pyenvalid import validate_settings
8+
9+
10+
class Settings(BaseSettings):
11+
api_key: str
12+
environment: Literal["dev", "staging", "prod"] = "dev"
13+
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO"
14+
15+
16+
settings = validate_settings(Settings)
17+
print(f"Running in {settings.environment} mode")

pyproject.toml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
[project]
2+
name = "pyenvalid"
3+
version = "0.1.0"
4+
description = "Beautiful validation errors for pydantic-settings"
5+
readme = "README.md"
6+
license = "MIT"
7+
authors = [
8+
{ name = "truehazker", email = "[email protected]" }
9+
]
10+
requires-python = ">=3.11"
11+
keywords = ["pydantic", "pydantic-settings", "validation", "environment", "configuration"]
12+
classifiers = [
13+
"Development Status :: 4 - Beta",
14+
"Intended Audience :: Developers",
15+
"License :: OSI Approved :: MIT License",
16+
"Operating System :: OS Independent",
17+
"Programming Language :: Python :: 3",
18+
"Programming Language :: Python :: 3.11",
19+
"Programming Language :: Python :: 3.12",
20+
"Programming Language :: Python :: 3.13",
21+
"Topic :: Software Development :: Libraries :: Python Modules",
22+
"Typing :: Typed",
23+
]
24+
dependencies = [
25+
"pydantic>=2.0.0",
26+
"pydantic-settings>=2.0.0",
27+
]
28+
29+
[project.urls]
30+
Repository = "https://github.com/truehazker/pyenvalid"
31+
32+
[build-system]
33+
requires = ["hatchling"]
34+
build-backend = "hatchling.build"
35+
36+
[tool.hatch.build]
37+
packages = ["src/pyenvalid"]
38+
39+
[dependency-groups]
40+
dev = [
41+
"basedpyright>=1.34.0",
42+
"pytest>=8.0.0",
43+
"ruff>=0.4.0",
44+
]
45+
46+
[tool.pytest.ini_options]
47+
testpaths = ["tests"]
48+
pythonpath = ["src"]
49+
addopts = "-v --tb=short"
50+
51+
[tool.ruff]
52+
target-version = "py311"
53+
line-length = 88
54+
src = ["src", "tests"]
55+
56+
[tool.ruff.lint]
57+
select = [
58+
"E", # pycodestyle errors
59+
"W", # pycodestyle warnings
60+
"F", # pyflakes
61+
"I", # isort
62+
"B", # flake8-bugbear
63+
"C4", # flake8-comprehensions
64+
"UP", # pyupgrade
65+
"ARG", # flake8-unused-arguments
66+
"SIM", # flake8-simplify
67+
]
68+
ignore = [
69+
"E501", # line too long (handled by formatter)
70+
]
71+
72+
[tool.ruff.lint.isort]
73+
known-first-party = ["pyenvalid"]
74+
75+
[tool.basedpyright]
76+
pythonVersion = "3.11"
77+
typeCheckingMode = "strict"
78+
pythonPlatform = "All"

src/pyenvalid/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Pyenvalid - Beautiful validation errors for pydantic-settings.
2+
3+
A lightweight library that provides user-friendly error messages when
4+
environment variable validation fails in pydantic-settings applications.
5+
6+
Example:
7+
>>> from pydantic_settings import BaseSettings
8+
>>> from pyenvalid import validate_settings, ConfigurationError
9+
>>>
10+
>>> class Settings(BaseSettings):
11+
... api_key: str
12+
... database_url: str
13+
... port: int = 8080
14+
>>>
15+
>>> try:
16+
... settings = validate_settings(Settings)
17+
... except ConfigurationError as e:
18+
... print(e) # Beautiful formatted error
19+
"""
20+
21+
from pyenvalid.validation import ConfigurationError, validate_settings
22+
23+
__all__ = ["ConfigurationError", "validate_settings"]

0 commit comments

Comments
 (0)