Skip to content

Reference

This part of the project documentation focuses on an information-oriented approach. Use it as a reference for the technical implementation of the movie_guess project code.

utils

Utility functions.

general

General utility functions.

check_env_vars

check_env_vars(env_vars=None)

Checks if the required environment variables are set.

Parameters:

Name Type Description Default
env_vars list[str] | None

List of environment variables to check. Defaults to None.

None

Raises:

Type Description
ValueError

If any of the environment variables are not set.

Source code in api/utils/general.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def check_env_vars(env_vars: list[str] | None = None) -> None:
    """Checks if the required environment variables are set.

    Args:
        env_vars: List of environment variables to check. Defaults to None.

    Raises:
        ValueError: If any of the environment variables are not set.
    """
    if env_vars is None:
        return

    for env_var in env_vars:
        if os.getenv(env_var) is None:
            raise ValueError(f"Please set {env_var} env var.")

is_module_installed

is_module_installed(module_name, throw_error=False)

Check if the module is installed or not.

Examples:

>>> is_module_installed(module_name="yaml", throw_error=False)
True
>>> is_module_installed(module_name="numpy", throw_error=False)
False
>>> is_module_installed(module_name="numpy", throw_error=True)
Traceback (most recent call last):
ImportError: Module numpy is not installed.

Parameters:

Name Type Description Default
module_name str

Name of the module to be checked.

required
throw_error bool

If True, raises ImportError if module is not installed.

False

Returns:

Type Description
bool

Returns True if module is installed, False otherwise.

Raises:

Type Description
ImportError

If throw_error is True and module is not installed.

Source code in api/utils/general.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def is_module_installed(module_name: str, throw_error: bool = False) -> bool:
    """Check if the module is installed or not.

    Examples:
        >>> is_module_installed(module_name="yaml", throw_error=False)
        True
        >>> is_module_installed(module_name="numpy", throw_error=False)
        False
        >>> is_module_installed(module_name="numpy", throw_error=True)
        Traceback (most recent call last):
        ImportError: Module numpy is not installed.

    Args:
        module_name: Name of the module to be checked.
        throw_error: If True, raises ImportError if module is not installed.

    Returns:
        Returns True if module is installed, False otherwise.

    Raises:
        ImportError: If throw_error is True and module is not installed.
    """
    try:
        importlib.import_module(module_name)
        return True
    except ImportError as e:
        if throw_error:
            message = f"Module {module_name} is not installed."
            raise ImportError(message) from e
        return False

movie

Utility functions for interacting with the TMDB API.

fuzzy_search_movies

fuzzy_search_movies(query, threshold=60, limit=5, include_backdrops=True)

Search movies with fuzzy matching.

Examples:

>>> results = fuzzy_search_movies("Matrix")
>>> isinstance(results, list)
True
>>> all(isinstance(movie, dict) for movie in results)
True

Parameters:

Name Type Description Default
query str

The search term to look for.

required
threshold int

Minimum similarity score (0-100) for fuzzy matching.

60
limit int

Maximum number of results to return.

5
include_backdrops bool

Whether to include backdrop images in results (default: True).

True

Returns:

Type Description
list[dict] | None

A list of movie dictionaries that match the search criteria, or None if no matches found.

Source code in api/utils/movie.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
@timing_decorator
def fuzzy_search_movies(
    query: str, threshold: int = 60, limit: int = 5, include_backdrops: bool = True
) -> list[dict] | None:
    """Search movies with fuzzy matching.

    Examples:
        >>> results = fuzzy_search_movies("Matrix")
        >>> isinstance(results, list)
        True
        >>> all(isinstance(movie, dict) for movie in results)
        True

    Args:
        query: The search term to look for.
        threshold: Minimum similarity score (0-100) for fuzzy matching.
        limit: Maximum number of results to return.
        include_backdrops: Whether to include backdrop images in results (default: True).

    Returns:
        A list of movie dictionaries that match the search criteria, or None if no matches found.
    """
    # Get initial results from TMDB
    results = search_api.movies(query)

    # Apply fuzzy matching
    fuzzy_matches = []
    for result in results:
        # Safely get title, skip if not a string
        title = getattr(result, "title", None)
        if not isinstance(title, str):
            logger.warning(f"Invalid title type for movie: {type(title)}")
            continue

        # Calculate similarity ratio
        ratio = fuzz.ratio(query.lower(), title.lower())

        if ratio >= threshold:
            backdrop_image_url = FALLBACK_IMAGE_URL
            if include_backdrops is True:
                backdrops = get_movie_backdrops(result.id)
                if backdrops:
                    backdrop_image_url = f"{TMDB_IMG_BASE_PATH}{backdrops[0]}"

            fuzzy_matches.append(
                {
                    "title": title,
                    "similarity": ratio,
                    "id": result.id,
                    "release_date": getattr(result, "release_date", "N/A"),
                    "overview": getattr(result, "overview", "N/A"),
                    "backdrop_image_url": backdrop_image_url,
                }
            )

    if not fuzzy_matches:
        return None

    # Sort by similarity score
    sorted_matches = sorted(fuzzy_matches, key=lambda x: x["similarity"], reverse=True)

    return sorted_matches[:limit]

get_movie_backdrops

get_movie_backdrops(movie_id)

Get all available backdrops for a movie.

Examples:

>>> backdrops = get_movie_backdrops(550)
>>> isinstance(backdrops, list)
True
>>> all(isinstance(path, str) for path in backdrops)
True

Parameters:

Name Type Description Default
movie_id int

The TMDB ID of the movie.

required

Returns:

Type Description
list[str]

A list of strings representing backdrop file paths.

Source code in api/utils/movie.py
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
@timing_decorator
def get_movie_backdrops(movie_id: int) -> list[str]:
    """Get all available backdrops for a movie.

    Examples:
        >>> backdrops = get_movie_backdrops(550)
        >>> isinstance(backdrops, list)
        True
        >>> all(isinstance(path, str) for path in backdrops)
        True

    Args:
        movie_id: The TMDB ID of the movie.

    Returns:
        A list of strings representing backdrop file paths.
    """
    images = movie_api.images(movie_id=movie_id, include_image_language="en,null")
    return [img.file_path for img in images.backdrops]

get_movie_posters

get_movie_posters(movie_id)

Get all available posters for a movie.

Examples:

>>> posters = get_movie_posters(550)
>>> isinstance(posters, list)
True
>>> all(isinstance(path, str) for path in posters)
True

Parameters:

Name Type Description Default
movie_id int

The TMDB ID of the movie.

required

Returns:

Type Description
list[str]

A list of strings representing poster file paths.

Source code in api/utils/movie.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@timing_decorator
def get_movie_posters(movie_id: int) -> list[str]:
    """Get all available posters for a movie.

    Examples:
        >>> posters = get_movie_posters(550)
        >>> isinstance(posters, list)
        True
        >>> all(isinstance(path, str) for path in posters)
        True

    Args:
        movie_id: The TMDB ID of the movie.

    Returns:
        A list of strings representing poster file paths.
    """
    images = movie_api.images(movie_id=movie_id, include_image_language="en,null")
    return [img.file_path for img in images.posters]

get_random_movie

get_random_movie(category='popular')

Get a random movie from specified TMDB category.

Parameters:

Name Type Description Default
category str

The category to select from (default: "popular") Options: "popular", "top_rated", "now_playing", "upcoming"

'popular'

Returns:

Type Description
Movie

A Movie object representing a randomly selected movie from the specified category.

Source code in api/utils/movie.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def get_random_movie(category: str = "popular") -> Movie:
    """Get a random movie from specified TMDB category.

    Args:
        category: The category to select from (default: "popular")
                 Options: "popular", "top_rated", "now_playing", "upcoming"

    Returns:
        A Movie object representing a randomly selected movie from the specified category.
    """
    # Get the category method or default to popular if invalid
    category_method = MOVIE_CATEGORIES.get(category, MOVIE_CATEGORIES["popular"])
    # Get movies from the category
    movies = category_method()
    return random.choice(movies)

get_random_movie_with_details

get_random_movie_with_details(min_backdrops=5, category='popular', depth=0, max_depth=5)

Get a random movie with at least specified number of backdrops.

Parameters:

Name Type Description Default
min_backdrops int

Minimum number of backdrops required (default: 5)

5
category str

The category to select from (default: "popular") Options: "popular", "top_rated", "now_playing", "upcoming"

'popular'
depth int

Current recursion depth (default: 0)

0

Returns:

Type Description
dict

A dictionary containing movie details including title, backdrops, etc.

Source code in api/utils/movie.py
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
@timing_decorator
def get_random_movie_with_details(
    min_backdrops: int = 5,
    category: str = "popular",
    depth: int = 0,
    max_depth: int = 5,
) -> dict:
    """Get a random movie with at least specified number of backdrops.

    Args:
        min_backdrops: Minimum number of backdrops required (default: 5)
        category: The category to select from (default: "popular")
                 Options: "popular", "top_rated", "now_playing", "upcoming"
        depth: Current recursion depth (default: 0)

    Returns:
        A dictionary containing movie details including title, backdrops, etc.
    """
    movie = get_random_movie(category)
    backdrops = get_movie_backdrops(movie.id)

    # Recursively try another movie if this one doesn't have enough backdrops
    if len(backdrops) < min_backdrops:
        logger.debug(
            f"Movie {movie.title} has {len(backdrops)} backdrops, trying another..."
        )
        return (
            get_random_movie_with_details(min_backdrops, category, depth + 1)
            if depth < max_depth
            else {"error": "Max recursion depth reached"}
        )

    return {
        "id": movie.id,
        "title": movie.title,
        "backdrops": backdrops,
        "overview": getattr(movie, "overview", "N/A"),
        "release_date": getattr(movie, "release_date", "N/A"),
    }