# tmdbsimple maps TMDb API v3 endpoints onto Python objects and class attributes

> tmdbsimple is a Python wrapper for The Movie Database API v3 that turns each endpoint into a method on a small set of object types, so responses land on instance attributes instead of dict lookups. It is a thin layer with one runtime dependency, and the trade-off is that it mirrors the API rather than improving it.

**celiao/tmdbsimple** — A wrapper for The Movie Database API v3.

- Repository: https://github.com/celiao/tmdbsimple
- Stars: 702 · Forks: 126
- Language: Python
- License: GPL-3.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/celiao-tmdbsimple

## Every TMDb endpoint becomes a method on a small set of objects

tmdbsimple is a wrapper, not a client framework. The README states the mapping plainly: one-to-one mapping between tmdbsimple methods and TMDb endpoints. There is no query builder, no ORM and no local database. You pick an object type that corresponds to a TMDb resource, call a method on it, and the endpoint is invoked.

The mechanics are simple enough to describe in one sentence. You create an instance of one of the object types, call one of the methods on the instance, and access the instance attributes. The README shows that with a movie instance:

```python
    >>> movie = tmdb.Movies(603)
    >>> response = movie.info()
    >>> movie.title
    'The Matrix'
    >>> movie.budget
    63000000
```

The constructor argument is the TMDb identifier, and the method call returns the raw response while the instance keeps the decoded fields. Note that the constructor does not fetch anything on its own; the data arrives when you call info(), and the attributes are populated as a side effect of that call.

For one-off lookups you do not need to keep the instance around:

```python
    >>> response = tmdb.Movies(603).info()
    >>> response['budget']
    63000000
```

The same object gives you both styles, attributes for readable code and the raw response dict when you need a field the wrapper does not surface.

## Global module settings carry the API key, timeout and session

Configuration lives on the module itself rather than on a per-object basis. The documented setup is two lines:

```python
import tmdbsimple as tmdb
tmdb.API_KEY = 'YOUR_API_KEY_HERE'
```

Beyond the key, three optional globals change how requests are made. REQUESTS_TIMEOUT takes either a single number or a tuple, with the README describing the scalar form as seconds for both connect and read and the tuple form as separate connect and read values:

```python
tmdb.REQUESTS_TIMEOUT = 5  # seconds, for both connect and read
```

```python
tmdb.REQUESTS_TIMEOUT = (2, 5)  # seconds, for connect and read specifically 
```

A session can be injected if you need connection reuse or your own adapter configuration:

```python
import requests
tmdb.REQUESTS_SESSION = requests.Session()
```

And there is a switch for how the credential is sent:

```python
tmdb.USE_BEARER_AUTH = True
```

The README describes bearer token authentication as an alternative to the default API key query parameter, and suggests it may help if you hit authorization problems with the default method. Module level globals are convenient for scripts and a limitation for applications, since two clients in the same process cannot hold different keys without reaching around the wrapper.

## Searching returns a results list you iterate like plain dictionaries

Search is the case where the wrapper's one-to-one mapping shows its limits most clearly. The README example creates a Search object, calls the movie method with a query, then walks the results attribute:

```python
    >>> search = tmdb.Search()
    >>> response = search.movie(query='The Bourne')
    >>> for s in search.results:
    ...     print(s['title'], s['id'], s['release_date'], s['popularity'])
    ...
    The Bourne Ultimatum 2503 2007-08-03 55.2447062124256
    The Bourne Supremacy 2502 2004-07-23 43.4553609681985
    The Bourne Identity 2501 2002-06-06 38.5531563780592
```

Each element of results is a dictionary with TMDb's own field names, which is why the loop uses subscript access while the movie example above used attribute access. The attributes on the instance, title and budget and popularity, are conveniences for the response of a single resource; collection endpoints hand back raw dicts.

That inconsistency is the practical detail to plan around. Code that reads search results needs dictionary keys, and the keys are whatever TMDb names them, so a schema change on the service side shows up in your code as a KeyError rather than a version bump in your dependencies.

## Nested data is reached by key, and the README walks through it

Fields that are dictionaries are accessed with keys, which the README calls out explicitly. The release-certification example shows the pattern, where the country list attached to a movie is iterated and compared on the ISO code:

```python
    >>> response = movie.releases()
    >>> for c in movie.countries:
    ...    if c['iso_3166_1'] == 'US':
    ...         print(c['certification'])
    ...
    'R'
```

The indentation in that example is uneven in the README itself, which is a small sign of how the documentation was assembled rather than a hint about the API. The substance is the shape: a single call populates a list of dicts, and you filter on a fixed key.

This is where the wrapper's value and its ceiling sit next to each other. Writing the loop once against typed attribute access would be nicer, but it would also mean tmdbsimple had to model TMDb's nested structures in detail, and it deliberately does not. The one-to-one mapping keeps the wrapper small and the docs honest, at the cost of leaving nested access as dict work.

## Installation is pip install, and requests is the only dependency

The install path is standard. The README points at the Python Package Index and gives the pip command:

```bash
pip install tmdbsimple
```

You can also download the .zip or .tar.gz file from PyPI and install it yourself, or pull the source from GitHub and install it yourself. If you take one of the manual routes, the README asks you to install requests as well.

The dependency situation is minimal by design. The pyproject.toml declares dependencies = ["requests"], requires-python = ">=3.10", and the package classifiers list 3.10, 3.11, 3.12 and 3.13. The README says the same versions were used for testing and adds a constraint about Python versions with TLS 1.2 support.

The build backend is setuptools, with setuptools>=61.0 in the build requirements, and the project metadata lives in pyproject.toml with a setup.cfg alongside it. The source package itself is the tmdbsimple/ directory at the repository root, with tests/ next to it, so the layout is the standard src-less arrangement for a single package.

## A thin wrapper mirrors the API, including its rough edges

The obvious advantage of tmdbsimple is coverage. The README claims it implements all TMDb methods, including Accounts and Authentication, and it points at the TMDb documentation for the underlying API details. One dependency, one attribute assignment, and the whole service is available.

The cost is that you inherit the API's shape without gaining a stable one. Results come back as dicts with TMDb's field names, nesting is untyped, and there is no caching, no retry policy and no rate limit handling described anywhere in the README. If TMDb renames a field, your code breaks in a way a version constraint would not have caught.

There is a second boundary worth stating plainly. The package is a synchronous wrapper over requests. There is no asynchronous variant in the repository, so in an asyncio application you would either block the event loop or push the calls into a thread executor. The README also does not document pagination handling, which means walking a large result set is something you implement against the endpoint yourself.

The stated alternative in the README is rtsimple, a wrapper for the Rotten Tomatoes API, offered as a way to reach even more movie and TV data. That is a different data source rather than a different approach to the same one, which is the honest distinction here.

## GPLv3 and a steady patch cadence define the adoption cost

The licence is the one thing worth reading twice before you depend on this. The pyproject.toml records license = { text = "GPLv3" }, and the repository ships a LICENSE file. A copyleft licence of that kind carries obligations for how you distribute a modified or linked work, which is a question for your own legal review rather than something this article can answer.

In practice the concern is scoped by how the package is used. tmdbsimple is a client library that talks to a remote HTTP API over a network boundary, and it is not linked into your application the way a shared library would be. What the licence does not do is remove the obligation to look at it, so treat the LICENSE file as a gate in your own review rather than an afterthought.

On maintenance, the record is steady. The repository is not archived, the last push was on 2026-07-30, and three releases landed close together: v2.9.6 on 2026-05-25, v2.9.7 on 2026-07-29 and v2.9.8 on 2026-07-30. Two patch releases a day apart suggests a batch of fixes rather than a feature cadence, and the project classifier in pyproject.toml reads Development Status :: 5 - Production/Stable. The README also points at a codecov badge and a build workflow, so coverage and CI are part of the setup.

## Conclusion

Adopt tmdbsimple when you want the full TMDb surface in Python with method calls that match the endpoint names and response fields readable as attributes. Do not adopt it if you need an ORM, caching or a stable data model, because the wrapper mirrors the remote API and inherits its shape. Verify first that you have a TMDb API key, that your Python is 3.10 or later, and whether the default API key query parameter works for your account before reaching for tmdb.USE_BEARER_AUTH. Note the licence, since the package ships under GPLv3.

## FAQ

### How do I install tmdbsimple and set the API key?

Install it with pip install tmdbsimple from the Python Package Index, then assign the key on the module: import tmdbsimple as tmdb followed by tmdb.API_KEY = 'YOUR_API_KEY_HERE'. The package requires Python 3.10 or later and depends on requests.

### How do I set a timeout or a custom session in tmdbsimple?

Set tmdb.REQUESTS_TIMEOUT to a number for both connect and read, or to a tuple for separate connect and read values, and assign tmdb.REQUESTS_SESSION = requests.Session() to use your own session. Both are optional module level settings.

### What is the difference between tmdb.USE_BEARER_AUTH and the default API key?

The default method sends the API key as a query parameter. Setting tmdb.USE_BEARER_AUTH = True switches to bearer token authentication, and the README suggests it may help if you encounter authorization issues with the default method.

### Does tmdbsimple support asynchronous requests?

The repository does not document an async interface. The package depends on requests and exposes module level settings for a session and timeouts, so calls are synchronous.

### What licence is tmdbsimple released under?

The pyproject.toml records the licence as GPLv3 and the repository ships a LICENSE file. Review that licence yourself for how it applies to your use and distribution.

## Sources

- [celiao/tmdbsimple on GitHub](https://github.com/celiao/tmdbsimple)
- [Issues](https://github.com/celiao/tmdbsimple/issues)
- [License: GPL-3.0](https://github.com/celiao/tmdbsimple/blob/master/LICENSE)
- [README](https://github.com/celiao/tmdbsimple/blob/master/README.md)
- [Releases](https://github.com/celiao/tmdbsimple/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/celiao-tmdbsimple
