Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: encode/starlette
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0.46.0
Choose a base ref
...
head repository: encode/starlette
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0.46.1
Choose a head ref
  • 5 commits
  • 10 files changed
  • 5 contributors

Commits on Mar 4, 2025

  1. Document how to configure CORSMiddleware globally (#2885)

    timothy-jeong authored Mar 4, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    708930c View commit details
  2. Bump the python-packages group with 6 updates (#2894)

    Bumps the python-packages group with 6 updates:
    
    | Package | From | To |
    | --- | --- | --- |
    | [coverage](https://github.com/nedbat/coveragepy) | `7.6.10` | `7.6.12` |
    | [mypy](https://github.com/python/mypy) | `1.14.1` | `1.15.0` |
    | [ruff](https://github.com/astral-sh/ruff) | `0.9.4` | `0.9.9` |
    | [trio](https://github.com/python-trio/trio) | `0.28.0` | `0.29.0` |
    | [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | `9.6.5` | `9.6.6` |
    | [mkdocstrings-python](https://github.com/mkdocstrings/python) | `1.13.0` | `1.16.2` |
    
    
    Updates `coverage` from 7.6.10 to 7.6.12
    - [Release notes](https://github.com/nedbat/coveragepy/releases)
    - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
    - [Commits](nedbat/coveragepy@7.6.10...7.6.12)
    
    Updates `mypy` from 1.14.1 to 1.15.0
    - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
    - [Commits](python/mypy@v1.14.1...v1.15.0)
    
    Updates `ruff` from 0.9.4 to 0.9.9
    - [Release notes](https://github.com/astral-sh/ruff/releases)
    - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
    - [Commits](astral-sh/ruff@0.9.4...0.9.9)
    
    Updates `trio` from 0.28.0 to 0.29.0
    - [Release notes](https://github.com/python-trio/trio/releases)
    - [Commits](python-trio/trio@v0.28.0...v0.29.0)
    
    Updates `mkdocs-material` from 9.6.5 to 9.6.6
    - [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
    - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
    - [Commits](squidfunk/mkdocs-material@9.6.5...9.6.6)
    
    Updates `mkdocstrings-python` from 1.13.0 to 1.16.2
    - [Release notes](https://github.com/mkdocstrings/python/releases)
    - [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md)
    - [Commits](mkdocstrings/python@1.13.0...1.16.2)
    
    ---
    updated-dependencies:
    - dependency-name: coverage
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: python-packages
    - dependency-name: mypy
      dependency-type: direct:production
      update-type: version-update:semver-minor
      dependency-group: python-packages
    - dependency-name: ruff
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: python-packages
    - dependency-name: trio
      dependency-type: direct:production
      update-type: version-update:semver-minor
      dependency-group: python-packages
    - dependency-name: mkdocs-material
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: python-packages
    - dependency-name: mkdocstrings-python
      dependency-type: direct:production
      update-type: version-update:semver-minor
      dependency-group: python-packages
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
    dependabot[bot] and Kludex authored Mar 4, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    4915873 View commit details

Commits on Mar 8, 2025

  1. Allow relative directory path when follow_symlinks=True (#2896)

    * Fix for StaticFiles(follow_symlinks=True, directory="some relative path") that stopped working with commit eee4cdc
    
    * Change test name
    
    * Delete test parameter
    
    ---------
    
    Co-authored-by: Bruno D. Rodrigues <bruno.rodrigues@bitsighttech.com>
    Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
    3 people authored Mar 8, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    bc3b400 View commit details
  2. Add sponsorship page (#2899)

    * Add sponsorship page
    
    * push note about removing name
    Kludex authored Mar 8, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    9b704ac View commit details
  3. Version 0.46.1 (#2900)

    Kludex authored Mar 8, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    df754ca View commit details
Showing with 254 additions and 9 deletions.
  1. +1 −1 .github/FUNDING.yml
  2. +19 −0 docs/index.md
  3. +25 −0 docs/middleware.md
  4. +6 −0 docs/release-notes.md
  5. +185 −1 docs/sponsorship.md
  6. +2 −0 mkdocs.yml
  7. +6 −6 requirements.txt
  8. +1 −1 starlette/__init__.py
  9. +1 −0 starlette/staticfiles.py
  10. +8 −0 tests/test_staticfiles.py
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github: encode
github: Kludex
19 changes: 19 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -45,6 +45,25 @@ It is production-ready, and gives you the following:
* Compatible with `asyncio` and `trio` backends.
* Great overall performance [against independent benchmarks][techempower].


## Sponsorship

Starlette is an open-source project that relies on community support. You can help us maintain and improve the framework by [becoming a sponsor](/sponsorship).

<div style="text-align: center; margin: 2rem 0;">
<h4 style="color: #ffd700; margin-bottom: 1rem;">🏆 Our Gold Sponsor</h4>
<a href="https://fastapi.tiangolo.com" style="text-decoration: none;">
<div style="width: 200px; background: #f6f8fa; border-radius: 8px; padding: 1rem; text-align: center; margin: 0 auto;">
<div style="height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 0.75rem;">
<img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI" style="max-width: 100%; max-height: 100%; object-fit: contain;">
</div>
<p style="margin: 0; color: #57606a; font-size: 0.9em;">Modern, fast web framework for building APIs with Python 3.8+</p>
</div>
</a>
</div>



## Installation

```shell
25 changes: 25 additions & 0 deletions docs/middleware.md
Original file line number Diff line number Diff line change
@@ -92,6 +92,31 @@ appropriate CORS headers, and either a 200 or 400 response for informational pur
Any request with an `Origin` header. In this case the middleware will pass the
request through as normal, but will include appropriate CORS headers on the response.

### CORSMiddleware Global Enforcement

When using CORSMiddleware with your Starlette application, it's important to ensure that CORS headers are applied even to error responses generated by unhandled exceptions. The recommended solution is to wrap the entire Starlette application with CORSMiddleware. This approach guarantees that even if an exception is caught by ServerErrorMiddleware (or other outer error-handling middleware), the response will still include the proper `Access-Control-Allow-Origin` header.

For example, instead of adding CORSMiddleware as an inner `middleware` via the Starlette middleware parameter, you can wrap your application as follows:

```python
from starlette.applications import Starlette
from starlette.middleware.cors import CORSMiddleware

import uvicorn

app = Starlette()
app = CORSMiddleware(app=app, allow_origins=["*"])

# ... your routes and middleware configuration ...

if __name__ == '__main__':
uvicorn.run(
app,
host='0.0.0.0',
port=8000
)
```

## SessionMiddleware

Adds signed cookie-based HTTP sessions. Session information is readable but not modifiable.
6 changes: 6 additions & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,12 @@
toc_depth: 2
---

## 0.46.1 (March 8, 2025)

#### Fixed

* Allow relative directory path when `follow_symlinks=True` [#2896](https://github.com/encode/starlette/pull/2896).

## 0.46.0 (February 22, 2025)

#### Added
186 changes: 185 additions & 1 deletion docs/sponsorship.md
Original file line number Diff line number Diff line change
@@ -1 +1,185 @@
# Coming soon...
# ✨ Sponsor Starlette & Uvicorn ✨

Thank you for your interest in sponsoring Starlette and Uvicorn! ❤️

Your support *directly* contributes to the ongoing development, maintenance, and long-term sustainability of both projects.

<div style="display: flex; justify-content: center; gap: 4rem; margin: 2rem 0; text-align: center;">
<div style="padding: 1rem;">
<h3 style="color: #6e5494; font-size: 2em; margin-bottom: 0.5rem;">67M+</h3>
<p>Starlette Downloads/Month</p>
</div>
<div style="padding: 1rem;">
<h3 style="color: #6e5494; font-size: 2em; margin-bottom: 0.5rem;">57M+</h3>
<p>Uvicorn Downloads/Month</p>
</div>
<div style="padding: 1rem;">
<h3 style="color: #6e5494; font-size: 2em; margin-bottom: 0.5rem;">19K+</h3>
<p>Combined GitHub Stars</p>
</div>
</div>

## Why Sponsor?

While Starlette and Uvicorn are part of the [Encode](https://github.com/encode) organization,
they have been primarily maintained by [**Marcelo Trylesinski (Kludex)**](https://github.com/Kludex)
for the past several years. His dedication and consistent work have been instrumental in keeping
these projects robust, secure, and up-to-date.

This sponsorship page was created to give the community an opportunity to support Marcelo's continued
efforts in maintaining and improving both projects. Your sponsorship directly enables him to
dedicate more time and resources to maintaining and improving these essential tools:

- [x] **Active Development:** Developing new features, enhancing existing ones, and
keeping both projects aligned with the latest developments in the Python and ASGI ecosystems. 💻
- [x] **Community Support:** Providing better support, addressing user issues,
and cultivating a welcoming environment for contributors. 🤝
- [x] **Long-Term Stability:** Ensuring the long-term viability of both projects through strategic
planning and addressing technical debt. 🌳
- [x] **Bug Fixes & Maintenance:** Providing prompt attention to bug reports and
general maintenance to keep the projects reliable. 🔨
- [x] **Security:** Ensuring robust security practices, conducting regular security audits, and
promptly addressing vulnerabilities to protect millions of production deployments. 🔒
- [x] **Documentation:** Creating comprehensive guides, tutorials, and examples to help users of all skill levels. 📖

## How Sponsorship Works

We currently manage sponsorships *exclusively* through **GitHub Sponsors**. This platform integrates seamlessly with the GitHub ecosystem, making it easy for organizations to contribute.

<div style="text-align: center; padding: 2rem; margin: 2rem 0; background: linear-gradient(135deg, #6e5494, #24292e); border-radius: 10px; color: white;">
<h2 style="color: white; margin-bottom: 1rem;">🌟 Become a Sponsor Today! 🌟</h2>
<p style="margin-bottom: 1.5rem; font-size: 1.1em;">Your support helps keep Starlette and Uvicorn growing stronger!</p>
<a href="https://github.com/sponsors/Kludex"
style="display: inline-block; padding: 1rem 2rem; background-color: #238636; color: white; text-decoration: none; border-radius: 6px; font-size: 1.2em; font-weight: bold; transition: all 0.3s ease-in-out;"
onmouseover="this.style.backgroundColor='#2ea043';this.style.transform='translateY(-2px)'"
onmouseout="this.style.backgroundColor='#238636';this.style.transform='translateY(0)'">
❤️ Sponsor on GitHub
</a>
</div>

## Sponsorship Tiers 🎁

<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin: 2rem 0;">
<div style="padding: 1.5rem; border: 1px solid #e1e4e8; border-radius: 6px; background: #fff; display: flex; flex-direction: column;">
<h3 style="color: #cd7f32;">🥉 Bronze Sponsor</h3>
<div style="font-size: 1.5em; margin: 1rem 0;">$100<span style="font-size: 0.6em;">/month</span></div>
<ul style="list-style: none; padding: 0; margin-bottom: 1rem; min-height: 90px;">
<li>✓ Company name on Sponsors page</li>
<li>✓ Small logo with link</li>
<li>✓ Our eternal gratitude</li>
</ul>
<div style="text-align: center; margin-top: auto;">
<a href="https://github.com/sponsors/Kludex" style="display: inline-block; padding: 0.5rem 1rem; background-color: #cd7f32; color: white; text-decoration: none; border-radius: 6px; font-weight: bold; transition: opacity 0.2s;" onmouseover="this.style.opacity='0.8'" onmouseout="this.style.opacity='1'">
Become a Bronze Sponsor
</a>
</div>
</div>
<div style="padding: 1.5rem; border: 1px solid #e1e4e8; border-radius: 6px; background: #fff; display: flex; flex-direction: column;">
<h3 style="color: #c0c0c0;">🥈 Silver Sponsor</h3>
<div style="font-size: 1.5em; margin: 1rem 0;">$250<span style="font-size: 0.6em;">/month</span></div>
<ul style="list-style: none; padding: 0; margin-bottom: 1rem; min-height: 90px;">
<li>✓ All Bronze benefits</li>
<li>✓ Medium-sized logo</li>
<li>✓ Release notes mention</li>
</ul>
<div style="text-align: center; margin-top: auto;">
<a href="https://github.com/sponsors/Kludex" style="display: inline-block; padding: 0.5rem 1rem; background-color: #c0c0c0; color: white; text-decoration: none; border-radius: 6px; font-weight: bold; transition: opacity 0.2s;" onmouseover="this.style.opacity='0.8'" onmouseout="this.style.opacity='1'">
Become a Silver Sponsor
</a>
</div>
</div>
<div style="padding: 1.5rem; border: 1px solid #e1e4e8; border-radius: 6px; background: #fff; position: relative; overflow: hidden; display: flex; flex-direction: column;">
<div style="position: absolute; top: 10px; right: -25px; background: #238636; color: white; padding: 5px 30px; transform: rotate(45deg);">
Popular
</div>
<h3 style="color: #ffd700;">🥇 Gold Sponsor</h3>
<div style="font-size: 1.5em; margin: 1rem 0;">$500<span style="font-size: 0.6em;">/month</span></div>
<ul style="list-style: none; padding: 0; margin-bottom: 1rem; min-height: 90px;">
<li>✓ All Silver benefits</li>
<li>✓ Large logo on main pages</li>
<li>✓ Priority support</li>
</ul>
<div style="text-align: center; margin-top: auto;">
<a href="https://github.com/sponsors/Kludex" style="display: inline-block; padding: 0.5rem 1rem; background-color: #ffd700; color: black; text-decoration: none; border-radius: 6px; font-weight: bold; transition: opacity 0.2s;" onmouseover="this.style.opacity='0.8'" onmouseout="this.style.opacity='1'">
Become a Gold Sponsor
</a>
</div>
</div>
</div>

<div style="text-align: center; margin: 2rem 0;">
<h3>🤝 Custom Sponsor</h3>
<p>Looking for something different? <a href="mailto:your-email@example.com">Contact us</a> to discuss custom sponsorship options!</p>
</div>

## Current Sponsors

**Thank you to our generous sponsors!** 🙏

<div style="display: flex; flex-direction: column; gap: 3rem; margin: 2rem 0;">
<div>
<h3 style="text-align: center; color: #ffd700; margin-bottom: 1.5rem;">🏆 Gold Sponsors</h3>
<div style="display: flex; flex-wrap: wrap; justify-content: center; gap: 2rem; align-items: center;">
<a href="https://fastapi.tiangolo.com" style="text-decoration: none;">
<div style="width: 200px; background: #f6f8fa; border-radius: 8px; padding: 1rem; text-align: center;">
<div style="height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 0.75rem;">
<img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI" style="max-width: 100%; max-height: 100%; object-fit: contain;">
</div>
<p style="margin: 0; color: #57606a; font-size: 0.9em;">Modern, fast web framework for building APIs with Python 3.8+</p>
</div>
</a>
</div>
</div>

<div>
<h3 style="text-align: center; color: #c0c0c0; margin-bottom: 1.5rem;">🥈 Silver Sponsors</h3>
<div style="display: flex; flex-wrap: wrap; justify-content: center; gap: 2rem; align-items: center;">
<!-- Add Silver Sponsors here -->
</div>
</div>

<div>
<h3 style="text-align: center; color: #cd7f32; margin-bottom: 1.5rem;">🥉 Bronze Sponsors</h3>
<div style="display: flex; flex-wrap: wrap; justify-content: center; gap: 2rem; align-items: center;">
<!-- Add Bronze Sponsors here -->
</div>
</div>
</div>

## Alternative Sponsorship Platforms

<div style="background: #f6f8fa; padding: 1.5rem; border-radius: 8px; margin: 2rem 0;">
<h3>📢 We Want Your Input!</h3>
<p>We are currently evaluating whether to expand our sponsorship options beyond GitHub Sponsors. If your company would be interested in sponsoring Starlette and Uvicorn but prefers to use a different platform (e.g., Open Collective, direct invoicing), please let us know!</p>
<p>Your feedback is invaluable in helping us make sponsorship as accessible as possible. Share your thoughts by:</p>
<ul>
<li>Opening a discussion on our <a href="https://github.com/encode/starlette/discussions">GitHub repository</a></li>
<li>Contacting us directly at <a href="mailto:marcelotryle@gmail.com">marcelotryle@gmail.com</a></li>
</ul>
</div>

<a id="acknowledgments"></a>

## Community & Future Plans 🌟

We want to express our deepest gratitude to all the contributors who have helped shape Starlette and
Uvicorn over the years. These projects wouldn't be what they are today without the incredible work of
every single contributor.

Special thanks to some of our most impactful contributors:

- **Tom Christie** ([@tomchristie](https://github.com/tomchristie)) - The original creator of Starlette and Uvicorn.
- **Adrian Garcia Badaracco** ([@adriangb](https://github.com/adriangb)) - Major contributor to Starlette.
- **Thomas Grainger** ([@graingert](https://github.com/graingert)) - Major contributor to AnyIO, and significant contributions to Starlette and Uvicorn.
- **Alex Grönholm** ([@AlexGrönholm](https://github.com/agronholm)) - Creator of AnyIO.
- **Florimond Manca** ([@florimondmanca](https://github.com/florimondmanca)) - Important contributions to Starlette and Uvicorn.

If you want your name removed from the list above, or if I forgot a significant contributor, please let me know.
You can view all contributors on GitHub:
[Starlette Contributors](https://github.com/encode/starlette/graphs/contributors) / [Uvicorn Contributors](https://github.com/encode/uvicorn/graphs/contributors).

While the current sponsorship program directly supports Marcelo's maintenance work, we are exploring ways
to distribute funding to other key contributors in the future. This initiative is still in early planning
stages, as we want to ensure a fair and sustainable model that recognizes the valuable contributions of
our community members.

2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -67,6 +67,8 @@ markdown_extensions:
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
- pymdownx.tasklist:
custom_checkbox: true

watch:
- starlette
12 changes: 6 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -2,22 +2,22 @@
-e .[full]

# Testing
coverage==7.6.10
coverage==7.6.12
importlib-metadata==8.6.1
mypy==1.14.1
ruff==0.9.4
mypy==1.15.0
ruff==0.9.9
typing_extensions==4.12.2
types-contextvars==2.4.7.3
types-PyYAML==6.0.12.20241230
types-dataclasses==0.6.6
pytest==8.3.4
trio==0.28.0
trio==0.29.0

# Documentation
black==25.1.0
mkdocs==1.6.1
mkdocs-material==9.6.5
mkdocstrings-python==1.13.0
mkdocs-material==9.6.6
mkdocstrings-python==1.16.2

# Packaging
build==1.2.2.post1
2 changes: 1 addition & 1 deletion starlette/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.46.0"
__version__ = "0.46.1"
1 change: 1 addition & 0 deletions starlette/staticfiles.py
Original file line number Diff line number Diff line change
@@ -153,6 +153,7 @@ def lookup_path(self, path: str) -> tuple[str, os.stat_result | None]:
joined_path = os.path.join(directory, path)
if self.follow_symlink:
full_path = os.path.abspath(joined_path)
directory = os.path.abspath(directory)
else:
full_path = os.path.realpath(joined_path)
directory = os.path.realpath(directory)
8 changes: 8 additions & 0 deletions tests/test_staticfiles.py
Original file line number Diff line number Diff line change
@@ -593,3 +593,11 @@ def test_staticfiles_self_symlinks(tmp_path: Path, test_client_factory: TestClie
assert response.url == "http://testserver/index.html"
assert response.status_code == 200
assert response.text == "<h1>Hello</h1>"


def test_staticfiles_relative_directory_symlinks(test_client_factory: TestClientFactory) -> None:
app = StaticFiles(directory="tests/statics", follow_symlink=True)
client = test_client_factory(app)
response = client.get("/example.txt")
assert response.status_code == 200
assert response.text == "123\n"