> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python

> Get started creating Python apps on Upsun.

export const DynamicCodeBlock = ({language = 'yaml', filename, icon, lines, wrap, expandable, highlight, focus, children}) => {
  const STORAGE_KEY = 'upsun_versions_cache';
  const COMPOSABLE_STORAGE_KEY = 'upsun_composable_cache';
  const CACHE_TTL = 5 * 60 * 1000;
  const API_URL = 'https://meta.upsun.com/images';
  const COMPOSABLE_API_URL = 'https://meta.upsun.com/composable';
  const DEBUG_PREFIX = '[DynamicCodeBlock cache]';
  const [versionData, setVersionData] = useState(null);
  const [versionError, setVersionError] = useState(false);
  const [composableData, setComposableData] = useState(null);
  const [composableError, setComposableError] = useState(false);
  useEffect(() => {
    const fetchData = async () => {
      let cachedData = null;
      let cachedEtag = null;
      if (typeof localStorage !== 'undefined') {
        try {
          const cached = localStorage.getItem(STORAGE_KEY);
          if (cached) {
            const parsed = JSON.parse(cached);
            cachedData = parsed?.data || null;
            cachedEtag = parsed?.etag || null;
            if (cachedData && Date.now() - parsed.timestamp < CACHE_TTL) {
              return cachedData;
            }
          }
        } catch (err) {
          console.error('Failed to load from cache:', err);
        }
      }
      const requestHeaders = cachedEtag ? {
        'If-None-Match': cachedEtag
      } : {};
      console.debug(`${DEBUG_PREFIX} revalidating`, {
        storageKey: STORAGE_KEY,
        hasCachedData: Boolean(cachedData),
        hasCachedEtag: Boolean(cachedEtag)
      });
      const response = await fetch(API_URL, {
        headers: requestHeaders
      });
      if (response.status === 304 && cachedData) {
        console.debug(`${DEBUG_PREFIX} revalidated (304)`, {
          storageKey: STORAGE_KEY
        });
        if (typeof localStorage !== 'undefined') {
          try {
            const etag = response.headers.get('etag') || cachedEtag;
            localStorage.setItem(STORAGE_KEY, JSON.stringify({
              data: cachedData,
              etag,
              timestamp: Date.now()
            }));
          } catch (err) {
            console.error('Failed to refresh cache metadata:', err);
          }
        }
        return cachedData;
      }
      if (!response.ok) throw new Error(`API request failed: ${response.statusText}`);
      const data = await response.json();
      const etag = response.headers.get('etag');
      console.debug(`${DEBUG_PREFIX} refreshed (200)`, {
        storageKey: STORAGE_KEY,
        etag
      });
      if (typeof localStorage !== 'undefined') {
        try {
          localStorage.setItem(STORAGE_KEY, JSON.stringify({
            data,
            etag,
            timestamp: Date.now()
          }));
        } catch (err) {
          console.error('Failed to cache data:', err);
        }
      }
      return data;
    };
    fetchData().then(data => setVersionData(data)).catch(err => console.error('Failed to fetch version data:', err));
  }, []);
  const findHighestVersion = versionsMap => {
    if (!versionsMap || Object.keys(versionsMap).length === 0) return null;
    const entries = Object.entries(versionsMap);
    const active = entries.filter(([, v]) => v.upsun && v.upsun.status === 'supported' || v.upsun && v.upsun.status === 'deprecated');
    const candidates = active.length > 0 ? active : entries;
    let [highestName] = candidates[0];
    for (let i = 1; i < candidates.length; i++) {
      const [currentName] = candidates[i];
      const cp = currentName.split('.').map(Number);
      const hp = highestName.split('.').map(Number);
      for (let j = 0; j < Math.max(cp.length, hp.length); j++) {
        if ((cp[j] || 0) > (hp[j] || 0)) {
          highestName = currentName;
          break;
        } else if ((cp[j] || 0) < (hp[j] || 0)) {
          break;
        }
      }
    }
    return highestName;
  };
  const getVersion = (lang, requestedVersion = 'latest') => {
    if (lang === 'composable') {
      if (!composableData || !composableData.versions || Object.keys(composableData.versions).length === 0) return null;
      if (requestedVersion && requestedVersion !== 'latest') {
        return (requestedVersion in composableData.versions) ? requestedVersion : null;
      }
      return findHighestVersion(composableData.versions);
    }
    if (!versionData) return null;
    const imageData = versionData[lang];
    if (!imageData || !imageData.versions || Object.keys(imageData.versions).length === 0) {
      return null;
    }
    if (requestedVersion && requestedVersion !== 'latest') {
      return (requestedVersion in imageData.versions) ? requestedVersion : null;
    }
    return findHighestVersion(imageData.versions);
  };
  let code = typeof children === 'string' ? children : String(children || '');
  const codeLines = code.split('\n');
  while (codeLines.length > 0 && codeLines[0].trim() === '') codeLines.shift();
  while (codeLines.length > 0 && codeLines[codeLines.length - 1].trim() === '') codeLines.pop();
  if (codeLines.length > 0) {
    const indents = codeLines.filter(line => line.trim().length > 0).map(line => line.match(/^[ \t]*/)[0].length);
    const minIndent = Math.min(...indents);
    code = codeLines.map(line => line.slice(minIndent)).join('\n');
  }
  code = code.replace(/\{\{version:(.*?)\}\}/g, (match, params) => {
    const parts = params.split(':');
    const lang = parts[0];
    const ver = parts[1] || 'latest';
    const isComposable = lang === 'composable';
    const hasError = isComposable ? composableError : versionError;
    const dataReady = isComposable ? composableData !== null : versionData !== null;
    if (hasError) return '(unavailable)';
    if (dataReady) {
      const resolvedVersion = getVersion(lang, ver);
      return resolvedVersion || match;
    }
    return '...';
  });
  const codeBlockProps = {
    language,
    ...filename && ({
      filename
    }),
    ...icon && ({
      icon
    }),
    ...lines !== undefined && ({
      lines
    }),
    ...wrap !== undefined && ({
      wrap
    }),
    ...expandable !== undefined && ({
      expandable
    }),
    ...highlight && ({
      highlight
    }),
    ...focus && ({
      focus
    })
  };
  return <CodeBlock {...codeBlockProps}>{code}</CodeBlock>;
};

export const VersionDeprecatedBlock = () => <>
    <h3 id="deprecated-versions">Deprecated versions</h3>
    <p>
    The following versions are <a href="/docs/glossary#deprecated-versions">deprecated</a>.
    They're available, but they don't receive security updates from upstream and aren't guaranteed to work.
    They'll be removed in the future – consider migrating to a <a href="#supported-versions">supported version</a>.
    </p>
  </>;

export const DisclaimerNix = () => <Tip>
    You can now use composable image to install runtimes and tools in your application container. To find out more, see the <a href="/docs/configure-apps/app-reference/composable-image">Composable image</a> topic.
  </Tip>;

<DisclaimerNix />

Python is a general purpose scripting language often used in web development.
You can deploy Python apps on Upsun using a server or a project such as [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/).

## Supported versions

You can select the major and minor version.

Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches.

* 3.14
* 3.13

### Specify the language

To use Python, specify `python` as your [app’s type](/docs/configure-apps/app-reference/single-runtime-image#type):

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        <APP_NAME>:
          type: 'python:<VERSION_NUMBER>'
    `
  }
</DynamicCodeBlock>

For example:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'`
  }
</DynamicCodeBlock>

<VersionDeprecatedBlock />

* 3.12
* 3.11
* 3.10

\* This version doesn't receive any updates at all.
You are strongly recommended to upgrade to a supported version.

## Retired versions

The following versions have been retired and are no longer available.
If your project uses a retired version, you must update to a [supported version](#supported-versions).

* 3.9
* 3.8
* 3.7
* 3.6
* 3.5
* 2.7

## Usage example

### Run your own server

You can define any server to handle requests.
Once you have it configured, add the following configuration to get it running on Upsun:

1. Specify one of the [supported versions](#supported-versions):

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'`
  }
</DynamicCodeBlock>

2. Install the requirements for your app.

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'
          dependencies:
            python3:
              pipenv: "2024.4.1"
          hooks:
            build: |
              set -eu
              pipenv install --system --deploy`
  }
</DynamicCodeBlock>

3. Define the command to start your web server:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'
          web:
            # Start your app with the configuration you define
            # You can replace the file location with your location
            commands:
              start: python server.py`
  }
</DynamicCodeBlock>

You can choose from many web servers such as Daphne, Gunicorn, Hypercorn, and Uvicorn.
See more about [running Python web servers](/docs/languages/python/server).

### Use uWSGI

You can also use [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) to manage your server.
Follow these steps to get your server started.

1. Specify one of the [supported versions](#supported-versions):

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'`
  }
</DynamicCodeBlock>

2. Define the conditions for your web server:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'
          web:
            upstream:
              # Send requests to the app server through a unix socket
              # Its location is defined in the SOCKET environment variable
              socket_family: "unix"

            # Start your app with the configuration you define
            # You can replace the file location with your location
            commands:
              start: "uwsgi --ini conf/uwsgi.ini"

            locations:
              # The folder from which to serve static assets
              "/":
                root: "public"
                passthru: true
                expires: 1h`
  }
</DynamicCodeBlock>

3. Create configuration for uWSGI such as the following:

   ```ini config/uwsgi.ini theme={null}
   [uwsgi]
   # Unix socket to use to talk with the web server
   # Uses the variable defined in the configuration in step 2
   socket = $(SOCKET)
   protocol = http

   # the entry point to your app
   wsgi-file = app.py
   ```

   Replace `app.py` with whatever your file is.

4. Install the requirements for your app.

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'
          dependencies:
            python3:
              pipenv: "2024.4.1"
          hooks:
            build: |
              set -eu
              pipenv install --system --deploy`
  }
</DynamicCodeBlock>

5. Define the entry point in your app:

   ```python theme={null}
   # You can name the function differently and pass the new name as a flag
   # start: "uwsgi --ini conf/uwsgi.ini --callable <NAME>"
   def application(env, start_response):

       start_response('200 OK', [('Content-Type', 'text/html')])
       return [b"Hello world from Upsun"]
   ```

## Package management

Your app container comes with pip pre-installed.
For more about managing packages with pip, Pipenv, and Poetry,
see how to [manage dependencies](/docs/languages/python/dependencies).

To add global dependencies (packages available as commands),
add them to the `dependencies` in your [app configuration](/docs/configure-apps/app-reference/single-runtime-image#dependencies):

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'
          dependencies:
            python3:
              <PACKAGE_NAME>:<PACKAGE_VERSION>`
  }
</DynamicCodeBlock>

For example, to use `pipenv` to manage requirements and a virtual environment, add the following:

<DynamicCodeBlock language="yaml" filename=".upsun/config.yaml">
  {`
      applications:
        # The app's name, which must be unique within the project.
        myapp:
          type: 'python:{{version:python:latest}}'
          dependencies:
            python3:
              pipenv: "2024.4.1"
          hooks:
            build: |
              set -eu
              pipenv install --system --deploy`
  }
</DynamicCodeBlock>

## Connect to services

The following examples show how to access various [services](/docs/add-services) with Python.
For more information on configuring a given service, see the page for that service.

You can access service credentials to connect to [managed services](/docs/add-services) from environment variables present in the application container.
Consult each of the individual service documentation to see how to retrieve and surface credentials into your application.

* [ClickHouse](https://developer.upsun.com/docs/add-services/clickhouse#usage-example)
* [Elasticsearch](https://developer.upsun.com/docs/add-services/elasticsearch#usage-example)
* [Gotenberg](https://developer.upsun.com/docs/add-services/gotenberg#usage-example)
* [Headless Chrome](https://developer.upsun.com/docs/add-services/headless-chrome#usage-example)
* [InfluxDB](https://developer.upsun.com/docs/add-services/influxdb#usage-example)
* [Kafka](https://developer.upsun.com/docs/add-services/kafka#usage-example)
* [MariaDB/MySQL](https://developer.upsun.com/docs/add-services/mysql#usage-example)
* [Memcached](https://developer.upsun.com/docs/add-services/memcached#usage-example)
* [mercure](https://developer.upsun.com/docs/add-services/mercure#usage-example)
* [mongodb](https://developer.upsun.com/docs/add-services/mongodb#usage-example)
* [Network Storage](https://developer.upsun.com/docs/add-services/network-storage#usage-example)
* [OpenSearch](https://developer.upsun.com/docs/add-services/opensearch#usage-example)
* [PostgreSQL](https://developer.upsun.com/docs/add-services/postgresql#usage-example)
* [RabbitMQ](https://developer.upsun.com/docs/add-services/rabbitmq#usage-example)
* [Redis](https://developer.upsun.com/docs/add-services/redis#usage-example)
* [Solr](https://developer.upsun.com/docs/add-services/solr#usage-example)
* [Valkey](https://developer.upsun.com/docs/add-services/valkey#usage-example)
* [Varnish](https://developer.upsun.com/docs/add-services/varnish#usage-example)
* [Vault KMS](https://developer.upsun.com/docs/add-services/vault#usage-example)
* [Chroma](/tutorials/self-hosted/chroma#3-use-the-relationship-in-your-application)
* [Qdrant](/tutorials/self-hosted/qdrant#4-use-the-relationship-in-your-application)

## Sanitizing data

By default, data is inherited automatically by each child environment from its parent.
If you need to sanitize data in preview environments for compliance,
see how to [sanitize databases](/docs/development/sanitize-db).

## Frameworks

All major Python web frameworks can be deployed on Upsun.
See dedicated guides for deploying and working with them:

* [Django](/docs/get-started/stacks/django)
* [Flask](/docs/get-started/stacks/flask)
