A Python project that manages a movie database using SQLite, integrates with the OMDb API for metadata and posters, and generates a static website to display movies with ratings and posters.
tree
├── _static
│ ├── index_template.html
│ ├── index.html
│ └── style.css
├── batch_import.py
├── Histogram_ratings.png
├── movie_storage_sql.py
├── movie_storage.py
├── movies.db
├── movies.json
├── movies.py
├── requirements.txt
└── test_movies.py
2 directories, 12 files- SQLite database with schema self-healing (
poster_urlcolumn). - OMDb API integration for fetching movie details and posters.
- CLI menu (
movies.py) for adding, deleting, updating, searching, and generating stats. - Static website generator with grid layout (10 movies per row).
- Visualizations: rating histograms and charts.
- Unit tests with
pytest.
- Install dependencies:
pip install -r requirements.txt
Set your OMDb API key:
sign up and replace with OMDb API key https://www.omdbapi.com/apikey.aspx
export OMDB_API_KEY=your_api_key_hereRun the CLI:
python3 movies.py********** Movies Database **********
0. Exit
1. List movies
2. Add movie (OMDb)
3. Delete movie
4. Update movie
5. Stats
6. Random movie
7. Search movie
8. Movies sorted by rating
9. Create Rating Histogram
10. Movies sorted by year
11. Filter movies by minimum rating
12. Generate website
Enter choice (0-12): 0
Bye!Generate the website (menu option 12):
Output: _static/index.html
Open in browser to view movie grid.
🔧 Best Practice:
‣ Keep Black first (formatting).
‣ Run Ruff second (fast linting).
‣ Run Pylint third (deep linting).
‣ Run Pytest last (validation).
‣ Configure Ruff/Pylint to ignore style rules Black enforces (line length, etc.).
Execute black:
black .
reformatted ~/movie-project-sql-plus-html-plus-api/movies.py
All done! ✨ 🍰 ✨
1 file reformatted, 4 files left unchanged.Execute ruff:
ruff check --fix .
All checks passed!Execute pylint on Project root folder files:
pylint movies.py movie_storage_sql.py
************* Module movies
movies.py:25:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:42:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:50:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:57:19: W3101: Missing timeout argument for method 'requests.get' can cause your program to hang indefinitely (missing-timeout)
movies.py:89:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:97:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:112:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:134:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:143:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:163:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:173:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:193:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:218:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:285:0: C0116: Missing function or method docstring (missing-function-docstring)
movies.py:12:0: C0411: standard import "statistics" should be placed before third party import "requests" (wrong-import-order)
movies.py:13:0: C0411: standard import "difflib" should be placed before third party import "requests" (wrong-import-order)
************* Module movie_storage_sql
movie_storage_sql.py:78:0: C0301: Line too long (119/100) (line-too-long)
movie_storage_sql.py:1:0: C0114: Missing module docstring (missing-module-docstring)
movie_storage_sql.py:61:29: W0621: Redefining name 'connection' from outer scope (line 29) (redefined-outer-name)
movie_storage_sql.py:62:8: W0621: Redefining name 'result' from outer scope (line 47) (redefined-outer-name)
movie_storage_sql.py:74:29: W0621: Redefining name 'connection' from outer scope (line 29) (redefined-outer-name)
movie_storage_sql.py:89:15: W0718: Catching too general exception Exception (broad-exception-caught)
movie_storage_sql.py:95:29: W0621: Redefining name 'connection' from outer scope (line 29) (redefined-outer-name)
movie_storage_sql.py:97:12: W0621: Redefining name 'result' from outer scope (line 47) (redefined-outer-name)
movie_storage_sql.py:105:15: W0718: Catching too general exception Exception (broad-exception-caught)
movie_storage_sql.py:111:29: W0621: Redefining name 'connection' from outer scope (line 29) (redefined-outer-name)
movie_storage_sql.py:113:12: W0621: Redefining name 'result' from outer scope (line 47) (redefined-outer-name)
movie_storage_sql.py:122:15: W0718: Catching too general exception Exception (broad-exception-caught)
------------------------------------------------------------------
Your code has been rated at 8.91/10 (previous run: 8.79/10, +0.12)🧪 Testing Run unit tests with:
Pytest unit tests
Execute pytest:
pytest -v
================= test session starts ==================
pytest-9.0.1, pluggy-1.6.0 -- ~/movie-project-sql-html-api-pyenv/bin/python3
cachedir: .pytest_cache
rootdir: /movie-project-sql-plus-html-plus-api
collected 4 items
test_movies.py::test_add_and_list_movie PASSED [ 25%]
test_movies.py::test_update_movie_rating PASSED [ 50%]
test_movies.py::test_delete_movie PASSED [ 75%]
test_movies.py::test_add_movie_via_command PASSED [100%]
================== 4 passed in 1.94s ==================📌 Notes
‣ Avoid hardcoding absolute paths for portability (Codio, cloud environments).
‣ Use environment variable MOVIES_DB_PATH to override DB location if needed.
‣ CSS Grid ensures no more than 10 movies per row in the generated site.