From 9b3e7849058b053bdc1dcc75e4303996e672f823 Mon Sep 17 00:00:00 2001 From: gabrielbazan Date: Fri, 8 Jul 2022 02:49:30 -0300 Subject: [PATCH 1/6] Fix Makefile:run_unit_tests. Remove run_unit_tests.sh --- .../scripts/run_unit_tests.sh | 3 --- .../{{ cookiecutter.project_package_name }}/Makefile | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100755 {{ cookiecutter.project_package_name }}/scripts/run_unit_tests.sh diff --git a/{{ cookiecutter.project_package_name }}/scripts/run_unit_tests.sh b/{{ cookiecutter.project_package_name }}/scripts/run_unit_tests.sh deleted file mode 100755 index 96e3e28..0000000 --- a/{{ cookiecutter.project_package_name }}/scripts/run_unit_tests.sh +++ /dev/null @@ -1,3 +0,0 @@ - - -python3 -m unittest discover -s ./../ -p '*_test.py' diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile index f01baf1..983a32a 100644 --- a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile +++ b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile @@ -32,5 +32,7 @@ install_test_reqs_in_venv: run_unit_tests: @echo "Running unit tests..." - . ${VIRTUALENV_PATH}/bin/activate && ./scripts/run_unit_tests.sh && deactivate + . ${VIRTUALENV_PATH}/bin/activate && \ + python -m unittest discover -s . -p '*_test.py' && \ + cd .. @echo "Done!" From bf37f9db505d59f8a028df85e2e4dbf861b91008 Mon Sep 17 00:00:00 2001 From: gabrielbazan Date: Fri, 8 Jul 2022 02:51:09 -0300 Subject: [PATCH 2/6] Fix Makefile:run_unit_tests and move Makefile --- .../{{{ cookiecutter.project_package_name }} => }/Makefile | 1 + 1 file changed, 1 insertion(+) rename {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }} => }/Makefile (94%) diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile similarity index 94% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile rename to {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile index 983a32a..bd39e01 100644 --- a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile +++ b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile @@ -33,6 +33,7 @@ install_test_reqs_in_venv: run_unit_tests: @echo "Running unit tests..." . ${VIRTUALENV_PATH}/bin/activate && \ + cd {{ cookiecutter.project_package_name }} && \ python -m unittest discover -s . -p '*_test.py' && \ cd .. @echo "Done!" From f600288b403b33c58f917c49b3190b1ef516e56c Mon Sep 17 00:00:00 2001 From: gabrielbazan Date: Sat, 9 Jul 2022 15:04:56 -0300 Subject: [PATCH 3/6] Change repo structure and update documentation --- README.md | 35 ++++++++++++++++--- .../Makefile | 8 +++++ .../docker-compose.yml | 0 .../Dockerfile | 0 .../Makefile | 28 +++++++++------ .../requirements.frozen | 0 .../requirements.test.frozen | 0 .../__init__.py | 0 .../run.py | 0 .../tests/__init__.py | 0 10 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 {{ cookiecutter.project_package_name }}/Makefile rename {{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }} => }/docker-compose.yml (100%) rename {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }} => }/Dockerfile (100%) rename {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }} => }/Makefile (63%) rename {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }} => }/requirements.frozen (100%) rename {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }} => }/requirements.test.frozen (100%) rename {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }} => }/__init__.py (100%) rename {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }} => }/run.py (100%) rename {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{{ cookiecutter.project_package_name }} => }/tests/__init__.py (100%) diff --git a/README.md b/README.md index db4d0d6..ead9718 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # Python Project Template with Docker Compose -This is a template for a simple Python project with Docker Compose. -It is used by create_app [create_app](https://github.com/application-creators/create_app) -to create a new Python simple project with Docker Compose. +This is a template used by [create_app](https://github.com/application-creators/create_app) to create a +new Python project with Docker Compose. To create your new project from this template, simply run: @@ -15,11 +14,37 @@ python -m create_app python_compose ## What's in this template * Project structure - * Containerization with Docker Compose + * Virtualenv * Unit tests + * Docker Compose containerization * Pre-commit GIT hooks * [Black](https://github.com/psf/black) * [Isort](https://pycqa.github.io/isort/) * [Flake8](https://flake8.pycqa.org/en/latest/) * Makefile with useful commands - \ No newline at end of file + + +## Git hooks + +This template uses [pre-commit](https://pre-commit.com/) to run GIT hooks in your repo: + * [Black](https://github.com/psf/black) + * [Isort](https://pycqa.github.io/isort/) + * [Flake8](https://flake8.pycqa.org/en/latest/) + +This helps developers to keep the same code styling in the project. + +To install the hooks in your repo, first [install pre-commit](https://pre-commit.com/#install) in your system. Then run: +```shell +make install_git_hooks +``` + + +## Docker compose + +The project structure has been designed keeping in mind that you may need to have multiple services in your project +(such as an API and a database, for example). Thus, Docker compose is a good way to get them running together. If you +need just one container, [python_simple](https://github.com/application-creators/python_simple) may be the way to go. + +By default, you get a service named the same as you project package name. You can add as many services you need in the +[root](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D) of your repo, each in their own folder, and declare the +services in diff --git a/{{ cookiecutter.project_package_name }}/Makefile b/{{ cookiecutter.project_package_name }}/Makefile new file mode 100644 index 0000000..1b2b767 --- /dev/null +++ b/{{ cookiecutter.project_package_name }}/Makefile @@ -0,0 +1,8 @@ + + +install_git_hooks: + pre-commit install + + +run_git_hooks: + pre-commit run --all-files diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/docker-compose.yml b/{{ cookiecutter.project_package_name }}/docker-compose.yml similarity index 100% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/docker-compose.yml rename to {{ cookiecutter.project_package_name }}/docker-compose.yml diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Dockerfile b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Dockerfile similarity index 100% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Dockerfile rename to {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Dockerfile diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile similarity index 63% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile rename to {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile index bd39e01..2a970c8 100644 --- a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile +++ b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Makefile @@ -6,34 +6,42 @@ REQUIREMENTS_FILE_PATH=./requirements.frozen TEST_REQUIREMENTS_FILE_PATH=./requirements.test.frozen -install_venv: - @echo "Installing virtualenv..." - sudo apt install python3.10-venv - @echo "Done!" - - -create_venv: +create_virtualenv: @echo "Creating virtualenv..." python3 -m venv "${VIRTUALENV_PATH}" @echo "Done!" -install_reqs_in_venv: +install_requirements: @echo "Installing requirements..." ${VIRTUALENV_PATH}/bin/pip install -r "${REQUIREMENTS_FILE_PATH}" @echo "Done!" -install_test_reqs_in_venv: +install_test_requirements: @echo "Installing test requirements..." ${VIRTUALENV_PATH}/bin/pip install -r "${TEST_REQUIREMENTS_FILE_PATH}" @echo "Done!" +install_all_requirements: install_requirements install_test_requirements + + run_unit_tests: @echo "Running unit tests..." - . ${VIRTUALENV_PATH}/bin/activate && \ + @. ${VIRTUALENV_PATH}/bin/activate && \ cd {{ cookiecutter.project_package_name }} && \ python -m unittest discover -s . -p '*_test.py' && \ cd .. @echo "Done!" + + +docker_build: + docker build -t {{ cookiecutter.project_package_name }} . + + +docker_run: + docker run -t {{ cookiecutter.project_package_name }} + + +docker_build_and_run: docker_build docker_run diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/requirements.frozen b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/requirements.frozen similarity index 100% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/requirements.frozen rename to {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/requirements.frozen diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/requirements.test.frozen b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/requirements.test.frozen similarity index 100% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/requirements.test.frozen rename to {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/requirements.test.frozen diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/__init__.py b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/__init__.py similarity index 100% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/__init__.py rename to {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/__init__.py diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/run.py b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/run.py similarity index 100% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/run.py rename to {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/run.py diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/tests/__init__.py b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/tests/__init__.py similarity index 100% rename from {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/tests/__init__.py rename to {{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/tests/__init__.py From 0c5cdbf1621def1af17da6f8e6d230d1cb8a5bb8 Mon Sep 17 00:00:00 2001 From: gabrielbazan Date: Sat, 9 Jul 2022 15:47:03 -0300 Subject: [PATCH 4/6] Update documentation --- README.md | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ead9718..a27dd05 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,130 @@ make install_git_hooks ``` -## Docker compose +## Project structure The project structure has been designed keeping in mind that you may need to have multiple services in your project (such as an API and a database, for example). Thus, Docker compose is a good way to get them running together. If you need just one container, [python_simple](https://github.com/application-creators/python_simple) may be the way to go. -By default, you get a service named the same as you project package name. You can add as many services you need in the -[root](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D) of your repo, each in their own folder, and declare the -services in +By default, you get a [service](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D) +named the same as you project package name. You can add as many services you want to the +[docker-compose.yml](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/docker-compose.yml) file. If you need to build +a new service, create a new folder at the [root](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D) of the repo and +put all its files in there. This will keep your repo organized and all your services decoupled from each other. + +Say you have a project named "my_project". The following is an example structure, with multiple services: + +``` +my_project/ (repo root) +│ ... +│ +└───service_a/ +│ │ ... +│ │ Dockerfile +│ +└───service_b/ +│ │ ... +│ │ Dockerfile +│ +│ docker-compose.yml +│ +│ ... +``` + +Each Python service (although you may have services using other technologies) has the following structure: + +``` +service_a/ (service folder) +│ +└───service_a/ (contains sources) +│ │ +│ └───tests/ +│ │ +│ │run.py +│ +│ Dockerfile +│ Makefile +│ requirements.frozen +│ requirements.test.frozen +``` + + * The [Dockerfile](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/Dockerfile) +provides instructions to build the image + * [Makefile](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/Makefile) + is not required, but it's useful to keep some everyday commands in there + * Declare your dependencies in + [requirements.frozen](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/requirements.frozen) + and + [requirements.test.frozen](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/requirements.test.frozen) + * [run.py](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/run.py) + is the entry point to the service. + * Put the unit tests in the [tests](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/tests) package + + +## Docker compose + +To build the images, go into the project repo and run: +```shell +docker compose build +``` + +And to run the containers: +```shell +docker compose up +``` + + +## Virtualenv + +It is recommended to keep your system's Python interpreter clean, and install your project's dependencies in a virtual +environment (_venv_). Doing this has advantages like preventing dependencies conflicts between different projects +you may have in your system. + +### Create the virtualenv + +After you've installed [venv](https://docs.python.org/3/library/venv.html) in your system, go to the +[service folder](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D) +and run the following to create the venv: + +```shell +make create_virtualenv +``` + + +### Requirements + +Use the [requirements.frozen](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/requirements.frozen) +file to declare the project's dependencies, and [requirements.test.frozen](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/requirements.test.frozen) +to declare dependencies that are only required to run tests. As indicated in the filenames, it is advised to declare +the dependencies with explicit versions (example: _requests==2.28.1_). This will allow you to control when to upgrade +dependencies versions, and will save you headaches when a new dependency version is released right when you were +running a deployment pipeline. + +To install the requirements in the venv, go to the [service folder](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D) +and run: +```shell +make install_requirements +``` + +To install the test requirements in the venv, run: +```shell +make install_test_requirements +``` + +To install requirements and test requirements with a single, command, run: +```shell +make install_all_requirements +``` + + +## Unit tests + +Add your unit tests to the +[tests package](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/tests). + +To run all unit tests, go to the [service folder](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D) +and run: +```shell +make run_unit_tests +``` From 9b6127a3e34b873bff7d89e21f9e4255b31618a0 Mon Sep 17 00:00:00 2001 From: gabrielbazan Date: Sat, 9 Jul 2022 15:49:56 -0300 Subject: [PATCH 5/6] Update documentation --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a27dd05..a9e8215 100644 --- a/README.md +++ b/README.md @@ -95,9 +95,11 @@ provides instructions to build the image [requirements.frozen](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/requirements.frozen) and [requirements.test.frozen](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/requirements.test.frozen) + (refer to [requirements](#requirements)) * [run.py](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/run.py) - is the entry point to the service. - * Put the unit tests in the [tests](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/tests) package + is the entry point to the service + * Put the unit tests in the [tests](/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/%7B%7B%20cookiecutter.project_package_name%20%7D%7D/tests) + package (refer to [unit tests](#unit-tests)) ## Docker compose From 170bdc551c4d6c41b78105f879e108fec5768304 Mon Sep 17 00:00:00 2001 From: gabrielbazan Date: Sat, 9 Jul 2022 15:59:00 -0300 Subject: [PATCH 6/6] Add requirements.frozen to image --- .../{{ cookiecutter.project_package_name }}/Dockerfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Dockerfile b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Dockerfile index 55bfca7..52223a3 100644 --- a/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Dockerfile +++ b/{{ cookiecutter.project_package_name }}/{{ cookiecutter.project_package_name }}/Dockerfile @@ -10,10 +10,13 @@ ARG REQUIREMENTS_FILENAME=requirements.frozen WORKDIR ${WORK_DIR} -COPY ${PROJECT_PACKAGE_NAME} . - +COPY ${REQUIREMENTS_FILENAME} . RUN pip install -r ${REQUIREMENTS_FILENAME} +COPY ${PROJECT_PACKAGE_NAME} . + + + CMD python run.py