pax_global_header 0000666 0000000 0000000 00000000064 15104460745 0014520 g ustar 00root root 0000000 0000000 52 comment=a6b2d3869f24c9c04cd7c024e59ccec3e5422a56
annotated-doc-0.0.4/ 0000775 0000000 0000000 00000000000 15104460745 0014241 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/.github/ 0000775 0000000 0000000 00000000000 15104460745 0015601 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/.github/DISCUSSION_TEMPLATE/ 0000775 0000000 0000000 00000000000 15104460745 0020557 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/.github/DISCUSSION_TEMPLATE/questions.yml 0000664 0000000 0000000 00000010176 15104460745 0023341 0 ustar 00root root 0000000 0000000 labels: [question]
body:
- type: markdown
attributes:
value: |
Thanks for your interest in the project! 🚀
Please follow these instructions, fill every question, and do every step. 🙏
I'm asking this because answering questions and solving problems in GitHub is what consumes most of the time.
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling questions.
By asking questions in a structured way (following this) it will be much easier to help you.
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
As there are too many questions, I'll have to discard and close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
- type: checkboxes
id: checks
attributes:
label: First Check
description: Please confirm and check all the following options.
options:
- label: I added a very descriptive title here.
required: true
- label: I used the GitHub search to find a similar question and didn't find it.
required: true
- label: I already searched in Google "How to X with annotated-doc" and didn't find any information.
required: true
- label: I already read and followed all the tutorial in the docs and didn't find an answer.
required: true
- label: I already checked if it is not related to annotated-doc but to [FastAPI](https://github.com/fastapi/fastapi) or another specific project.
required: true
- type: textarea
id: example
attributes:
label: Example Code
description: |
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.
If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you.
placeholder: |
from typing import Annotated
from annotated_doc import Doc
def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None:
print(f"Hi!")
render: python
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: |
What is the problem, question, or error?
Write a short description telling me what you are doing, what you expect to happen, and what is currently happening.
placeholder: |
* Create a function with one parameter documented with annotated-doc.
* Call the function with the parameter.
* I expected the code to do what the docs say, but it doesn't unless I implement that code.
validations:
required: true
- type: dropdown
id: os
attributes:
label: Operating System
description: What operating system are you on?
multiple: true
options:
- Linux
- Windows
- macOS
- Other
validations:
required: true
- type: textarea
id: os-details
attributes:
label: Operating System Details
description: You can add more details about your operating system here, in particular if you chose "Other".
- type: input
id: version
attributes:
label: Version
description: |
What version are you using?
You can find the version with:
```bash
python -c "import annotated_doc; print(annotated_doc.__version__)"
```
validations:
required: true
- type: input
id: python-version
attributes:
label: Python Version
description: |
What Python version are you using?
You can find the Python version with:
```bash
python --version
```
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional Context
description: Add any additional context information or screenshots you think are useful.
annotated-doc-0.0.4/.github/FUNDING.yml 0000664 0000000 0000000 00000000023 15104460745 0017411 0 ustar 00root root 0000000 0000000 github: [tiangolo]
annotated-doc-0.0.4/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 15104460745 0017764 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/.github/ISSUE_TEMPLATE/config.yml 0000664 0000000 0000000 00000001417 15104460745 0021757 0 ustar 00root root 0000000 0000000 blank_issues_enabled: false
contact_links:
- name: Security Contact
about: Please report security vulnerabilities to security@tiangolo.com
- name: Question or Problem
about: Ask a question or ask about a problem in GitHub Discussions.
url: https://github.com/fastapi/annotated-doc/discussions/categories/questions
- name: Feature Request
about: To suggest an idea or ask about a feature, please start with a question saying what you would like to achieve. There might be a way to do it already.
url: https://github.com/fastapi/annotated-doc/discussions/categories/questions
- name: Show and tell
about: Show what you built with annotated-doc and where you use it.
url: https://github.com/fastapi/annotated-doc/discussions/categories/show-and-tell
annotated-doc-0.0.4/.github/ISSUE_TEMPLATE/privileged.yml 0000664 0000000 0000000 00000001604 15104460745 0022642 0 ustar 00root root 0000000 0000000 name: Privileged
description: You are @tiangolo or he asked you directly to create an issue here. If not, check the other options. 👇
body:
- type: markdown
attributes:
value: |
Thanks for your interest in annotated-doc! 🚀
If you are not @tiangolo or he didn't ask you directly to create an issue here, please start the conversation in a [Question in GitHub Discussions](https://github.com/fastapi/annotated-doc/discussions/categories/questions) instead.
- type: checkboxes
id: privileged
attributes:
label: Privileged issue
description: Confirm that you are allowed to create an issue here.
options:
- label: I'm @tiangolo or he asked me directly to create an issue here.
required: true
- type: textarea
id: content
attributes:
label: Issue Content
description: Add the content of the issue here.
annotated-doc-0.0.4/.github/dependabot.yml 0000664 0000000 0000000 00000000466 15104460745 0020437 0 ustar 00root root 0000000 0000000 version: 2
updates:
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
commit-message:
prefix: ⬆
# Python
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "monthly"
commit-message:
prefix: ⬆
annotated-doc-0.0.4/.github/labeler.yml 0000664 0000000 0000000 00000000367 15104460745 0017740 0 ustar 00root root 0000000 0000000 internal:
- all:
- changed-files:
- any-glob-to-any-file:
- .github/**
- scripts/**
- .gitignore
- .pre-commit-config.yaml
- all-globs-to-all-files:
- '!src/**'
- '!pyproject.toml'
annotated-doc-0.0.4/.github/workflows/ 0000775 0000000 0000000 00000000000 15104460745 0017636 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/.github/workflows/add-to-project.yml 0000664 0000000 0000000 00000000570 15104460745 0023177 0 ustar 00root root 0000000 0000000 name: Add to Project
on:
pull_request_target:
issues:
types:
- opened
- reopened
jobs:
add-to-project:
name: Add to project
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@v1.0.2
with:
project-url: https://github.com/orgs/fastapi/projects/2
github-token: ${{ secrets.FASTAPI_PROJECTS_TOKEN }}
annotated-doc-0.0.4/.github/workflows/detect-conflicts.yml 0000664 0000000 0000000 00000000763 15104460745 0023621 0 ustar 00root root 0000000 0000000 name: Conflict detector
on:
push:
pull_request_target:
types:
- synchronize
jobs:
main:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Check if PRs have merge conflicts
uses: eps1lon/actions-label-merge-conflict@v3
with:
dirtyLabel: conflicts
repoToken: "${{ secrets.GITHUB_TOKEN }}"
commentOnDirty: This pull request has a merge conflict that needs to be resolved.
annotated-doc-0.0.4/.github/workflows/issue-manager.yml 0000664 0000000 0000000 00000003065 15104460745 0023125 0 ustar 00root root 0000000 0000000 name: Issue Manager
on:
schedule:
- cron: "13 22 * * *"
issue_comment:
types:
- created
issues:
types:
- labeled
pull_request_target:
types:
- labeled
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
issue-manager:
if: github.repository_owner == 'fastapi'
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: tiangolo/issue-manager@0.6.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
config: >
{
"answered": {
"delay": 864000,
"message": "Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs."
},
"waiting": {
"delay": 2628000,
"message": "As this PR has been waiting for the original user for a while but seems to be inactive, it's now going to be closed. But if there's anyone interested, feel free to create a new PR.",
"reminder": {
"before": "P3D",
"message": "Heads-up: this will be closed in 3 days unless there's new activity."
}
},
"invalid": {
"delay": 0,
"message": "This was marked as invalid and will be closed now. If this is an error, please provide additional details."
}
}
annotated-doc-0.0.4/.github/workflows/labeler.yml 0000664 0000000 0000000 00000001474 15104460745 0021775 0 ustar 00root root 0000000 0000000 name: Labels
on:
pull_request_target:
types:
- opened
- synchronize
- reopened
# For label-checker
- labeled
- unlabeled
jobs:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v6
if: ${{ github.event.action != 'labeled' && github.event.action != 'unlabeled' }}
- run: echo "Done adding labels"
# Run this after labeler applied labels
check-labels:
needs:
- labeler
permissions:
pull-requests: read
runs-on: ubuntu-latest
steps:
- uses: docker://agilepathway/pull-request-label-checker:latest
with:
one_of: breaking,security,feature,bug,refactor,upgrade,docs,lang-all,internal
repo_token: ${{ secrets.GITHUB_TOKEN }}
annotated-doc-0.0.4/.github/workflows/latest-changes.yml 0000664 0000000 0000000 00000002466 15104460745 0023273 0 ustar 00root root 0000000 0000000 name: Latest Changes
on:
pull_request_target:
branches:
- main
types:
- closed
workflow_dispatch:
inputs:
number:
description: PR number
required: true
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: 'false'
jobs:
latest-changes:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v5
with:
# To allow latest-changes to commit to the main branch
token: ${{ secrets.ANNOTATED_DOC_LATEST_CHANGES }}
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- uses: tiangolo/latest-changes@0.4.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
latest_changes_file: release-notes.md
latest_changes_header: '## Latest Changes'
end_regex: '^## '
debug_logs: true
label_header_prefix: '### '
annotated-doc-0.0.4/.github/workflows/publish.yml 0000664 0000000 0000000 00000001377 15104460745 0022037 0 ustar 00root root 0000000 0000000 name: Publish
on:
release:
types:
- created
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"
- name: Install build dependencies
run: pip install build
- name: Build distribution
run: python -m build
- name: Publish
uses: pypa/gh-action-pypi-publish@v1.13.0
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
annotated-doc-0.0.4/.github/workflows/smokeshow.yml 0000664 0000000 0000000 00000003404 15104460745 0022401 0 ustar 00root root 0000000 0000000 name: Smokeshow
on:
workflow_run:
workflows:
- Test
types:
- completed
permissions:
statuses: write
env:
UV_SYSTEM_PYTHON: 1
jobs:
smokeshow:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.9'
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
- run: uv pip install -r requirements-tests.txt
- uses: actions/download-artifact@v6
with:
name: coverage-html
path: htmlcov
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
# Try 5 times to upload coverage to smokeshow
- name: Upload coverage to Smokeshow
run: |
for i in 1 2 3 4 5; do
if smokeshow upload htmlcov; then
echo "Smokeshow upload success!"
break
fi
echo "Smokeshow upload error, sleep 1 sec and try again."
sleep 1
done
env:
SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 100
SMOKESHOW_GITHUB_CONTEXT: coverage
SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
SMOKESHOW_AUTH_KEY: ${{ secrets.SMOKESHOW_AUTH_KEY }}
annotated-doc-0.0.4/.github/workflows/test-redistribute.yml 0000664 0000000 0000000 00000003033 15104460745 0024042 0 ustar 00root root 0000000 0000000 name: Test Redistribute
on:
push:
branches:
- main
pull_request:
types:
- opened
- synchronize
env:
UV_SYSTEM_PYTHON: 1
jobs:
test-redistribute:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"
- name: Install build dependencies
run: pip install build
- name: Build source distribution
run: python -m build --sdist
- name: Decompress source distribution
run: |
cd dist
tar xvf annotated_doc*.tar.gz
- name: Install test dependencies
run: |
cd dist/annotated_doc*/
pip install -r requirements-tests.txt
- name: Run source distribution tests
run: |
cd dist/annotated_doc*/
bash scripts/test.sh
- name: Build wheel distribution
run: |
cd dist
pip wheel --no-deps annotated_doc*.tar.gz
# https://github.com/marketplace/actions/alls-green#why
test-redistribute-alls-green: # This job does nothing and is only used for the branch protection
if: always()
needs:
- test-redistribute
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}
annotated-doc-0.0.4/.github/workflows/test.yml 0000664 0000000 0000000 00000010034 15104460745 0021336 0 ustar 00root root 0000000 0000000 name: Test
on:
push:
branches:
- main
pull_request:
types:
- opened
- synchronize
workflow_dispatch:
inputs:
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: 'false'
schedule:
# cron every week on monday
- cron: "0 0 * * 1"
env:
UV_SYSTEM_PYTHON: 1
jobs:
test:
strategy:
matrix:
os:
- ubuntu-latest
- windows-latest
- macos-latest
python-version:
- "3.14"
include:
- os: macos-latest
python-version: "3.8"
- os: windows-latest
python-version: "3.9"
- os: ubuntu-latest
python-version: "3.10"
- os: macos-latest
python-version: "3.11"
- os: windows-latest
python-version: "3.12"
- os: ubuntu-latest
python-version: "3.13"
- os: macos-latest
python-version: "3.13"
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- name: Install Dependencies
run: uv pip install -r requirements-tests.txt
- name: Lint
run: bash scripts/lint.sh
- run: mkdir coverage
- name: Test
run: bash scripts/test.sh
env:
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
- name: Store coverage files
uses: actions/upload-artifact@v5
with:
name: coverage-${{ runner.os }}-${{ matrix.python-version }}
path: coverage
include-hidden-files: true
coverage-combine:
needs:
- test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
- name: Get coverage files
uses: actions/download-artifact@v6
with:
pattern: coverage-*
path: coverage
merge-multiple: true
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- name: Install Dependencies
run: uv pip install -r requirements-tests.txt
- run: ls -la coverage
- run: coverage combine coverage
- run: coverage report
- run: coverage html --title "Coverage for ${{ github.sha }}"
- name: Store coverage HTML
uses: actions/upload-artifact@v5
with:
name: coverage-html
path: htmlcov
include-hidden-files: true
# https://github.com/marketplace/actions/alls-green#why
alls-green: # This job does nothing and is only used for the branch protection
if: always()
needs:
- coverage-combine
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}
annotated-doc-0.0.4/.gitignore 0000664 0000000 0000000 00000000214 15104460745 0016226 0 ustar 00root root 0000000 0000000 # Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# Virtual environments
.venv
# Coverage
htmlcov
.coverage*
annotated-doc-0.0.4/.pre-commit-config.yaml 0000664 0000000 0000000 00000001336 15104460745 0020525 0 ustar 00root root 0000000 0000000 # See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
default_language_version:
python: python3.10
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-added-large-files
- id: check-toml
- id: check-yaml
args:
- --unsafe
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.13.3
hooks:
- id: ruff
args:
- --fix
- id: ruff-format
ci:
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
annotated-doc-0.0.4/CITATION.cff 0000664 0000000 0000000 00000001246 15104460745 0016136 0 ustar 00root root 0000000 0000000 # This CITATION.cff file was generated with cffinit.
# Visit https://bit.ly/cffinit to generate yours today!
cff-version: 1.2.0
title: annotated-doc
message: >-
If you use this software, please cite it using the metadata from this file.
type: software
authors:
- given-names: Sebastián
family-names: Ramírez
email: tiangolo@gmail.com
identifiers:
repository-code: 'https://github.com/fastapi/annotated-doc'
url: 'https://github.com/fastapi/annotated-doc'
abstract: >-
Document parameters, class attributes, return types, and variables inline, with Annotated.
keywords:
- annotated
- documentation
- fastapi
- typer
- sqlmodel
- asyncer
license: MIT
annotated-doc-0.0.4/LICENSE 0000664 0000000 0000000 00000002076 15104460745 0015253 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2025 Sebastián Ramírez
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
annotated-doc-0.0.4/README.md 0000664 0000000 0000000 00000011322 15104460745 0015517 0 ustar 00root root 0000000 0000000 # Annotated Doc
Document parameters, class attributes, return types, and variables inline, with `Annotated`.
## Installation
```bash
pip install annotated-doc
```
Or with `uv`:
```Python
uv add annotated-doc
```
## Usage
Import `Doc` and pass a single literal string with the documentation for the specific parameter, class attribute, return type, or variable.
For example, to document a parameter `name` in a function `hi` you could do:
```Python
from typing import Annotated
from annotated_doc import Doc
def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None:
print(f"Hi, {name}!")
```
You can also use it to document class attributes:
```Python
from typing import Annotated
from annotated_doc import Doc
class User:
name: Annotated[str, Doc("The user's name")]
age: Annotated[int, Doc("The user's age")]
```
The same way, you could document return types and variables, or anything that could have a type annotation with `Annotated`.
## Who Uses This
`annotated-doc` was made for:
* [FastAPI](https://fastapi.tiangolo.com/)
* [Typer](https://typer.tiangolo.com/)
* [SQLModel](https://sqlmodel.tiangolo.com/)
* [Asyncer](https://asyncer.tiangolo.com/)
`annotated-doc` is supported by [griffe-typingdoc](https://github.com/mkdocstrings/griffe-typingdoc), which powers reference documentation like the one in the [FastAPI Reference](https://fastapi.tiangolo.com/reference/).
## Reasons not to use `annotated-doc`
You are already comfortable with one of the existing docstring formats, like:
* Sphinx
* numpydoc
* Google
* Keras
Your team is already comfortable using them.
You prefer having the documentation about parameters all together in a docstring, separated from the code defining them.
You care about a specific set of users, using one specific editor, and that editor already has support for the specific docstring format you use.
## Reasons to use `annotated-doc`
* No micro-syntax to learn for newcomers, it’s **just Python** syntax.
* **Editing** would be already fully supported by default by any editor (current or future) supporting Python syntax, including syntax errors, syntax highlighting, etc.
* **Rendering** would be relatively straightforward to implement by static tools (tools that don't need runtime execution), as the information can be extracted from the AST they normally already create.
* **Deduplication of information**: the name of a parameter would be defined in a single place, not duplicated inside of a docstring.
* **Elimination** of the possibility of having **inconsistencies** when removing a parameter or class variable and **forgetting to remove** its documentation.
* **Minimization** of the probability of adding a new parameter or class variable and **forgetting to add its documentation**.
* **Elimination** of the possibility of having **inconsistencies** between the **name** of a parameter in the **signature** and the name in the docstring when it is renamed.
* **Access** to the documentation string for each symbol at **runtime**, including existing (older) Python versions.
* A more formalized way to document other symbols, like type aliases, that could use Annotated.
* **Support** for apps using FastAPI, Typer and others.
* **AI Accessibility**: AI tools will have an easier way understanding each parameter as the distance from documentation to parameter is much closer.
## History
I ([@tiangolo](https://github.com/tiangolo)) originally wanted for this to be part of the Python standard library (in [PEP 727](https://peps.python.org/pep-0727/)), but the proposal was withdrawn as there was a fair amount of negative feedback and opposition.
The conclusion was that this was better done as an external effort, in a third-party library.
So, here it is, with a simpler approach, as a third-party library, in a way that can be used by others, starting with FastAPI and friends.
## License
This project is licensed under the terms of the MIT license.
annotated-doc-0.0.4/pyproject.toml 0000664 0000000 0000000 00000005543 15104460745 0017164 0 ustar 00root root 0000000 0000000 [project]
name = "annotated-doc"
dynamic = ["version"]
license = "MIT"
license-files = ["LICENSE"]
description = "Document parameters, class attributes, return types, and variables inline, with Annotated."
readme = "README.md"
authors = [
{ name = "Sebastián Ramírez", email = "tiangolo@gmail.com" }
]
requires-python = ">=3.8"
classifiers = [
"Intended Audience :: Information Technology",
"Intended Audience :: System Administrators",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python",
"Topic :: Internet",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development",
"Typing :: Typed",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]
dependencies = []
[project.urls]
Homepage = "https://github.com/fastapi/annotated-doc"
Documentation = "https://github.com/fastapi/annotated-doc"
Repository = "https://github.com/fastapi/annotated-doc"
Issues = "https://github.com/fastapi/annotated-doc/issues"
Changelog = "https://github.com/fastapi/annotated-doc/release-notes.md"
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"
[tool.mypy]
strict = true
[tool.pytest.ini_options]
addopts = [
"--strict-config",
"--strict-markers",
]
xfail_strict = true
junit_family = "xunit2"
[tool.coverage.run]
parallel = true
data_file = "coverage/.coverage"
source = [
"src/annotated_doc",
"tests",
]
context = '${CONTEXT}'
dynamic_context = "test_function"
relative_files = true
[tool.coverage.report]
show_missing = true
sort = "-Cover"
[tool.coverage.html]
show_contexts = true
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = [
"E501", # line too long, handled by black
"B008", # do not perform function calls in argument defaults
"C901", # too complex
"W191", # indentation contains tabs
]
[tool.ruff.lint.pyupgrade]
# Preserve types, even if a file imports `from __future__ import annotations`.
keep-runtime-typing = true
[tool.pdm]
version = { source = "file", path = "src/annotated_doc/__init__.py" }
distribution = true
[tool.pdm.build]
source-includes = [
"tests/",
"requirements*.txt",
"scripts/",
]
annotated-doc-0.0.4/release-notes.md 0000664 0000000 0000000 00000004450 15104460745 0017334 0 ustar 00root root 0000000 0000000 # Release Notes
## Latest Changes
## 0.0.4
### Fixes
* 👷 Switch to dynamic versioning with `pdm` build system. PR [#19](https://github.com/fastapi/annotated-doc/pull/19) by [@svlandeg](https://github.com/svlandeg).
### Upgrades
* ⬆ Bump ruff from 0.14.1 to 0.14.3. PR [#17](https://github.com/fastapi/annotated-doc/pull/17) by [@dependabot[bot]](https://github.com/apps/dependabot).
### Internal
* ➕ Add `typing-extensions` to test requirements for Python < 3.9. PR [#12](https://github.com/fastapi/annotated-doc/pull/12) by [@musicinmybrain](https://github.com/musicinmybrain).
* ⬆ Bump actions/upload-artifact from 4 to 5. PR [#14](https://github.com/fastapi/annotated-doc/pull/14) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump actions/download-artifact from 5 to 6. PR [#13](https://github.com/fastapi/annotated-doc/pull/13) by [@dependabot[bot]](https://github.com/apps/dependabot).
## 0.0.3
### Docs
* 📝 Add mention to `griffe-typingdoc`. PR [#10](https://github.com/fastapi/annotated-doc/pull/10) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update README with use cases. PR [#9](https://github.com/fastapi/annotated-doc/pull/9) by [@tiangolo](https://github.com/tiangolo).
* 📝 Add badges to docs. PR [#8](https://github.com/fastapi/annotated-doc/pull/8) by [@tiangolo](https://github.com/tiangolo).
### Internal
* 🔧 Add PEP-639 license metadata. PR [#11](https://github.com/fastapi/annotated-doc/pull/11) by [@bollwyvl](https://github.com/bollwyvl).
## 0.0.2
### Features
* ✨ Add implementation.
### Internal
* ✅ Migrate/add tests. PR [#7](https://github.com/fastapi/annotated-doc/pull/7) by [@tiangolo](https://github.com/tiangolo).
* 👷 Add setup to run tests on CI. PR [#6](https://github.com/fastapi/annotated-doc/pull/6) by [@tiangolo](https://github.com/tiangolo).
* 👷 Add templates and admin CI workflows. PR [#3](https://github.com/fastapi/annotated-doc/pull/3) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Add configs for `.github`. PR [#1](https://github.com/fastapi/annotated-doc/pull/1) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update latest-changes config to point to `main` as the main branch. PR [#2](https://github.com/fastapi/annotated-doc/pull/2) by [@tiangolo](https://github.com/tiangolo).
## 0.0.1
Reserve PyPI package.
annotated-doc-0.0.4/requirements-tests.txt 0000664 0000000 0000000 00000000204 15104460745 0020661 0 ustar 00root root 0000000 0000000 -e .
pytest >=8.3.5
typing-extensions; python_version < "3.9"
coverage[toml] >=7.6.1
mypy ==1.14.1
ruff ==0.14.3
smokeshow >=0.5.0
annotated-doc-0.0.4/scripts/ 0000775 0000000 0000000 00000000000 15104460745 0015730 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/scripts/coverage.sh 0000775 0000000 0000000 00000000123 15104460745 0020056 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
set -e
set -x
coverage combine
coverage report
coverage html
annotated-doc-0.0.4/scripts/format.sh 0000775 0000000 0000000 00000000135 15104460745 0017556 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
set -x
ruff check src tests scripts --fix
ruff format src tests scripts
annotated-doc-0.0.4/scripts/lint.sh 0000775 0000000 0000000 00000000150 15104460745 0017231 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
set -e
set -x
mypy src
ruff check src tests scripts
ruff format src tests --check
annotated-doc-0.0.4/scripts/test-cov-html.sh 0000775 0000000 0000000 00000000127 15104460745 0020775 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
set -e
set -x
bash scripts/test.sh ${@}
bash scripts/coverage.sh
annotated-doc-0.0.4/scripts/test.sh 0000775 0000000 0000000 00000000106 15104460745 0017243 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
set -e
set -x
coverage run -m pytest tests ${@}
annotated-doc-0.0.4/src/ 0000775 0000000 0000000 00000000000 15104460745 0015030 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/src/annotated_doc/ 0000775 0000000 0000000 00000000000 15104460745 0017632 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/src/annotated_doc/__init__.py 0000664 0000000 0000000 00000000064 15104460745 0021743 0 ustar 00root root 0000000 0000000 from .main import Doc as Doc
__version__ = "0.0.4"
annotated-doc-0.0.4/src/annotated_doc/main.py 0000664 0000000 0000000 00000002063 15104460745 0021131 0 ustar 00root root 0000000 0000000 class Doc:
"""Define the documentation of a type annotation using `Annotated`, to be
used in class attributes, function and method parameters, return values,
and variables.
The value should be a positional-only string literal to allow static tools
like editors and documentation generators to use it.
This complements docstrings.
The string value passed is available in the attribute `documentation`.
Example:
```Python
from typing import Annotated
from annotated_doc import Doc
def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None:
print(f"Hi, {name}!")
```
"""
def __init__(self, documentation: str, /) -> None:
self.documentation = documentation
def __repr__(self) -> str:
return f"Doc({self.documentation!r})"
def __hash__(self) -> int:
return hash(self.documentation)
def __eq__(self, other: object) -> bool:
if not isinstance(other, Doc):
return NotImplemented
return self.documentation == other.documentation
annotated-doc-0.0.4/src/annotated_doc/py.typed 0000664 0000000 0000000 00000000000 15104460745 0021317 0 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/tests/ 0000775 0000000 0000000 00000000000 15104460745 0015403 5 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/tests/__init__.py 0000664 0000000 0000000 00000000000 15104460745 0017502 0 ustar 00root root 0000000 0000000 annotated-doc-0.0.4/tests/test_main.py 0000664 0000000 0000000 00000003346 15104460745 0017746 0 ustar 00root root 0000000 0000000 import pickle
import sys
from annotated_doc import Doc
if sys.version_info >= (3, 9):
from typing import Annotated, get_type_hints
else:
from typing_extensions import Annotated, get_type_hints
def test_doc_basic() -> None:
doc = Doc("This is a test documentation.")
assert doc.documentation == "This is a test documentation."
assert repr(doc) == "Doc('This is a test documentation.')"
assert hash(doc) == hash("This is a test documentation.")
assert doc == Doc("This is a test documentation.")
assert doc != Doc("Different documentation.")
assert doc != "Not a Doc instance"
def test_annotation():
def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None: # pragma: no cover
pass
hints = get_type_hints(hi, include_extras=True)
doc_info: Doc = hints["name"].__metadata__[0]
assert doc_info.documentation == "Who to say hi to"
assert isinstance(doc_info, Doc)
def test_repr():
doc_info = Doc("Who to say hi to")
assert repr(doc_info) == "Doc('Who to say hi to')"
def test_hashability():
doc_info = Doc("Who to say hi to")
assert isinstance(hash(doc_info), int)
assert hash(doc_info) != hash(Doc("Who not to say hi to"))
def test_equality():
doc_info = Doc("Who to say hi to")
# Equal to itself
assert doc_info == doc_info
# Equal to another instance with the same string
assert doc_info == Doc("Who to say hi to")
# Not equal to another instance with a different string
assert doc_info != Doc("Who not to say hi to")
def test_pickle():
doc_info = Doc("Who to say hi to")
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
pickled = pickle.dumps(doc_info, protocol=proto)
assert doc_info == pickle.loads(pickled)