Skip to content

Commit 1bd8156

Browse files
authored
Merge pull request #17 from hackersandslackers/feature/Python310-Update
Updated Python version & dependencies.
2 parents 31e25ad + da1b5fe commit 1bd8156

22 files changed

+606
-710
lines changed

.env.example

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
SQLALCHEMY_DATABASE_URI=mysql+pymysql://myuser:[email protected]:1234/mydatabase
2-
SQLALCHEMY_DATABASE_PEM="-----BEGIN CERTIFICATE-----\nghdfigfjvgkjdfvfjkhcvdfjhvfghjbfdvfjshdvjghvfgjvcfjdcvckdjh\n-----END CERTIFICATE-----\n"
1+
DATABASE_USERNAME="yourusername"
2+
DATABASE_PASSWORD="yourpassword"
3+
DATABASE_HOST="db.host.com"
4+
DATABASE_PORT=12345
5+
DATABASE_TABLE="table"
6+
DATABASE_CERT_FILE="ca-certificate.crt"
File renamed without changes.

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ venv/
8989
ENV/
9090
env.bak/
9191
venv.bak/
92+
creds/
93+
**/*.crt
9294

9395
# Spyder project settings
9496
.spyderproject
@@ -115,6 +117,7 @@ ca-certificate.crt
115117

116118
# Idea
117119
.idea/
120+
.vscode/
118121

119122
# logs
120123
logs/*

Makefile

+59-39
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,91 @@
1-
SRCPATH := $(shell pwd)
2-
PROJECTNAME := $(shell basename $(CURDIR))
3-
ENTRYPOINT := $(PROJECTNAME).ini
1+
PROJECT_NAME := $(shell basename $CURDIR)
2+
VIRTUAL_ENV := $(CURDIR)/.venv
3+
LOCAL_PYTHON := $(VIRTUAL_ENV)/bin/python3
44

55
define HELP
6-
Manage $(PROJECTNAME). Usage:
7-
8-
make run - Run $(PROJECTNAME).
9-
make deploy - Pull latest build and deploy to production.
10-
make update - Update pip dependencies via Python Poetry.
11-
make format - Format code with Python's `Black` library.
12-
make lint - Check code formatting with flake8
13-
make clean - Remove cached files and lock files.
14-
endef
15-
export HELP
16-
6+
Manage $(PROJECT_NAME). Usage:
177

18-
.PHONY: run restart deploy update format lint clean help
8+
make run - Run $(PROJECT_NAME) locally.
9+
make install - Create local virtualenv & install dependencies.
10+
make deploy - Set up project & run locally.
11+
make update - Update dependencies via Poetry and output resulting `requirements.txt`.
12+
make format - Run Python code formatter & sort dependencies.
13+
make lint - Check code formatting with flake8.
14+
make clean - Remove extraneous compiled files, caches, logs, etc.
1915

20-
requirements: .requirements.txt
21-
env: ./.venv/bin/activate
16+
endef
17+
export HELP
2218

23-
.requirements.txt: requirements.txt
24-
$(shell . .venv/bin/activate && pip install -r requirements.txt)
2519

20+
.PHONY: run install deploy update format lint clean help
2621

2722
all help:
2823
@echo "$$HELP"
2924

25+
env: $(VIRTUAL_ENV)
26+
27+
$(VIRTUAL_ENV):
28+
if [ ! -d $(VIRTUAL_ENV) ]; then \
29+
echo "Creating Python virtual env in \`${VIRTUAL_ENV}\`"; \
30+
python3 -m venv $(VIRTUAL_ENV); \
31+
fi
32+
33+
.PHONY: dev
34+
dev: env
35+
$(LOCAL_PYTHON) -m main --reload
3036

3137
.PHONY: run
3238
run: env
33-
python main.py
39+
$(LOCAL_PYTHON) -m main
3440

41+
.PHONY: install
42+
install: env
43+
$(LOCAL_PYTHON) -m pip install --upgrade pip setuptools wheel && \
44+
$(LOCAL_PYTHON) -m pip install -r requirements.txt && \
45+
echo Installed dependencies in \`${VIRTUAL_ENV}\`;
3546

3647
.PHONY: deploy
3748
deploy:
38-
make clean
39-
$(shell . ./deploy.sh)
49+
make install && \
50+
make run
4051

52+
.PHONY: test
53+
test: env
54+
$(LOCAL_PYTHON) -m \
55+
coverage run -m pytest -vv \
56+
--disable-pytest-warnings && \
57+
coverage html --title='Coverage Report' -d .reports && \
58+
open .reports/index.html
4159

4260
.PHONY: update
4361
update: env
44-
.venv/bin/python3 -m pip install --upgrade pip setuptools wheel
45-
poetry update
46-
poetry export -f requirements.txt --output requirements.txt --without-hashes
47-
62+
$(LOCAL_PYTHON) -m pip install --upgrade pip setuptools wheel && \
63+
poetry update && \
64+
poetry export -f requirements.txt --output requirements.txt --without-hashes && \
65+
echo Installed dependencies in \`${VIRTUAL_ENV}\`;
4866

4967
.PHONY: format
5068
format: env
51-
$(shell . .venv/bin/activate && isort ./)
52-
$(shell . .venv/bin/activate && black ./)
53-
69+
$(LOCAL_PYTHON) -m isort --multi-line=3 . && \
70+
$(LOCAL_PYTHON) -m black .
5471

5572
.PHONY: lint
56-
lint:
57-
flake8 . --count \
73+
lint: env
74+
$(LOCAL_PYTHON) -m flake8 . --count \
5875
--select=E9,F63,F7,F82 \
59-
--exclude .git,.github,__pycache__,.pytest_cache,.venv,logs,creds,.venv,docs,logs \
76+
--exclude .git,.github,__pycache__,.pytest_cache,.venv,logs,creds,.venv,docs,logs,.reports \
6077
--show-source \
6178
--statistics
6279

63-
6480
.PHONY: clean
6581
clean:
66-
find . -name '*.pyc' -delete
67-
find . -name '__pycache__' -delete
68-
find . -name 'poetry.lock' -delete
69-
find . -name 'Pipefile.lock' -delete
70-
find . -name 'logs/*' -delete
71-
find . -name '.pytest_cache' -delete
82+
find . -name 'poetry.lock' -delete && \
83+
find . -name '.coverage' -delete && \
84+
find . -name '.Pipfile.lock' -delete && \
85+
find . -wholename '**/*.pyc' -delete && \
86+
find . -type d -wholename '__pycache__' -exec rm -rf {} + && \
87+
find . -type d -wholename './.venv' -exec rm -rf {} + && \
88+
find . -type d -wholename '.pytest_cache' -exec rm -rf {} + && \
89+
find . -type d -wholename '**/.pytest_cache' -exec rm -rf {} + && \
90+
find . -type d -wholename './logs/*.log' -exec rm -rf {} + && \
91+
find . -type d -wholename './.reports/*' -exec rm -rf {} +

README.md

+16-13
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# SQLAlchemy Tutorial
22

3-
![Python](https://img.shields.io/badge/Python-v^3.8-blue.svg?logo=python&longCache=true&logoColor=white&colorB=5e81ac&style=flat-square&colorA=4c566a)
4-
![SQLAlchemy](https://img.shields.io/badge/SQLAlchemy-v^1.4.0-blue.svg?longCache=true&logo=python&style=flat-square&logoColor=white&colorB=5e81ac&colorA=4c566a)
5-
![PyMySQL](https://img.shields.io/badge/PyMySQL-v^1.0.0-red.svg?longCache=true&style=flat-square&logo=scala&logoColor=white&colorA=4c566a&colorB=bf616a)
3+
![Python](https://img.shields.io/badge/Python-v^3.10-blue.svg?logo=python&longCache=true&logoColor=white&colorB=5e81ac&style=flat-square&colorA=4c566a)
4+
![SQLAlchemy](https://img.shields.io/badge/SQLAlchemy-v^2.0.20-blue.svg?longCache=true&logo=python&style=flat-square&logoColor=white&colorB=5e81ac&colorA=4c566a)
5+
![PyMySQL](https://img.shields.io/badge/PyMySQL-v^1.1.0-red.svg?longCache=true&style=flat-square&logo=scala&logoColor=white&colorA=4c566a&colorB=bf616a)
66
![GitHub Last Commit](https://img.shields.io/github/last-commit/google/skia.svg?style=flat-square&colorA=4c566a&colorB=a3be8c&logo=GitHub)
77
[![GitHub Issues](https://img.shields.io/github/issues/hackersandslackers/sqlalchemy-tutorial.svg?style=flat-square&colorA=4c566a&logo=GitHub&colorB=ebcb8b)](https://github.com/hackersandslackers/sqlalchemy-tutorial/issues)
88
[![GitHub Stars](https://img.shields.io/github/stars/hackersandslackers/sqlalchemy-tutorial.svg?style=flat-square&colorA=4c566a&logo=GitHub&colorB=ebcb8b)](https://github.com/hackersandslackers/sqlalchemy-tutorial/stargazers)
99
[![GitHub Forks](https://img.shields.io/github/forks/hackersandslackers/sqlalchemy-tutorial.svg?style=flat-square&colorA=4c566a&logo=GitHub&colorB=ebcb8b)](https://github.com/hackersandslackers/sqlalchemy-tutorial/network)
1010

11-
![SQLAlchemy Tutorial](https://github.com/hackersandslackers/sqlalchemy-tutorial/blob/master/.github/[email protected]?raw=true)
11+
![SQLAlchemy Tutorial](https://github.com/hackersandslackers/sqlalchemy-tutorial/blob/master/.github/img/[email protected]?raw=true)
1212

1313
This repository contains the source code for a four-part tutorial series on SQLAlchemy:
1414

@@ -17,29 +17,32 @@ This repository contains the source code for a four-part tutorial series on SQLA
1717
3. [Relationships in SQLAlchemy Data Models](https://hackersandslackers.com/sqlalchemy-data-models)
1818
4. [Constructing Database Queries with SQLAlchemy](https://hackersandslackers.com/database-queries-sqlalchemy-orm)
1919

20-
# Getting Started
20+
## Getting Started
2121

2222
Get set up locally in two steps:
2323

2424
### Environment Variables
2525

2626
Replace the values in **.env.example** with your values and rename this file to **.env**:
2727

28-
29-
* `SQLALCHEMY_DATABASE_URI`: Connection URI of a SQL database.
30-
* `SQLALCHEMY_DATABASE_PEM` _(Optional)_: PEM key for databases requiring an SSL connection.
28+
* `DATABASE_USERNAME`: Username for a SQL database.
29+
* `DATABASE_PASSWORD`: Corresponding password for the above SQL database user.
30+
* `DATABASE_HOST`: Host of the SQL database.
31+
* `DATABASE_PORT`: Numerical port of the SQL database.
32+
* `DATABASE_TABLE`: Name of the SQL database table.
33+
* `DATABASE_CERT_FILE` _(optional)_: Path to SSL certificate file for database.
3134

3235
*Remember never to commit secrets saved in .env files to Github.*
3336

3437
### Installation
3538

36-
Get up and running with `make deploy`:
39+
Get up and running with `make run`:
3740

3841
```shell
39-
$ git clone https://github.com/hackersandslackers/sqlalchemy-tutorial.git
40-
$ cd sqlalchemy-tutorial
41-
$ make deploy
42-
```
42+
git clone https://github.com/hackersandslackers/sqlalchemy-tutorial.git
43+
cd sqlalchemy-tutorial
44+
make run
45+
```
4346

4447
-----
4548

config.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Database config."""
2-
from os import environ, path
2+
from os import getenv, path
33

44
from dotenv import load_dotenv
55

@@ -8,8 +8,14 @@
88
load_dotenv(path.join(basedir, ".env"))
99

1010
# Database connection variables
11-
SQLALCHEMY_DATABASE_URI = environ.get("SQLALCHEMY_DATABASE_URI")
12-
SQLALCHEMY_DATABASE_PEM = environ.get("SQLALCHEMY_DATABASE_PEM")
11+
DATABASE_USERNAME = getenv("DATABASE_USERNAME")
12+
DATABASE_PASSWORD = getenv("DATABASE_PASSWORD")
13+
DATABASE_HOST = getenv("DATABASE_HOST")
14+
DATABASE_PORT = getenv("DATABASE_PORT")
15+
DATABASE_TABLE = getenv("DATABASE_TABLE")
16+
DATABASE_CERT_FILE = getenv("DATABASE_CERT_FILE")
17+
18+
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{DATABASE_USERNAME}:{DATABASE_PASSWORD}@{DATABASE_HOST}:{DATABASE_PORT}/{DATABASE_TABLE}?ssl_ca={DATABASE_CERT_FILE}"
1319

1420
# Reset data after each run
1521
CLEANUP_DATA = False

database/__init__.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
1-
from .connect import engine, session
1+
"""Create SQLAlchemy engine and session objects."""
2+
from sqlalchemy import create_engine
3+
from sqlalchemy.orm import sessionmaker
4+
5+
from config import SQLALCHEMY_DATABASE_URI
6+
7+
# Create database engine
8+
engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=False)
9+
10+
# Create database session
11+
Session = sessionmaker(bind=engine)
12+
session = Session()

database/connect.py

-14
This file was deleted.

deploy.sh

-12
This file was deleted.

logger.py

+10-25
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,19 @@ def formatter(log: dict) -> str:
88
"""
99
Format log colors based on level.
1010
11-
:param log: Logged event stored as map containing contextual metadata.
12-
:type log: dict
11+
:param dict log: Logged event stored as map containing contextual metadata.
12+
1313
:returns: str
1414
"""
15+
if log["level"].name == "INFO":
16+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #b3cfe7>{level}</fg #b3cfe7>: <light-white>{message}</light-white>\n"
1517
if log["level"].name == "WARNING":
16-
return (
17-
"<white>{time:MM-DD-YYYY HH:mm:ss}</white> | "
18-
"<light-yellow>{level}</light-yellow>: "
19-
"<light-white>{message}</light-white> \n"
20-
)
21-
elif log["level"].name == "ERROR":
22-
return (
23-
"<white>{time:MM-DD-YYYY HH:mm:ss}</white> | "
24-
"<light-red>{level}</light-red>: "
25-
"<light-white>{message}</light-white> \n"
26-
)
27-
elif log["level"].name == "SUCCESS":
28-
return (
29-
"<white>{time:MM-DD-YYYY HH:mm:ss}</white> | "
30-
"<light-green>{level}</light-green>: "
31-
"<light-white>{message}</light-white> \n"
32-
)
33-
else:
34-
return (
35-
"<white>{time:MM-DD-YYYY HH:mm:ss}</white> | "
36-
"<fg #67c9c4>{level}</fg #67c9c4>: "
37-
"<light-white>{message}</light-white> \n"
38-
)
18+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #b09057>{level}</fg #b09057>: <light-white>{message}</light-white>\n"
19+
if log["level"].name == "SUCCESS":
20+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #6dac77>{level}</fg #6dac77>: <light-white>{message}</light-white>\n"
21+
if log["level"].name == "ERROR":
22+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #a35252>{level}</fg #a35252>: <light-white>{message}</light-white>\n"
23+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #b3cfe7>{level}</fg #b3cfe7>: <light-white>{message}</light-white>\n"
3924

4025

4126
def create_logger() -> custom_logger:

mypy.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[mypy]
2-
python_version = 3.8
2+
python_version = 3.10
33
warn_return_any = True
44
warn_unused_configs = True

0 commit comments

Comments
 (0)