Skip to content

Commit

Permalink
Merge fd95dd5 into 94a3f01
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffLIrion committed Oct 18, 2023
2 parents 94a3f01 + fd95dd5 commit e112fb9
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 41 deletions.
217 changes: 180 additions & 37 deletions Makefile
@@ -1,48 +1,191 @@
.PHONY: release
release:
rm -rf dist
rm -rf build
scripts/git_tag.sh
python setup.py sdist bdist_wheel
twine upload dist/*
#-------------------- ONLY MODIFY CODE IN THIS SECTION --------------------#
PACKAGE_DIR := androidtv
TEST_DIR := tests
DOCS_DIR := docs

.PHONY: docs
docs:
@cd docs/source && rm -f androidtv*.rst
@cd docs && sphinx-apidoc -f -e -o source/ ../androidtv/
@cd docs && make html && make html
# Change to false if you don't want to use pytest
USE_PYTEST := true

SYNCTESTS := $(shell cd tests && ls test*.py | grep -v async)
# Change this to false if you don't want to run linting checks on the tests
LINT_TEST_DIR := false
#-------------------- DO NOT MODIFY CODE BELOW!!!!!!!! --------------------#

.PHONY: test
test:
python --version 2>&1 | grep -q "Python 2" && (for synctest in $(SYNCTESTS); do python -m unittest discover -s tests/ -t . -p "$$synctest"; done) || true
python --version 2>&1 | grep -q "Python 3" && python -m unittest discover -s tests/ -t . || true
export PATH := $(abspath venv)/bin:${PATH}

.PHONY: coverage
coverage:
coverage run --source androidtv -m unittest discover -s tests/ -t . && coverage html && coverage report -m
# Whether to include "*_async.py" files
INCLUDE_ASYNC = $(shell python --version | grep -q "Python 3.[7891]" && echo "true" || echo "false")

.PHONY: tdd
tdd:
coverage run --source androidtv -m unittest discover -s tests/ -t . && coverage report -m
# Async vs. Sync files
PACKAGE_ASYNC_FILES = $(shell ls -m $(PACKAGE_DIR)/*_async.py 2>/dev/null)
TEST_ASYNC_FILES = $(shell ls -m $(TEST_DIR)/*_async.py 2>/dev/null)
TEST_SYNC_FILES = $(shell cd $(TEST_DIR) && ls test*.py | grep -v async)

.PHONY: lint
lint:
flake8 androidtv/ && pylint androidtv/
# Target prerequisites that may or may not exist
VENV_REQUIREMENTS_TXT := $(wildcard venv_requirements.txt)
SETUP_PY := $(wildcard setup.py)

# A prerequisite for forcing targets to run
FORCE:

# Help!
help: ## Show this help menu
@echo "\n\033[1mUsage:\033[0m"; \
awk -F ':|##' '/^[^\t].+?:.*?##/ { printf "\033[36m make %-20s\033[0m %s\n", $$1, $$NF }' $(MAKEFILE_LIST) | grep -v "make venv/\." | sort
@echo ""
@echo "NOTES:"
@echo "- The 'venv/.bin' target may fail because newer Python versions include the 'venv' package. Follow the instructions to create the virtual environment manually."
ifneq ("$(wildcard scripts/pre-commit.sh)", "")
@echo "- To install the git pre-commit hook:\n\n scripts/pre-commit.sh\n"
endif
@echo "- You may need to activate the virtual environment prior to running any Make commands:\n\n source venv/bin/activate\n"


# Virtual environment targets
.PHONY: clean-venv
clean-venv: ## Remove the virtual environment
rm -rf venv

venv: venv/.bin venv/.requirements venv/.setup .git/hooks/pre-commit ## Create the virtual environment and install all necessary packages

venv/.bin: ## Create the virtual environment
if [ -z "$$ENV_GITHUB_ACTIONS" ]; then \
echo -e "If this target fails, you can perform this action manually via:\n\n make clean-venv && python3 -m venv venv && source venv/bin/activate && pip install -U setuptools && echo -e '*.*\n**/' > venv/.gitignore && touch venv/.bin\n\n"; \
apt list -a --installed python3-venv 2>&1 | grep -q installed || (sudo apt update && sudo apt install python3-venv); \
python3 -m venv venv; \
pip install -U setuptools; \
fi
mkdir -p venv
echo '*.*\n**/' > venv/.gitignore
touch venv/.bin

venv/.requirements: venv/.bin $(VENV_REQUIREMENTS_TXT) ## Install the requirements from 'venv_requirements.txt' in the virtual environment
ifneq ("$(wildcard venv_requirements.txt)", "")
pip install -U -r venv_requirements.txt
endif
touch venv/.requirements

# Install the package in the virtual environment
venv/.setup: venv/.bin $(SETUP_PY)
ifneq ("$(wildcard setup.py)", "")
pip install .
endif
touch venv/.setup

.PHONY: uninstall
uninstall:
rm -f venv/.setup

.PHONY: install
install: uninstall venv/.setup ## Install the package in the virtual environment

# Create the pre-commit hook
.git/hooks/pre-commit:
./scripts/pre-commit.sh MAKE_PRECOMMIT_HOOK

.PHONY: pre-commit
pre-commit: .git/hooks/pre-commit ## Create the pre-commit hook

# Linting and code analysis
.PHONY: black
black:
black --safe --line-length 120 --target-version py35 androidtv
black --safe --line-length 120 --target-version py35 tests
black: venv ## Format the code using black
black --safe --line-length 120 --target-version py35 $(PACKAGE_DIR)
black --safe --line-length 120 --target-version py35 $(TEST_DIR)
ifneq ("$(wildcard setup.py)", "")
black --safe --line-length 120 --target-version py35 setup.py
endif

.PHONY: lint-black
lint-black:
black --check --safe --line-length 120 --target-version py35 androidtv
black --check --safe --line-length 120 --target-version py35 tests
black --check --safe --line-length 120 --target-version py35 setup.py

.PHONY: alltests
alltests:
flake8 androidtv/ && pylint androidtv/ && coverage run --source androidtv -m unittest discover -s tests/ -t . && coverage report -m
lint-black: venv ## Check that the code is formatted using black
black --check --line-length 120 --safe --target-version py35 $(PACKAGE_DIR)
black --check --line-length 120 --safe --target-version py35 $(TEST_DIR)
ifneq ("$(wildcard setup.py)", "")
black --check --line-length 120 --safe --target-version py35 setup.py
endif

.PHONY: lint-flake8
lint-flake8: venv ## Check the code using flake8
ifeq ($(INCLUDE_ASYNC), true)
flake8 $(PACKAGE_DIR)
ifeq ($(LINT_TEST_DIR), true)
flake8 $(TEST_DIR)
endif
else
flake8 $(PACKAGE_DIR) --exclude="$(PACKAGE_ASYNC_FILES)"
ifeq ($(LINT_TEST_DIR), true)
flake8 $(TEST_DIR) --exclude="$(TEST_ASYNC_FILES)"
endif
endif
ifneq ("$(wildcard setup.py)", "")
flake8 setup.py
endif

.PHONY: lint-pylint
lint-pylint: venv ## Check the code using pylint
ifeq ($(INCLUDE_ASYNC), true)
pylint $(PACKAGE_DIR)
ifeq ($(LINT_TEST_DIR), true)
pylint $(TEST_DIR)
endif
else
pylint $(PACKAGE_DIR) --ignore="$(PACKAGE_ASYNC_FILES)"
ifeq ($(LINT_TEST_DIR), true)
pylint $(TEST_DIR) --ignore="$(TEST_ASYNC_FILES)"
endif
endif
ifneq ("$(wildcard setup.py)", "")
pylint setup.py
endif

.PHONY: lint
lint: lint-black lint-flake8 lint-pylint ## Run all linting checks on the code


# Testing and coverage.
.PHONY: test
test: venv ## Run the unit tests
ifeq ($(INCLUDE_ASYNC), true)
ifeq ($(USE_PYTEST), true)
pytest $(TEST_DIR)
else
python -m unittest discover -s $(TEST_DIR)/ -t .
endif
else
ifeq ($(USE_PYTEST), true)
pytest $(TEST_DIR) --ignore-glob="*async.py"
else
for synctest in $(TEST_SYNC_FILES); do echo "\033[1;32m$(TEST_DIR)/$$synctest\033[0m" && python -m unittest "$(TEST_DIR)/$$synctest"; done
endif
endif

.PHONY: coverage
coverage: venv ## Run the unit tests and produce coverage info
ifeq ($(INCLUDE_ASYNC), true)
ifeq ($(USE_PYTEST), true)
coverage run --source $(PACKAGE_DIR) -m pytest $(TEST_DIR)/ && coverage report -m
else
coverage run --source $(PACKAGE_DIR) -m unittest discover -s $(TEST_DIR) -t . && coverage report -m
endif
else
ifeq ($(USE_PYTEST), true)
coverage run --source $(PACKAGE_DIR) -m pytest $(TEST_DIR)/ --ignore-glob="*async.py" && coverage report -m
else
for synctest in $(TEST_SYNC_FILES); do echo "\033[1;32m$(TEST_DIR)/$$synctest\033[0m" && coverage run --source $(PACKAGE_DIR) -m unittest "$(TEST_DIR)/$$synctest"; done
coverage report -m
endif
endif

.PHONY: htmlcov
htmlcov: coverage ## Produce a coverage report
coverage html


# Documentation
.PHONY: docs
docs: venv ## Build the documentation
rm -rf $(DOCS_DIR)/build
@cd $(DOCS_DIR) && sphinx-apidoc -f -e -o source/ $(CURDIR)/$(PACKAGE_DIR)/
@cd $(DOCS_DIR) && make html && make html


.PHONY: all
all: lint htmlcov ## Run all linting checks and unit tests and produce a coverage report
71 changes: 71 additions & 0 deletions scripts/pre-commit.sh
@@ -0,0 +1,71 @@
#!/bin/bash

set -e

function make_pre_commit() {
# setup pre-commit hook
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo -e "#!/bin/bash\n\n./scripts/pre-commit.sh 'placeholder_argument'" > "$DIR/../.git/hooks/pre-commit"
chmod a+x "$DIR/../.git/hooks/pre-commit"
echo "pre-commit hook successfully configured"
}

# if no arguments are passed, create the pre-commit hook
if [ "$#" -eq 0 ]; then
read -p "Do you want to setup the git pre-commit hook? [Y/n] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
make_pre_commit
else
echo "pre-commit hook not configured"
fi
exit 0
fi

# if the argument passed is "MAKE_PRECOMMIT_HOOK", then make the pre-commit hook
if [[ $1 == "MAKE_PRECOMMIT_HOOK" ]]; then
make_pre_commit
exit 0
fi

# THE PRE-COMMIT HOOK

# get the directory of this script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

(
cd "$DIR/.."

no_unstaged_changes=true
echo -e "\n\033[1m1. Checking for unstaged changes...\033[0m"
for staged_file in $(git diff --name-only --cached); do
git diff --name-only | grep -q "${staged_file}" && echo "You have unstaged changes in '${staged_file}'" && no_unstaged_changes=false || true
done

# modified .py files
pyfiles=$(git diff --cached --name-only -- '*.py')

# flake8
flake8_pass=true
if [ "$pyfiles" != "" ]; then
echo -e "\n\033[1m2. Running flake8...\033[0m"
flake8 $pyfiles || flake8_pass=false
else
echo -e "\n\033[1m2. Skipping flake8.\033[0m"
fi

# pylint
pylint_pass=true
if [ "$pyfiles" != "" ]; then
echo -e "\n\033[1m3. Running pylint...\033[0m"
pylint $pyfiles || pylint_pass=false
else
echo -e "\n\033[1m3. Skipping pylint.\033[0m\n"
fi

if [ "$flake8_pass" != "true" ] || [ "$pylint_pass" != "true" ] || [ "$no_unstaged_changes" != "true" ]; then
echo -e "\033[1m\033[31mSome checks failed.\033[0m\n\n NOT RECOMMENDED: If you want to skip the pre-commit hook, use the --no-verify flag.\n"
exit 1
fi
echo -e "\033[1m\033[32mAll checks passed.\033[0m\n"
)
2 changes: 2 additions & 0 deletions setup.py
@@ -1,3 +1,5 @@
"""setup.py file for the androidtv package."""

from setuptools import setup

with open("README.rst") as f:
Expand Down
14 changes: 10 additions & 4 deletions tests/test_adb_manager_async_temp.py
@@ -1,10 +1,12 @@
import sys
"""Tests for the ClientAsync and AdbDeviceUsbAsync classes."""

import unittest
from unittest.mock import patch

sys.path.insert(0, "..")

from adb_shell.transport.usb_transport import UsbTransport
try:
from adb_shell.transport.usb_transport import UsbTransport
except (ImportError, OSError):
UsbTransport = None

from androidtv.adb_manager.adb_manager_async import AdbDeviceUsbAsync, ClientAsync

Expand All @@ -21,6 +23,7 @@ class TestAsyncClientDevice(unittest.TestCase):

@awaiter
async def test_async_client_device(self):
"""Test the ClientAsync class."""
with patch("androidtv.adb_manager.adb_manager_async.Client", patchers.ClientFakeSuccess):
client = ClientAsync("host", "port")

Expand All @@ -40,6 +43,7 @@ async def test_async_client_device(self):

@awaiter
async def test_async_client_device_fail(self):
"""Test the ClientAsync class when it fails."""
with patch("androidtv.adb_manager.adb_manager_async.Client", patchers.ClientFakeFail):
client = ClientAsync("host", "port")

Expand All @@ -48,6 +52,7 @@ async def test_async_client_device_fail(self):
self.assertFalse(device)


@unittest.skipIf(UsbTransport is None, "UsbTransport cannot be imported")
class TestAsyncUsb(unittest.TestCase):
"""Test the ``AdbDeviceUsbAsync`` class defined in ``adb_manager_async.py``.
Expand All @@ -57,6 +62,7 @@ class TestAsyncUsb(unittest.TestCase):

@awaiter
async def test_async_usb(self):
"""Test the AdbDeviceUsbAsync class."""
with patch("adb_shell.adb_device.UsbTransport.find_adb", return_value=UsbTransport("device", "setting")):
device = AdbDeviceUsbAsync()

Expand Down
12 changes: 12 additions & 0 deletions venv_requirements.txt
@@ -0,0 +1,12 @@
adb-shell[usb]
aiofiles
black
coverage
coveralls
flake8
pylint
pytest
pyyaml
sphinx
sphinx-rtd-theme
tk

0 comments on commit e112fb9

Please sign in to comment.