Compare commits

..

12 Commits

Author SHA1 Message Date
Eugene Morozov
fb0187db5d Release 0.5: Updated libs
All checks were successful
Build Docker Image / build-and-deploy-image (pg15) (push) Successful in 1m44s
Build Docker Image / build-and-deploy-image (pg16) (push) Successful in 1m41s
Build Docker Image / build-and-deploy-image (pg17) (push) Successful in 1m43s
2025-06-07 20:30:38 +03:00
Eugene Morozov
ba2a897d18 Removed pg14, Added pg17, bump alpine, move to matrix
All checks were successful
Build Docker Image / build-and-deploy-image (pg15) (push) Successful in 1m37s
Build Docker Image / build-and-deploy-image (pg16) (push) Successful in 1m35s
Build Docker Image / build-and-deploy-image (pg17) (push) Successful in 1m33s
2024-12-08 13:28:56 +02:00
Eugene Morozov
f073e33e59 Added gitea support; Updated libs
All checks were successful
Build Docker Image / build-and-deploy-image (push) Successful in 5m39s
2024-07-07 17:38:40 +03:00
Eugene Morozov
1d01dfe84d Update libs; Removed support PostgreSQL 13 2024-05-28 10:59:02 +03:00
95ec028bf4 Release 0.4: Added Postgres 16; Upgraded Alpine 19 and Python 3.11; 2023-12-10 08:32:48 +00:00
Eugene Morozov
d639be40e9 Release 0.3: Added dockerignore (#6); Added SCHEDULE setting (#7); Added support postgres 15 (#8); Updated libs; 2023-12-10 08:05:46 +00:00
Eugene Morozov
fdc1825e19 Merge branch 'v0.2' into 'main'
V0.2

See merge request technocloud/docker-postgres-backup!4
2022-08-29 17:31:41 +00:00
Eugene Morozov
d9bf4df6a4 V0.2 2022-08-29 17:31:41 +00:00
Eugene Morozov
1f7f58b359 Merge branch 'prefix' into 'main'
Added prefix for backup filename

See merge request technocloud/docker-postgres-backup!3
2022-08-29 17:31:22 +00:00
Eugene Morozov
d9d35983f1 Used alpine as a based image
See merge request technocloud/docker-postgres-backup!2
2022-08-29 17:31:08 +00:00
9059c41dbc Added prefix for backup filename 2022-08-05 12:54:06 +03:00
80c9dc8f0f Used alpine as a based image 2022-08-05 12:41:23 +03:00
15 changed files with 245 additions and 438 deletions

7
.dockerignore Normal file
View File

@@ -0,0 +1,7 @@
.python-version
.idea
Dockerfile*
.pre-commit-config.yaml
.gitlab-ci.yml
.flake8
.gitignore

View File

@@ -1,4 +1,4 @@
[flake8] [flake8]
max-line-length = 90 max-line-length = 100
extend-ignore = E203, W503 extend-ignore = E203, W503
exclude = */migrations/*.py exclude = */migrations/*.py

View File

@@ -0,0 +1,47 @@
name: Build Docker Image
on:
push:
branches:
- main
schedule:
- cron: '@monthly'
jobs:
build-and-deploy-image:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
env:
DOCKER_ORG: technocloud-public
RUNNER_TOOL_CACHE: /toolcache
strategy:
matrix:
postgres-version: ['pg15', 'pg16', 'pg17']
steps:
- name: Checkout
uses: actions/checkout@v4
with:
github-server-url: https://gitea.technocloud.ee
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
- name: Login to DockerHub
uses: docker/login-action@v3
with:
registry: gitea.technocloud.ee
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get Meta
id: meta
run: |
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
- name: Build and Push image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile.${{ matrix.postgres-version }}
platforms: linux/amd64,linux/arm64
push: true
tags: gitea.technocloud.ee/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ matrix.postgres-version }}

2
.gitignore vendored
View File

@@ -1,2 +1,2 @@
/.python-version .python-version
.idea .idea

View File

@@ -1,13 +0,0 @@
# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
stages:
- test
sast:
stage: test
include:
- template: Security/SAST.gitlab-ci.yml

View File

@@ -1,10 +1,10 @@
exclude: 'docs|node_modules|migrations|.git|.tox' exclude: 'docs|node_modules|migrations|.git|.tox'
default_stages: [commit] default_stages: [pre-commit]
fail_fast: true fail_fast: false
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1 rev: v5.0.0
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
- id: check-ast - id: check-ast
@@ -13,12 +13,12 @@ repos:
- id: check-toml - id: check-toml
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 21.12b0 rev: 25.1.0
hooks: hooks:
- id: black - id: black
- repo: https://github.com/timothycrosley/isort - repo: https://github.com/timothycrosley/isort
rev: 5.10.1 rev: 6.0.1
hooks: hooks:
- id: isort - id: isort
@@ -27,13 +27,13 @@ repos:
hooks: hooks:
- id: dodgy - id: dodgy
- repo: https://gitlab.com/pycqa/flake8 - repo: https://github.com/pycqa/flake8
rev: 4.0.1 rev: 7.2.0
hooks: hooks:
- id: flake8 - id: flake8
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v2.31.0 rev: v3.20.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py310-plus] args: [--py312-plus]

View File

@@ -1,32 +0,0 @@
FROM python:3.10-slim-bullseye
ENV HOME=/home/app \
APP_HOME=/home/app/docker-postgres-backup \
\
# python
PYTHONPATH=${PYTHONPATH}:${PWD} \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
\
# pip
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
\
# language locales
LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8
RUN apt-get update && apt-get install -y --no-install-recommends locales postgresql-client-13 tini && \
apt-get -y --purge autoremove && apt-get clean && rm -rf /var/cache/apt && \
sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen && pip install -U pip
COPY ./ $APP_HOME
WORKDIR $APP_HOME
RUN python -m pip install $APP_HOME
ENTRYPOINT ["tini", "--"]
CMD ["python", "start.py"]

View File

@@ -1,35 +0,0 @@
FROM python:3.10-slim-bullseye
ENV HOME=/home/app \
APP_HOME=/home/app/docker-postgres-backup \
\
# python
PYTHONPATH=${PYTHONPATH}:${PWD} \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
\
# pip
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
\
# language locales
LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8
RUN apt-get update && apt-get install -y --no-install-recommends locales curl ca-certificates gnupg tini && \
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null && \
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \
apt-get update && apt-get -y --no-install-recommends install postgresql-client-14 && \
apt-get -y --purge autoremove && apt-get clean && rm -rf /var/cache/apt && \
sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen && pip install -U pip
COPY ./ $APP_HOME
WORKDIR $APP_HOME
RUN python -m pip install $APP_HOME
ENTRYPOINT ["tini", "--"]
CMD ["python", "start.py"]

20
Dockerfile.pg15 Normal file
View File

@@ -0,0 +1,20 @@
FROM alpine:3.22
ENV APP_HOME=/home/app/docker-postgres-backup \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_BREAK_SYSTEM_PACKAGES=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
LANG=en_US.UTF-8
RUN apk --no-cache add postgresql15-client python3 py3-pip tini
COPY ./ $APP_HOME
WORKDIR $APP_HOME
RUN python3 -m pip install $APP_HOME
ENTRYPOINT ["tini", "--"]
CMD ["python3", "start.py"]

20
Dockerfile.pg16 Normal file
View File

@@ -0,0 +1,20 @@
FROM alpine:3.22
ENV APP_HOME=/home/app/docker-postgres-backup \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_BREAK_SYSTEM_PACKAGES=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
LANG=en_US.UTF-8
RUN apk --no-cache add postgresql16-client python3 py3-pip tini
COPY ./ $APP_HOME
WORKDIR $APP_HOME
RUN python3 -m pip install $APP_HOME
ENTRYPOINT ["tini", "--"]
CMD ["python3", "start.py"]

20
Dockerfile.pg17 Normal file
View File

@@ -0,0 +1,20 @@
FROM alpine:3.22
ENV APP_HOME=/home/app/docker-postgres-backup \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_BREAK_SYSTEM_PACKAGES=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
LANG=en_US.UTF-8
RUN apk --no-cache add postgresql17-client python3 py3-pip tini
COPY ./ $APP_HOME
WORKDIR $APP_HOME
RUN python3 -m pip install $APP_HOME
ENTRYPOINT ["tini", "--"]
CMD ["python3", "start.py"]

View File

@@ -5,16 +5,17 @@ This docker image provides functionality:
1. Backup your PostgresSQL database to sql file using pg_dump 1. Backup your PostgresSQL database to sql file using pg_dump
2. Compress sql file using LZMA2 2. Compress sql file using LZMA2
3. Upload compressed file to S3 storage 3. Upload compressed file to S3 storage
4. Scheduled to run every hour 4. Backup running schedule (monthly, weekly, daily, hourly)
# Versions # Versions
You can use two versions: You can use four versions:
- PostgreSQL 13: `registry.gitlab.com/technocloud/docker-postgres-backup/docker-postgres-backup:pg13`
- PostgreSQL 14: `registry.gitlab.com/technocloud/docker-postgres-backup/docker-postgres-backup:pg14` - PostgreSQL 14: `registry.gitlab.com/technocloud/docker-postgres-backup/docker-postgres-backup:pg14`
- PostgreSQL 15: `registry.gitlab.com/technocloud/docker-postgres-backup/docker-postgres-backup:pg15`
- PostgreSQL 16: `registry.gitlab.com/technocloud/docker-postgres-backup/docker-postgres-backup:pg16`
# SETTINGS # SETTINGS
You can set some envs vars: You can set some envs vars:
- DEBUG - run every 1 minute if 1, default is 0 - SCHEDULE - can be monthly, weekly, daily, hourly (by default)
- DB_USER - user to connect DB, default is postgres - DB_USER - user to connect DB, default is postgres
- DB_PASSWORD - password to connect DB, default is postgres - DB_PASSWORD - password to connect DB, default is postgres
- DB_HOST - host to connect DB, default is localhost - DB_HOST - host to connect DB, default is localhost
@@ -22,6 +23,7 @@ You can set some envs vars:
- DB_NAME - database to back up, default is postgres - DB_NAME - database to back up, default is postgres
- TIME_ZONE - timezone for datetime using in filenames, default is Europe/Tallinn - TIME_ZONE - timezone for datetime using in filenames, default is Europe/Tallinn
- COMPRESSION_LEVEL - level of LZMA compression, default is 7 - COMPRESSION_LEVEL - level of LZMA compression, default is 7
- PREFIX - prefix for backup filename, default is empty
Also, please define settings for S3 storage: Also, please define settings for S3 storage:
- AWS_S3_REGION_NAME - default nl-ams - AWS_S3_REGION_NAME - default nl-ams
@@ -29,3 +31,7 @@ Also, please define settings for S3 storage:
- AWS_ACCESS_KEY_ID - AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY - AWS_SECRET_ACCESS_KEY
- AWS_BUCKET_NAME - AWS_BUCKET_NAME
# Build docker
`docker buildx build --platform=linux/arm64/v8,linux/amd64 --push --tag registry.gitlab.com/technocloud/docker-postgres-backup/docker-postgres-backup:pgXX -f Dockerfile.pgXX .`

402
poetry.lock generated
View File

@@ -1,390 +1,148 @@
# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
[[package]] [[package]]
name = "boto3" name = "boto3"
version = "1.20.51" version = "1.38.32"
description = "The AWS SDK for Python" description = "The AWS SDK for Python"
category = "main"
optional = false optional = false
python-versions = ">= 3.6" python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "boto3-1.38.32-py3-none-any.whl", hash = "sha256:b998edac72f6740bd5d9d585cf3880f2dfeb4842e626b34430fd0e9623378011"},
{file = "boto3-1.38.32.tar.gz", hash = "sha256:3faa2c328a61745f3215a63039606a6fcf55d9afe1cc76e3a5e27b9db58cdbf6"},
]
[package.dependencies] [package.dependencies]
botocore = ">=1.23.51,<1.24.0" botocore = ">=1.38.32,<1.39.0"
jmespath = ">=0.7.1,<1.0.0" jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.5.0,<0.6.0" s3transfer = ">=0.13.0,<0.14.0"
[package.extras] [package.extras]
crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]] [[package]]
name = "botocore" name = "botocore"
version = "1.23.51" version = "1.38.32"
description = "Low-level, data-driven core of boto 3." description = "Low-level, data-driven core of boto 3."
category = "main"
optional = false optional = false
python-versions = ">= 3.6" python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "botocore-1.38.32-py3-none-any.whl", hash = "sha256:64ab919a5d8b74dd73eaac1f978d0e674d11ff3bbe8815c3d2982477be9a082c"},
{file = "botocore-1.38.32.tar.gz", hash = "sha256:0899a090e352cb5eeaae2c7bb52a987b469d23912c7ece86664dfb5c2e074978"},
]
[package.dependencies] [package.dependencies]
jmespath = ">=0.7.1,<1.0.0" jmespath = ">=0.7.1,<2.0.0"
python-dateutil = ">=2.1,<3.0.0" python-dateutil = ">=2.1,<3.0.0"
urllib3 = ">=1.25.4,<1.27" urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}
[package.extras] [package.extras]
crt = ["awscrt (==0.12.5)"] crt = ["awscrt (==0.23.8)"]
[[package]]
name = "cfgv"
version = "3.3.1"
description = "Validate configuration and produce human readable error messages."
category = "dev"
optional = false
python-versions = ">=3.6.1"
[[package]]
name = "distlib"
version = "0.3.4"
description = "Distribution utilities"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "filelock"
version = "3.4.2"
description = "A platform independent file lock."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"]
testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"]
[[package]]
name = "identify"
version = "2.4.8"
description = "File identification library for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
license = ["ukkonen"]
[[package]] [[package]]
name = "jmespath" name = "jmespath"
version = "0.10.0" version = "1.0.1"
description = "JSON Matching Expressions" description = "JSON Matching Expressions"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "nodeenv"
version = "1.6.0"
description = "Node.js virtual environment builder"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "platformdirs"
version = "2.4.1"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
groups = ["main"]
[package.extras] files = [
docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"},
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"},
]
[[package]]
name = "pre-commit"
version = "2.17.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
category = "dev"
optional = false
python-versions = ">=3.6.1"
[package.dependencies]
cfgv = ">=2.0.0"
identify = ">=1.0.0"
nodeenv = ">=0.11.1"
pyyaml = ">=5.1"
toml = "*"
virtualenv = ">=20.0.8"
[[package]]
name = "psycopg2-binary"
version = "2.9.3"
description = "psycopg2 - Python-PostgreSQL Database Adapter"
category = "main"
optional = false
python-versions = ">=3.6"
[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
version = "2.8.2" version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module" description = "Extensions to the standard Python datetime module"
category = "main"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
]
[package.dependencies] [package.dependencies]
six = ">=1.5" six = ">=1.5"
[[package]] [[package]]
name = "pytz" name = "pytz"
version = "2021.3" version = "2025.2"
description = "World timezone definitions, modern and historical" description = "World timezone definitions, modern and historical"
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
groups = ["main"]
[[package]] files = [
name = "pyyaml" {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"},
version = "6.0" {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"},
description = "YAML parser and emitter for Python" ]
category = "dev"
optional = false
python-versions = ">=3.6"
[[package]] [[package]]
name = "s3transfer" name = "s3transfer"
version = "0.5.1" version = "0.13.0"
description = "An Amazon S3 Transfer Manager" description = "An Amazon S3 Transfer Manager"
category = "main"
optional = false optional = false
python-versions = ">= 3.6" python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be"},
{file = "s3transfer-0.13.0.tar.gz", hash = "sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"},
]
[package.dependencies] [package.dependencies]
botocore = ">=1.12.36,<2.0a.0" botocore = ">=1.37.4,<2.0a.0"
[package.extras] [package.extras]
crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"]
[[package]] [[package]]
name = "schedule" name = "schedule"
version = "1.1.0" version = "1.2.2"
description = "Job scheduling for humans." description = "Job scheduling for humans."
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "schedule-1.2.2-py3-none-any.whl", hash = "sha256:5bef4a2a0183abf44046ae0d164cadcac21b1db011bdd8102e4a0c1e91e06a7d"},
{file = "schedule-1.2.2.tar.gz", hash = "sha256:15fe9c75fe5fd9b9627f3f19cc0ef1420508f9f9a46f45cd0769ef75ede5f0b7"},
]
[package.extras]
timezone = ["pytz"]
[[package]] [[package]]
name = "six" name = "six"
version = "1.16.0" version = "1.17.0"
description = "Python 2 and 3 compatibility utilities" description = "Python 2 and 3 compatibility utilities"
category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
[[package]] files = [
name = "toml" {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
version = "0.10.2" {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
description = "Python Library for Tom's Obvious, Minimal Language" ]
category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "1.26.8" version = "2.4.0"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"},
{file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"},
]
[package.extras] [package.extras]
brotli = ["brotlipy (>=0.6.0)"] brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] h2 = ["h2 (>=4,<5)"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "virtualenv"
version = "20.13.1"
description = "Virtual Python Environment builder"
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[package.dependencies]
distlib = ">=0.3.1,<1"
filelock = ">=3.2,<4"
platformdirs = ">=2,<3"
six = ">=1.9.0,<2"
[package.extras]
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"]
testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "2.1"
python-versions = "^3.10" python-versions = "^3.12"
content-hash = "43f8255e4ef052734b327d288656fbfc8cc4dbac8519d208e32959c941181c3e" content-hash = "447ff7cefd2e448599532c8a28bcc96db4be7726982ca4355aa8012d18c6b622"
[metadata.files]
boto3 = [
{file = "boto3-1.20.51-py3-none-any.whl", hash = "sha256:6b1e78ac44956adb3909da2194ad8397da0fde615ba3029648663b18f2b776fd"},
{file = "boto3-1.20.51.tar.gz", hash = "sha256:f26f7285780bda16c6ffb8db76c949aeeb45730d3f68626e31b90246ec00fe1a"},
]
botocore = [
{file = "botocore-1.23.51-py3-none-any.whl", hash = "sha256:372428fb18ba813431b2301c9306b97c0bc0a888127725b427f227734e370c7e"},
{file = "botocore-1.23.51.tar.gz", hash = "sha256:f715fba22d1d2ecf995d3168ddd9adca63979a6cddd35534ccc8550c690f1c88"},
]
cfgv = [
{file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
]
distlib = [
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
{file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
]
filelock = [
{file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"},
{file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"},
]
identify = [
{file = "identify-2.4.8-py2.py3-none-any.whl", hash = "sha256:a55bdd671b6063eb837af938c250ec00bba6e610454265133b0d2db7ae718d0f"},
{file = "identify-2.4.8.tar.gz", hash = "sha256:97e839c1779f07011b84c92af183e1883d9745d532d83412cca1ca76d3808c1c"},
]
jmespath = [
{file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"},
{file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"},
]
nodeenv = [
{file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"},
{file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
]
platformdirs = [
{file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"},
{file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"},
]
pre-commit = [
{file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"},
{file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"},
]
psycopg2-binary = [
{file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:0a29729145aaaf1ad8bafe663131890e2111f13416b60e460dae0a96af5905c9"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a79d622f5206d695d7824cbf609a4f5b88ea6d6dab5f7c147fc6d333a8787e4"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:090f3348c0ab2cceb6dfbe6bf721ef61262ddf518cd6cc6ecc7d334996d64efa"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a9e1f75f96ea388fbcef36c70640c4efbe4650658f3d6a2967b4cc70e907352e"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c3ae8e75eb7160851e59adc77b3a19a976e50622e44fd4fd47b8b18208189d42"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-win32.whl", hash = "sha256:7b1e9b80afca7b7a386ef087db614faebbf8839b7f4db5eb107d0f1a53225029"},
{file = "psycopg2_binary-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:8b344adbb9a862de0c635f4f0425b7958bf5a4b927c8594e6e8d261775796d53"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:e847774f8ffd5b398a75bc1c18fbb56564cda3d629fe68fd81971fece2d3c67e"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68641a34023d306be959101b345732360fc2ea4938982309b786f7be1b43a4a1"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3303f8807f342641851578ee7ed1f3efc9802d00a6f83c101d21c608cb864460"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:e3699852e22aa68c10de06524a3721ade969abf382da95884e6a10ff798f9281"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_24_ppc64le.whl", hash = "sha256:526ea0378246d9b080148f2d6681229f4b5964543c170dd10bf4faaab6e0d27f"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:b1c8068513f5b158cf7e29c43a77eb34b407db29aca749d3eb9293ee0d3103ca"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:15803fa813ea05bef089fa78835118b5434204f3a17cb9f1e5dbfd0b9deea5af"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:152f09f57417b831418304c7f30d727dc83a12761627bb826951692cc6491e57"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:404224e5fef3b193f892abdbf8961ce20e0b6642886cfe1fe1923f41aaa75c9d"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:1f6b813106a3abdf7b03640d36e24669234120c72e91d5cbaeb87c5f7c36c65b"},
{file = "psycopg2_binary-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:2d872e3c9d5d075a2e104540965a1cf898b52274a5923936e5bfddb58c59c7c2"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:10bb90fb4d523a2aa67773d4ff2b833ec00857f5912bafcfd5f5414e45280fb1"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a52ecab70af13e899f7847b3e074eeb16ebac5615665db33bce8a1009cf33"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a29b3ca4ec9defec6d42bf5feb36bb5817ba3c0230dd83b4edf4bf02684cd0ae"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:12b11322ea00ad8db8c46f18b7dfc47ae215e4df55b46c67a94b4effbaec7094"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:53293533fcbb94c202b7c800a12c873cfe24599656b341f56e71dd2b557be063"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c381bda330ddf2fccbafab789d83ebc6c53db126e4383e73794c74eedce855ef"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d29409b625a143649d03d0fd7b57e4b92e0ecad9726ba682244b73be91d2fdb"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:183a517a3a63503f70f808b58bfbf962f23d73b6dccddae5aa56152ef2bcb232"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:15c4e4cfa45f5a60599d9cec5f46cd7b1b29d86a6390ec23e8eebaae84e64554"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba"},
{file = "psycopg2_binary-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:63638d875be8c2784cfc952c9ac34e2b50e43f9f0a0660b65e2a87d656b3116c"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ffb7a888a047696e7f8240d649b43fb3644f14f0ee229077e7f6b9f9081635bd"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c9d5450c566c80c396b7402895c4369a410cab5a82707b11aee1e624da7d004"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:d1c1b569ecafe3a69380a94e6ae09a4789bbb23666f3d3a08d06bbd2451f5ef1"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8fc53f9af09426a61db9ba357865c77f26076d48669f2e1bb24d85a22fb52307"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-win32.whl", hash = "sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce"},
{file = "psycopg2_binary-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:7af0dd86ddb2f8af5da57a976d27cd2cd15510518d582b478fbb2292428710b4"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93cd1967a18aa0edd4b95b1dfd554cf15af657cb606280996d393dadc88c3c35"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bda845b664bb6c91446ca9609fc69f7db6c334ec5e4adc87571c34e4f47b7ddb"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:01310cf4cf26db9aea5158c217caa92d291f0500051a6469ac52166e1a16f5b7"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99485cab9ba0fa9b84f1f9e1fef106f44a46ef6afdeec8885e0b88d0772b49e8"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-win32.whl", hash = "sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d"},
{file = "psycopg2_binary-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f"},
]
python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
pytz = [
{file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
{file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
]
pyyaml = [
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
{file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
{file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
{file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
{file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
{file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
{file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
{file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
{file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
{file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
{file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
{file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
{file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
]
s3transfer = [
{file = "s3transfer-0.5.1-py3-none-any.whl", hash = "sha256:25c140f5c66aa79e1ac60be50dcd45ddc59e83895f062a3aab263b870102911f"},
{file = "s3transfer-0.5.1.tar.gz", hash = "sha256:69d264d3e760e569b78aaa0f22c97e955891cd22e32b10c51f784eeda4d9d10a"},
]
schedule = [
{file = "schedule-1.1.0-py2.py3-none-any.whl", hash = "sha256:617adce8b4bf38c360b781297d59918fbebfb2878f1671d189f4f4af5d0567a4"},
{file = "schedule-1.1.0.tar.gz", hash = "sha256:e6ca13585e62c810e13a08682e0a6a8ad245372e376ba2b8679294f377dfc8e4"},
]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
toml = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
urllib3 = [
{file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
{file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
]
virtualenv = [
{file = "virtualenv-20.13.1-py2.py3-none-any.whl", hash = "sha256:45e1d053cad4cd453181ae877c4ffc053546ae99e7dd049b9ff1d9be7491abf7"},
{file = "virtualenv-20.13.1.tar.gz", hash = "sha256:e0621bcbf4160e4e1030f05065c8834b4e93f4fcc223255db2a823440aca9c14"},
]

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "docker-postgres-backup" name = "docker-postgres-backup"
version = "0.1.0" version = "0.5"
description = "" description = ""
authors = ["Eugene Morozov <e@morozov.ee>"] authors = ["Eugene Morozov <e@morozov.ee>"]
packages = [ packages = [
@@ -8,21 +8,18 @@ packages = [
] ]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = "^3.12"
schedule = "^1.1.0" schedule = "^1.1.0"
psycopg2-binary = "^2.9.3"
boto3 = "^1.20.51" boto3 = "^1.20.51"
pytz = "^2021.3" pytz = "^2025.2"
[tool.poetry.dev-dependencies]
pre-commit = "^2.17.0"
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.black] [tool.black]
line-length = 90 line-length = 100
[tool.isort] [tool.isort]
profile = "black" profile = "black"

View File

@@ -6,7 +6,7 @@ The script provides functionality:
4. Scheduled to run every hour 4. Scheduled to run every hour
You can set some envs vars: You can set some envs vars:
- DEBUG - run every 1 minute if 1, default is 0 - SCHEDULE - can be monthly, weekly, daily, hourly (by default)
- DB_USER - user to connect DB, default is postgres - DB_USER - user to connect DB, default is postgres
- DB_PASSWORD - password to connect DB, default is postgres - DB_PASSWORD - password to connect DB, default is postgres
- DB_HOST - host to connect DB, default is localhost - DB_HOST - host to connect DB, default is localhost
@@ -14,6 +14,7 @@ You can set some envs vars:
- DB_NAME - database to back up, default is postgres - DB_NAME - database to back up, default is postgres
- TIME_ZONE - timezone for datetime using in filenames, default is Europe/Tallinn - TIME_ZONE - timezone for datetime using in filenames, default is Europe/Tallinn
- COMPRESSION_LEVEL - level of LZMA compression, default is 7 - COMPRESSION_LEVEL - level of LZMA compression, default is 7
- PREFIX - prefix for backup filename, default is empty
Settings for S3 storage: Settings for S3 storage:
- AWS_S3_REGION_NAME - default nl-ams - AWS_S3_REGION_NAME - default nl-ams
@@ -36,13 +37,14 @@ import pytz
import schedule import schedule
from boto3.exceptions import S3UploadFailedError from boto3.exceptions import S3UploadFailedError
DEBUG = int(os.getenv("DEBUG", 0)) SCHEDULE = os.getenv("SCHEDULE", "HOURLY")
DB_USER = os.getenv("DB_USER", "postgres") DB_USER = os.getenv("DB_USER", "postgres")
DB_PASSWORD = os.getenv("DB_PASSWORD", "postgres") DB_PASSWORD = os.getenv("DB_PASSWORD", "postgres")
DB_HOST = os.getenv("DB_HOST", "localhost") DB_HOST = os.getenv("DB_HOST", "localhost")
DB_PORT = os.getenv("DB_PORT", "5432") DB_PORT = os.getenv("DB_PORT", "5432")
DB_NAME = os.getenv("DB_NAME", "postgres") DB_NAME = os.getenv("DB_NAME", "postgres")
TIME_ZONE = pytz.timezone(os.getenv("TIME_ZONE", "Europe/Tallinn")) TIME_ZONE = pytz.timezone(os.getenv("TIME_ZONE", "Europe/Tallinn"))
PREFIX = os.getenv("PREFIX", "")
AWS_S3_REGION_NAME = os.getenv("AWS_S3_REGION_NAME", "nl-ams") AWS_S3_REGION_NAME = os.getenv("AWS_S3_REGION_NAME", "nl-ams")
AWS_S3_ENDPOINT_URL = os.getenv("AWS_S3_ENDPOINT_URL", "https://s3.nl-ams.scw.cloud") AWS_S3_ENDPOINT_URL = os.getenv("AWS_S3_ENDPOINT_URL", "https://s3.nl-ams.scw.cloud")
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID") AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
@@ -62,9 +64,7 @@ def backup_db_from_postgres(file_path: str) -> bool:
:param file: :param file:
:return: :return:
""" """
postgres_connection_url = ( postgres_connection_url = f"postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
f"postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
)
try: try:
process = subprocess.Popen( process = subprocess.Popen(
[ [
@@ -89,9 +89,7 @@ def backup_db_from_postgres(file_path: str) -> bool:
def compress_file_to_xz(file_path: str) -> str: def compress_file_to_xz(file_path: str) -> str:
compressed_file_path = f"{file_path}.xz" compressed_file_path = f"{file_path}.xz"
with open(file_path, "rb") as origin_file: with open(file_path, "rb") as origin_file:
with lzma.open( with lzma.open(compressed_file_path, "wb", filters=COMPRESSION_SETTINGS) as compressed_file:
compressed_file_path, "wb", filters=COMPRESSION_SETTINGS
) as compressed_file:
shutil.copyfileobj(origin_file, compressed_file) shutil.copyfileobj(origin_file, compressed_file)
os.remove(file_path) os.remove(file_path)
return compressed_file_path return compressed_file_path
@@ -126,7 +124,10 @@ def run_backup_database() -> None:
""" """
scheduled_time = datetime.now(tz=TIME_ZONE).strftime("%y%m%d-%H%M") scheduled_time = datetime.now(tz=TIME_ZONE).strftime("%y%m%d-%H%M")
filename = f"{DB_NAME}-{scheduled_time}.sql" filename = f"{DB_NAME}-{scheduled_time}.sql"
if PREFIX:
filename = f"{PREFIX}-{filename}"
sql_file_path = f"/tmp/{filename}" sql_file_path = f"/tmp/{filename}"
backup_success = backup_db_from_postgres(file_path=sql_file_path) backup_success = backup_db_from_postgres(file_path=sql_file_path)
if not backup_success: if not backup_success:
print("Backup failed") print("Backup failed")
@@ -150,12 +151,23 @@ def run_threaded(job_func):
job_thread.start() job_thread.start()
if not DEBUG: match SCHEDULE:
print("Setting up task launch 'run_backup_database' every hour") case "MONTHLY":
schedule.every().hour.at(":05").do(run_threaded, run_backup_database) print("Scheduled to run backup task every 4 weeks")
else: schedule.every(4).weeks.do(run_threaded, run_backup_database)
print("Setting up task launch 'run_backup_database' every 5 minutes") case "WEEKLY":
schedule.every(5).minutes.do(run_threaded, run_backup_database) print("Scheduled to run backup task every Monday")
schedule.every().monday.at("02:00").do(run_threaded, run_backup_database)
case "DAILY":
print("Scheduled to run backup task every day at 02:00")
schedule.every().day.at("02:00").do(run_threaded, run_backup_database)
# For any other values, incl HOURLY - run hourly
case _:
print("Scheduled to run backup task every hour")
schedule.every().hour.at(":05").do(run_threaded, run_backup_database)
# Run first job immediately
schedule.run_all()
while True: while True:
schedule.run_pending() schedule.run_pending()