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
11 changes: 3 additions & 8 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ jobs:
exclude:

# Exclude test matrix slots that are no longer supported by GHA runners.
- os: 'ubuntu-20.04'
python-version: '3.6'
- os: 'macos-latest'
python-version: '3.6'
- os: 'macos-latest'
Expand Down Expand Up @@ -88,14 +90,7 @@ jobs:
cache-dependency-glob: |
pyproject.toml

- name: Install and validate package (Python 3.6)
if: matrix.python-version == '3.6'
run: |
pip install '.[full,develop,test]'
poe test

- name: Install and validate package (Python >=3.6)
if: matrix.python-version != '3.6'
- name: Install and validate package
run: |
uv pip install '.[full,develop,test]'
poe check
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,23 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
argument, enabling usage on single-file applications. Beforehand, only
invocations of Python modules were possible.
```shell
# Install Responder with CLI extension.
pip install 'responder[cli]'

# Start Responder application defined in Python module.
responder run acme.app:api

# Start Responder application defined in a single Python file.
responder run examples/helloworld.py:api
```
- CLI: `responder run` now also accepts URLs.
```shell
# Install Responder with CLI extension (full).
pip install 'responder[cli-full]'

# Start Responder application defined in Python module at remote location.
responder run https://github.com/kennethreitz/responder/raw/refs/heads/main/examples/helloworld.py
```

### Changed

Expand Down Expand Up @@ -55,6 +66,7 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
the `<target>` argument of `responder run`, but is semantically different,
as the former accepts a filesystem directory to the `package.json` file,
but the latter expects a Python entrypoint specification.
- Platform: Removed support for EOL Python 3.6

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Alternatively, install directly from the repository:

pip install 'responder[full] @ git+https://github.com/kennethreitz/responder.git'

Responder supports **Python 3.6+**.
Responder supports **Python 3.7+**.

# The Basic Idea

Expand Down
156 changes: 122 additions & 34 deletions docs/source/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,153 @@ Responder CLI
=============

Responder installs a command line program ``responder``. Use it to launch
a Responder application from a file or module.
a Responder application from a file or module, either located on a local
or remote filesystem, or object store.

Launch application from file
----------------------------
Launch Module Entrypoint
------------------------

For loading a Responder application from a Python module, you will refer to
its ``API()`` instance using a `Python entry point object reference`_ that
points to a Python object. It is either in the form ``importable.module``,
or ``importable.module:object.attr``.

Acquire minimal example application, `helloworld.py`_,
implementing a basic echo handler, and launch the HTTP service.
A basic invocation command to launch a Responder application:

.. code-block:: shell

responder run acme.app

The command above assumes a Python package ``acme`` including an ``app``
module ``acme/app.py`` that includes an attribute ``api`` that refers
to a ``responder.API`` instance, reflecting the typical layout of
a standard Responder application.

Loading a Responder application using an entrypoint specification will
inherit the capacities of `Python's import system`_, as implemented by
`importlib`_.

Launch Local File
-----------------

Acquire a minimal example single-file application, ``helloworld.py`` [1]_,
to your local filesystem, giving you the chance to edit it, and launch the
Responder HTTP service.

.. code-block:: shell

wget https://github.com/kennethreitz/responder/raw/refs/heads/main/examples/helloworld.py
responder run helloworld.py

In another terminal, invoke a HTTP request, for example using `HTTPie`_.
.. note::

.. code-block:: shell
To validate the example application, invoke a HTTP request, for example using
`curl`_, `HTTPie`_, or your favourite browser at hand.

http http://127.0.0.1:5042/hello
.. code-block:: shell

The response is no surprise.
http http://127.0.0.1:5042/Hello

::
The response is no surprise.

HTTP/1.1 200 OK
content-length: 13
content-type: text/plain
date: Sat, 26 Oct 2024 13:16:55 GMT
encoding: utf-8
server: uvicorn
::

hello, world!
HTTP/1.1 200 OK
content-length: 13
content-type: text/plain
date: Sat, 26 Oct 2024 13:16:55 GMT
encoding: utf-8
server: uvicorn

Hello, world!

Launch application from module
------------------------------
.. [1] The Responder application `helloworld.py`_ implements a basic echo handler.

If your Responder application has been implemented as a Python module,
launch it like this:
Launch Remote File
------------------

You can also launch a single-file application where its Python file is stored
on a remote location after installing the ``cli-full`` extra.

.. code-block:: shell

responder run acme.app
uv pip install 'responder[cli-full]'

That assumes a Python package ``acme`` including an ``app`` module
``acme/app.py`` that includes an attribute ``api`` that refers
to a ``responder.API`` instance, reflecting the typical layout of
a standard Responder application.
Responder supports all filesystem adapters compatible with `fsspec`_, and
installs the adapters for Azure Blob Storage (az), Google Cloud Storage (gs),
GitHub, HTTP, and AWS S3 by default.

.. code-block:: shell

.. rubric:: Non-standard instance name
# Works 1:1.
responder run https://github.com/kennethreitz/responder/raw/refs/heads/main/examples/helloworld.py
responder run github://kennethreitz:responder@/examples/helloworld.py

When your attribute that references the ``responder.API`` instance
is called differently than ``api``, append it to the launch target
address like this:
If you need access other kinds of remote targets, see the `list of
fsspec-supported filesystems and protocols`_. The next section enumerates
a few synthetic examples. The corresponding storage buckets do not even
exist, so don't expect those commands to work.

.. code-block:: shell

# Azure Blob Storage, Google Cloud Storage, and AWS S3.
responder run az://kennethreitz-assets/responder/examples/helloworld.py
responder run gs://kennethreitz-assets/responder/examples/helloworld.py
responder run s3://kennethreitz-assets/responder/examples/helloworld.py

# Hadoop Distributed File System (hdfs), SSH File Transfer Protocol (sftp),
# Common Internet File System (smb), Web-based Distributed Authoring and
# Versioning (webdav).
responder run hdfs://kennethreitz-assets/responder/examples/helloworld.py
responder run sftp://user@host/kennethreitz/responder/examples/helloworld.py
responder run smb://workgroup;user:password@server:port/responder/examples/helloworld.py
responder run webdav+https://user:password@server:port/responder/examples/helloworld.py

.. tip::

In order to install support for all filesystem types supported by fsspec, run:

.. code-block:: shell

uv pip install 'fsspec[full]'

When using ``uv``, this concludes within an acceptable time of approx.
25 seconds. If you need to be more selectively instead of using ``full``,
choose from one or multiple of the available `fsspec extras`_, which are:

abfs, arrow, dask, dropbox, fuse, gcs, git, github, hdfs, http, oci, s3,
sftp, smb, ssh.

Launch with Non-Standard Instance Name
--------------------------------------

By default, Responder will acquire an ``responder.API`` instance using the
symbol name ``api`` from the specified Python module.

If your main application file uses a different name than ``api``, please
append the designated symbol name to the launch target address.

It works like this for module entrypoints and local files:

.. code-block:: shell

responder run acme.app:service
responder run /path/to/acme/app.py:service

Within your ``app.py``, the instance would have been defined like this:
It works like this for URLs:

.. code-block:: shell

responder run http://app.server.local/path/to/acme/app.py#service

Within your ``app.py``, the instance would have been defined to use
the ``service`` symbol name instead of ``api``, like this:

.. code-block:: python

service = responder.API()


Build JavaScript application
Build JavaScript Application
----------------------------

The ``build`` subcommand invokes ``npm run build``, optionally accepting
Expand All @@ -78,13 +159,20 @@ where it expects a regular NPM ``package.json`` file.

responder build

When specifying a target directory, responder will change to that
When specifying a target directory, Responder will change to that
directory beforehand.

.. code-block:: shell

responder build /path/to/project


.. _curl: https://curl.se/
.. _fsspec: https://filesystem-spec.readthedocs.io/en/latest/
.. _fsspec extras: https://github.com/fsspec/filesystem_spec/blob/2024.12.0/pyproject.toml#L27-L69
.. _helloworld.py: https://github.com/kennethreitz/responder/blob/main/examples/helloworld.py
.. _HTTPie: https://httpie.io/docs/cli
.. _importlib: https://docs.python.org/3/library/importlib.html
.. _list of fsspec-supported filesystems and protocols: https://github.com/fsspec/universal_pathlib#currently-supported-filesystems-and-protocols
.. _Python entry point object reference: https://packaging.python.org/en/latest/specifications/entry-points/
.. _Python's import system: https://docs.python.org/3/reference/import.html
5 changes: 5 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@
# Feldroy.com links are ignored because it blocks GHA.
r"https://www.feldroy.com/.*",
]
linkcheck_anchors_ignore_for_url = [
# Requires JavaScript.
# After opting-in to new GitHub issues, Sphinx can no longer grok the HTML anchor references.
r"https://github.com",
]

# -- Options for intersphinx extension ---------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Or use standard pip where ``uv`` is not available.

pip install --upgrade 'responder'

Responder supports **Python 3.6+**. If you are looking at installing Responder
Responder supports **Python 3.7+**. If you are looking at installing Responder
for hacking on it, please refer to the :ref:`sandbox` documentation.

.. toctree::
Expand Down
10 changes: 1 addition & 9 deletions responder/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,13 @@
import uvicorn
from starlette.middleware.cors import CORSMiddleware
from starlette.middleware.errors import ServerErrorMiddleware
from starlette.middleware.exceptions import ExceptionMiddleware
from starlette.middleware.gzip import GZipMiddleware
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
from starlette.middleware.sessions import SessionMiddleware
from starlette.middleware.trustedhost import TrustedHostMiddleware
from starlette.testclient import TestClient

# Python 3.7+
try:
from starlette.middleware.exceptions import ExceptionMiddleware
# Python 3.6
except ImportError:
from starlette.exceptions import ( # type: ignore[attr-defined,no-redef]
ExceptionMiddleware,
)

from . import status_codes
from .background import BackgroundQueue
from .formats import get_formats
Expand Down
Loading
Loading