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
25 changes: 4 additions & 21 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
[flake8]
# Maximum line length allowed
max-line-length = 127

# Maximum allowed code complexity (10 is a reasonable threshold)
max-line-length = 88
max-complexity = 10

# Only check for specific error codes:
# - E9 -> Syntax errors
# - F63 -> Issues related to improper usage of `+=`, `-=`, etc.
# - F7 -> Issues related to improper `break`, `continue`, etc.
# - F82 -> Undefined names
select = E9,F63,F7,F82

# Exclude `.venv` from linting (prevents checking dependencies)
select = E,F,W
extend-ignore = E203, W503
exclude = .venv

# Print the count of linting errors
per-file-ignores = tests/test_main.py: E501
count = True

# Show the exact source of the error
show-source = True

# Display statistics of errors at the end of the report
statistics = True

# Enable verbose mode for more detailed output
verbose = True
8 changes: 6 additions & 2 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'

- name: Install dependencies
- name: Install lint dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-lint.txt
Expand All @@ -40,6 +40,10 @@ jobs:
run: |
flake8 .

- name: Check code formatting with Black
run: |
black --check .

test:
needs: lint
runs-on: ubuntu-latest
Expand All @@ -53,7 +57,7 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'

- name: Install dependencies
- name: Install test dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-test.txt
Expand Down
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"recommendations": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.flake8",
"ms-python.black-formatter",
"github.vscode-pull-request-github",
"github.vscode-github-actions",
"ms-azuretools.vscode-containers",
Expand Down
45 changes: 41 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,53 @@
{
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["tests"],
"files.exclude": {
"**/__pycache__": true,
"**/.git": true,
"**/.DS_Store": true
},
"editor.wordWrapColumn": 88,
"editor.rulers": [88],
"[python]": {
"editor.defaultFormatter": "ms-python.autopep8",
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true
},
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["tests"],
"flake8.enabled": true,
"flake8.importStrategy": "fromEnvironment",
"flake8.path": ["${interpreter}", "-m", "flake8"],
// Point flake8 to use your existing config file automatically
"flake8.args": [
"--max-line-length=88",
"--max-complexity=10",
"--select=E,F,W",
"--extend-ignore=E203,W503",
"--exclude=.venv",
"--per-file-ignores=tests/test_main.py:E501"
],
// Exclude files/folders you don’t want to lint (matching Black’s exclude)
"flake8.ignorePatterns": [
"**/.git/**",
"**/.github/**",
"**/.pytest_cache/**",
"**/.venv/**",
"**/.vscode/**",
"**/assets/**",
"**/htmlcov/**",
"**/postman_collections/**",
"**/scripts/**",
"**/storage/**",
"**/__pycache__/**",
"**/tests/test_main.py"
],
"flake8.severity": {
"convention": "Information",
"error": "Error",
"fatal": "Error",
"refactor": "Hint",
"warning": "Warning",
"info": "Information"
},
"sonarlint.connectedMode.project": {
"connectionId": "nanotaboada",
"projectKey": "nanotaboada_python-samples-fastapi-restful"
Expand Down
57 changes: 36 additions & 21 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,58 @@ We value **incremental, detail‑first contributions** over big rewrites or abst
## 2. Code & Commit Conventions

- **Conventional Commits**
Follow <https://www.conventionalcommits.org/en/v1.0.0/>:
- `feat: ` for new features
- `fix: ` for bug fixes
- `chore: ` for maintenance
Follow <https://www.conventionalcommits.org/en/v1.0.0/>:
- `feat: ` for new features
- `fix: ` for bug fixes
- `chore: ` for maintenance or tooling

- **Logical Commits**
Group changes by purpose. It’s okay to have multiple commits in a PR, but if they’re mere checkpoints, squash them into a single logical commit.

- **Lint & Tests**
Run existing linters/formatters and ensure all tests pass.
Group changes by purpose. Multiple commits are fine, but avoid noise. Squash when appropriate.

- **Python Formatting & Style**
- Use **[Black](https://black.readthedocs.io/)** for consistent code formatting.
- Black is opinionated: don't argue with it, just run it.
- Line length is set to **88**, matching the default.
- Use **[flake8](https://flake8.pycqa.org/en/latest/)** for static checks.
- Line length also set to 88.
- Some flake8 warnings are disabled (e.g. `E203`, `W503`) to avoid conflicts with Black.
- Run `black .` and `flake8` before submitting.
- Use Python **3.13.x** for local testing and formatting.

- **Testing**
- Run `pytest` before pushing.
- Ensure coverage isn’t regressing.

## 3. Pull Request Workflow

- **One logical change per PR.**
- **Rebase or squash** before opening to keep history concise.
- **Rebase or squash** before opening to keep history clean.
- **Title & Description**
- Title uses Conventional Commits style.
- Description explains _what_ and _why_—keep context minimal.
- Use Conventional Commit format.
- Explain _what_ and _why_ concisely in the PR body.

## 4. Issue Reporting

- Search existing issues first.
- Provide a minimal reproducible example and clear steps.
- Search open issues before creating a new one.
- Include clear steps to reproduce and environment details.
- Prefer **focused** issues—don’t bundle multiple topics.

## 5. Automation & Checks

We enforce quality via CI on every push and PR:
All PRs and pushes go through CI:

- **Commitlint** for commit‑message style
- **Linters/Formatters**
- **Unit tests**
- **Commitlint** for commit style
- **Black** for formatting
- **flake8** for static checks
- **pytest** with coverage

Failures must be fixed before review.
PRs must pass all checks to be reviewed.

## 6. Code of Conduct & Support

- Please see `CODE_OF_CONDUCT.md` for behavioral expectations and reporting.
- For quick questions or discussions, open an issue with the `discussion` label or mention a maintainer.
- See `CODE_OF_CONDUCT.md` for guidelines and reporting.
- For questions or planning, open an issue and use the `discussion` label, or mention a maintainer.

---

Thanks again for helping keep this project small, simple, and impactful!
Thanks again for helping keep this project small, sharp, and focused.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
[![codecov](https://codecov.io/gh/nanotaboada/python-samples-fastapi-restful/branch/master/graph/badge.svg?token=A1WNZPRQEJ)](https://codecov.io/gh/nanotaboada/python-samples-fastapi-restful)
[![CodeFactor](https://www.codefactor.io/repository/github/nanotaboada/python-samples-fastapi-restful/badge)](https://www.codefactor.io/repository/github/nanotaboada/python-samples-fastapi-restful)
[![codebeat badge](https://codebeat.co/badges/4c4f7c08-3b35-4b57-a875-bf2043efe515)](https://codebeat.co/projects/github-com-nanotaboada-python-samples-fastapi-restful-master)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

## About

Expand Down
10 changes: 3 additions & 7 deletions databases/player_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

The `STORAGE_PATH` environment variable controls the SQLite file location.
"""

import logging
import os
from typing import AsyncGenerator
Expand All @@ -21,16 +22,11 @@
logging.getLogger("sqlalchemy.engine.Engine").handlers = logger.handlers

async_engine = create_async_engine(
DATABASE_URL,
connect_args={"check_same_thread": False},
echo=True
DATABASE_URL, connect_args={"check_same_thread": False}, echo=True
)

async_sessionmaker = sessionmaker(
bind=async_engine,
class_=AsyncSession,
autocommit=False,
autoflush=False
bind=async_engine, class_=AsyncSession, autocommit=False, autoflush=False
)

Base = declarative_base()
Expand Down
13 changes: 9 additions & 4 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

This serves as the entry point for running the API server.
"""

from contextlib import asynccontextmanager
import logging
from typing import AsyncIterator
Expand All @@ -17,6 +18,7 @@
UVICORN_LOGGER = "uvicorn.error"
logger = logging.getLogger(UVICORN_LOGGER)


@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
"""
Expand All @@ -25,10 +27,13 @@ async def lifespan(_: FastAPI) -> AsyncIterator[None]:
logger.info("Lifespan event handler execution complete.")
yield

app = FastAPI(lifespan=lifespan,
title="python-samples-fastapi-restful",
description="🧪 Proof of Concept for a RESTful API made with Python 3 and FastAPI",
version="1.0.0",)

app = FastAPI(
lifespan=lifespan,
title="python-samples-fastapi-restful",
description="🧪 Proof of Concept for a RESTful API made with Python 3 and FastAPI",
version="1.0.0",
)

app.include_router(player_route.api_router)
app.include_router(health_route.api_router)
12 changes: 9 additions & 3 deletions models/player_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

These models are used for data validation and serialization in the API.
"""

from typing import Optional
from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_camel
Expand All @@ -22,8 +23,10 @@ class MainModel(BaseModel):
model_config (ConfigDict): Configuration for Pydantic models, including:
alias_generator (function): A function to generate field aliases.
Here, it uses `to_camel` to convert field names to camelCase.
populate_by_name (bool): Allows population of fields by name when using Pydantic models.
populate_by_name (bool): Allows population of fields by name when using
Pydantic models.
"""

model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)


Expand All @@ -39,11 +42,14 @@ class PlayerModel(MainModel):
date_of_birth (Optional[str]): The date of birth of the Player, if provided.
squad_number (int): The unique squad number assigned to the Player.
position (str): The playing position of the Player.
abbr_position (Optional[str]): The abbreviated form of the Player's position, if any.
abbr_position (Optional[str]): The abbreviated form of the Player's position,
if any.
team (Optional[str]): The team to which the Player belongs, if any.
league (Optional[str]): The league where the team plays, if any.
starting11 (Optional[bool]): Indicates if the Player is in the starting 11, if provided.
starting11 (Optional[bool]): Indicates if the Player is in the starting 11,
if provided.
"""

id: int
first_name: str
middle_name: Optional[str]
Expand Down
20 changes: 20 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[tool.black]
line-length = 88
target-version = ['py313']
include = '\.pyi?$'
exclude = '''
/(
\.git
| \.github
| \.pytest_cache
| \.venv
| \.vscode
| assets
| htmlcov
| postman_collections
| scripts
| storage
| __pycache__
| tests/test_main\.py
)/
'''
1 change: 1 addition & 0 deletions requirements-lint.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
flake8==7.2.0
black==25.1.0
5 changes: 4 additions & 1 deletion routes/health_route.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
Defines a simple endpoint to verify that the service is up and running.
Returns a JSON response with a "status" key set to "ok".
"""

from fastapi import APIRouter

api_router = APIRouter()


@api_router.get("/health", tags=["Health"])
async def health_check():
"""
Simple health check endpoint. Returns a JSON response with a single key "status" and value "ok".
Simple health check endpoint.
Returns a JSON response with a single key "status" and value "ok".
"""
return {"status": "ok"}
Loading