# Foreign Function Interface (FFI)

import { WranglerConfig } from "~/components";

Via [Pyodide](https://pyodide.org/en/stable/), Python Workers provide a [Foreign Function Interface (FFI)](https://en.wikipedia.org/wiki/Foreign_function_interface) to JavaScript. This allows you to:

- Use [bindings](/workers/runtime-apis/bindings/) to resources on Cloudflare, including [Workers AI](/workers-ai/), [Vectorize](/vectorize/), [R2](/r2/), [KV](/kv/), [D1](/d1/), [Queues](/queues/), [Durable Objects](/durable-objects/), [Service Bindings](/workers/runtime-apis/bindings/service-bindings/) and more.
- Use JavaScript globals, like [`Request`](/workers/runtime-apis/request/), [`Response`](/workers/runtime-apis/response/), and [`fetch()`](/workers/runtime-apis/fetch/).
- Use the full feature set of Cloudflare Workers — if an API is accessible in JavaScript, you can also access it in a Python Worker, writing exclusively Python code.

The details of Pyodide's Foreign Function Interface are documented [here](https://pyodide.org/en/stable/usage/type-conversions.html), and Workers written in Python are able to take full advantage of this.

## Using Bindings from Python Workers

Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform. When you declare a binding on your Worker, you grant it a specific capability, such as being able to read and write files to an [R2](/r2/) bucket.

For example, to access a [KV](/kv) namespace from a Python Worker, you would declare the following in your Worker's [Wrangler configuration file](/workers/wrangler/configuration/):

<WranglerConfig>

```jsonc
{
	"main": "./src/index.py",
	"kv_namespaces": [
		{
			"binding": "FOO",
			"id": "<YOUR_KV_NAMESPACE_ID>"
		}
	]
}
```

</WranglerConfig>

...and then call `.get()` on the binding object that is exposed on `env`:

```python
from workers import WorkerEntrypoint, Response

class Default(WorkerEntrypoint):
    async def fetch(self, request):
        await self.env.FOO.put("bar", "baz")
        bar = await self.env.FOO.get("bar")
        return Response(bar) # returns "baz"
```

### Converting Python to JavaScript

Occasionally, to interoperate with JavaScript APIs, you may need to convert a Python object to JavaScript. Pyodide provides a `to_js` function to facilitate this conversion.

```python
from js import Object
from pyodide.ffi import to_js as _to_js

from workers import WorkerEntrypoint, Response

# to_js converts between Python dictionaries and JavaScript Objects
def to_js(obj):
   return _to_js(obj, dict_converter=Object.fromEntries)
```

For more details, see out the [documentation on `pyodide.ffi.to_js`](https://pyodide.org/en/stable/usage/api/python-api/ffi.html#pyodide.ffi.to_js).

## Using JavaScript globals from Python Workers

We recommend using the `workers` module, which is provided by our `workers-runtime-sdk` package, to access JavaScript globals in a more Pythonic way.
However, if you need to access JavaScript globals directly for any reason, you can import them from the `js` module.

For example, note how `Response` is imported from `js` in the example below:

```python
from workers import WorkerEntrypoint
from js import Response

class Default(WorkerEntrypoint):
    async def fetch(self, request):
        return Response.new("Hello World!")
```

Refer to the [Python examples](/workers/languages/python/examples/) to learn how to call into JavaScript functions from Python, including `console.log` and logging, providing options to `Response`, and parsing JSON.