From patchwork Wed Jun 21 13:45:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Romain Naour X-Patchwork-Id: 1797916 Return-Path: X-Original-To: incoming-buildroot@patchwork.ozlabs.org Delivered-To: patchwork-incoming-buildroot@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=buildroot.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=buildroot-bounces@buildroot.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QmPs84Hqmz20Wk for ; Wed, 21 Jun 2023 23:45:32 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id AC4DC4011A; Wed, 21 Jun 2023 13:45:30 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org AC4DC4011A X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id bqq3ZU1fR5e5; Wed, 21 Jun 2023 13:45:28 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by smtp2.osuosl.org (Postfix) with ESMTP id 67B4240C22; Wed, 21 Jun 2023 13:45:27 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 67B4240C22 X-Original-To: buildroot@lists.busybox.net Delivered-To: buildroot@osuosl.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by ash.osuosl.org (Postfix) with ESMTP id E65AC1BF2B9 for ; Wed, 21 Jun 2023 13:45:25 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id BF2D2613D8 for ; Wed, 21 Jun 2023 13:45:25 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org BF2D2613D8 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id u_LlUcbVj7Yg for ; Wed, 21 Jun 2023 13:45:23 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org F3CBE60E09 Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by smtp3.osuosl.org (Postfix) with ESMTPS id F3CBE60E09 for ; Wed, 21 Jun 2023 13:45:22 +0000 (UTC) Received: by mail-wr1-x431.google.com with SMTP id ffacd0b85a97d-3090d3e9c92so6802508f8f.2 for ; Wed, 21 Jun 2023 06:45:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687355121; x=1689947121; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=zXvpiCS41xwgRpvkRKHwde/OLhMjX/w6Ucb2+RHU2rg=; b=Xx7e/mz7aqiX1VV40rAwbpvb0Q8cQ498wfVlGAl5ULiQwm2XCoyQBOk17leZPtTK42 subn3/74+c9+K849Q0pxinCAhNSzT3x93RJDFxaohWaIixMXwJrKkyomk1Y8RnkIYCIY 7VD5zSSn8xp0FzEM+SBgfZ0AdUNGcrMF9HSRhRsAv/OxD1KhkH5g6ez6eoEukm4eoStB MfBgfLJJL/k03UHADCZuFbTRUoCtjo+S12xTC45+u7qKlGvb+J9fv1Ho1EwL1V3yePkm dNkLlM9Av/dk897eiLD0AGxvaj99p0Far+hVQQK0wdvKyYRIpQ3b9ROZezKzL3Kt/iBc dtlw== X-Gm-Message-State: AC+VfDymBGZN4ZgrgXOn9V0YkJ6iv5u2IIV19P5zhgCq/P83pGlM3YQ0 o2sIZf4ctz4EPnHbMzVqg9qH3f10Xsy6OnmMmkw= X-Google-Smtp-Source: ACHHUZ57IX2osPtBfLBhiFBrfYCwavXjQfUOeLdaHzk3S7qvsLsRkdaZY4LmRiiWdKRC8qocpDJX4w== X-Received: by 2002:adf:dc84:0:b0:30e:59a2:3d70 with SMTP id r4-20020adfdc84000000b0030e59a23d70mr14765541wrj.43.1687355120531; Wed, 21 Jun 2023 06:45:20 -0700 (PDT) Received: from P-NTS-Evian.nantes.intranet (static-css-ccs-204145.business.bouyguestelecom.com. [176.157.204.145]) by smtp.gmail.com with ESMTPSA id k10-20020adff5ca000000b0030ae87bd3e3sm4560641wrp.18.2023.06.21.06.45.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Jun 2023 06:45:20 -0700 (PDT) From: Romain Naour To: buildroot@buildroot.org Date: Wed, 21 Jun 2023 15:45:18 +0200 Message-ID: <20230621134518.304689-1-romain.naour@smile.fr> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smile-fr.20221208.gappssmtp.com; s=20221208; t=1687355121; x=1689947121; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=zXvpiCS41xwgRpvkRKHwde/OLhMjX/w6Ucb2+RHU2rg=; b=VzgvCqsfo1SS5j3bQ4Y4BAEl5zx23uo+bTfGre+1hkfz11Ho+KJ8SOeNzJ/jURs/PQ O5F8PP870Flknktuk7hoymHhb3N5yPbfLO3iM5TNWXu5vXlTTYqVgoxOWt8dUFS/HRAg RNXtOyfzjq/QXzYZ2B/T5kO+MOmzQ1lmwaNzT/dBQf09Z4+n17ULG8BR5PDj77vGR8Ck xOp8RMKFGj5hyJ10UCfs5LOZHqVSnqFcEIqoP0CLu9uXn5UnRSzKbo9SHvOWWat3IroT 1236vAOBcnzRqLQE9mVbSzcTO9MPzTOYR/PEEZPzDNbgArORXJmkuoYyu2/fwLLA0i9u nrrQ== X-Mailman-Original-Authentication-Results: smtp3.osuosl.org; dkim=pass (2048-bit key) header.d=smile-fr.20221208.gappssmtp.com header.i=@smile-fr.20221208.gappssmtp.com header.a=rsa-sha256 header.s=20221208 header.b=VzgvCqsf Subject: [Buildroot] [PATCH] python-gpiozero: migrate to setup.cfg X-BeenThere: buildroot@buildroot.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Discussion and development of buildroot List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Romain Naour , James Hilliard Errors-To: buildroot-bounces@buildroot.org Sender: "buildroot" setup.cfg seems to be mandatory since (at least) setuptools 67.8.0 otherwise gpiozero dependencies are not properly detected File "/builds/buildroot.org/buildroot/test-output/TestPythonPy3Gpiozero/host/lib/python3.11/site-packages/pkg_resources/__init__.py", line 868, in _resolve_dist raise DistributionNotFound(req, requirers) pkg_resources.DistributionNotFound: The 'colorzero' distribution was not found and is required by the application See: http://lists.busybox.net/pipermail/buildroot/2023-June/669207.html Fixes: https://gitlab.com/buildroot.org/buildroot/-/jobs/4505977906 Signed-off-by: Romain Naour Cc: James Hilliard --- .../0001-Migrate-to-setup.cfg.patch | 855 ++++++++++++++++++ 1 file changed, 855 insertions(+) create mode 100644 package/python-gpiozero/0001-Migrate-to-setup.cfg.patch diff --git a/package/python-gpiozero/0001-Migrate-to-setup.cfg.patch b/package/python-gpiozero/0001-Migrate-to-setup.cfg.patch new file mode 100644 index 0000000000..090bcbc4a3 --- /dev/null +++ b/package/python-gpiozero/0001-Migrate-to-setup.cfg.patch @@ -0,0 +1,855 @@ +From d56ca0ee4fde7fa4ad82a532f9ea387f9f33d389 Mon Sep 17 00:00:00 2001 +From: Dave Jones +Date: Tue, 16 Mar 2021 17:52:49 +0000 +Subject: [PATCH] Migrate to setup.cfg + +(cherry picked from commit b167bef82c3bf2739707f062b35fcabbb9cc11ad) + +setup.cfg seems to be mandatory since (at least) setuptools 67.8.0 +otherwise gpiozero dependencies are not properly detected + +File "/builds/buildroot.org/buildroot/test-output/TestPythonPy3Gpiozero/host/lib/python3.11/site-packages/pkg_resources/__init__.py", +line 868, in _resolve_dist + raise DistributionNotFound(req, requirers) +pkg_resources.DistributionNotFound: The 'colorzero' distribution was not found +and is required by the application + +Upstream: https://github.com/gpiozero/gpiozero/commit/b167bef82c3bf2739707f062b35fcabbb9cc11ad + +See: +http://lists.busybox.net/pipermail/buildroot/2023-June/669207.html + +[Romain: rebase on 1.6.2] +Signed-off-by: Romain Naour +--- + MANIFEST.in | 4 -- + Makefile | 88 +++++--------------------------- + copyrights | 56 +++++++++++--------- + copyrights.cfg | 11 ---- + coverage.cfg | 18 ------- + docs/conf.py | 99 +++++++++++++++-------------------- + setup.cfg | 98 +++++++++++++++++++++++++++++++++++ + setup.py | 136 +++++-------------------------------------------- + 8 files changed, 196 insertions(+), 314 deletions(-) + delete mode 100644 MANIFEST.in + delete mode 100644 copyrights.cfg + delete mode 100644 coverage.cfg + create mode 100644 setup.cfg + +diff --git a/MANIFEST.in b/MANIFEST.in +deleted file mode 100644 +index bb562ea..0000000 +--- a/MANIFEST.in ++++ /dev/null +@@ -1,4 +0,0 @@ +-include README.rst +-recursive-include gpiozero/fonts *.txt +-recursive-include tests *.py +-include LICENSE.rst +diff --git a/Makefile b/Makefile +index c9ddd90..264a73c 100644 +--- a/Makefile ++++ b/Makefile +@@ -4,44 +4,18 @@ + PYTHON=python + PIP=pip + PYTEST=py.test +-COVERAGE=coverage + TWINE=twine + PYFLAGS= + DEST_DIR=/ + +-# Horrid hack to ensure setuptools is installed in our python environment. This +-# is necessary with Python 3.3's venvs which don't install it by default. +-ifeq ($(shell python -c "import setuptools" 2>&1),) +-SETUPTOOLS:= +-else +-SETUPTOOLS:=$(shell wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | $(PYTHON)) +-endif +- + # Calculate the base names of the distribution, the location of all source, + # documentation, packaging, icon, and executable script files + NAME:=$(shell $(PYTHON) $(PYFLAGS) setup.py --name) + VER:=$(shell $(PYTHON) $(PYFLAGS) setup.py --version) +-ifeq ($(shell lsb_release -si),Ubuntu) +-DEB_SUFFIX:=ubuntu1 +-else +-DEB_SUFFIX:= +-endif +-DEB_ARCH:=$(shell dpkg --print-architecture) + PYVER:=$(shell $(PYTHON) $(PYFLAGS) -c "import sys; print('py%d.%d' % sys.version_info[:2])") + PY_SOURCES:=$(shell \ + $(PYTHON) $(PYFLAGS) setup.py egg_info >/dev/null 2>&1 && \ + grep -v "\.egg-info" $(NAME).egg-info/SOURCES.txt) +-DEB_SOURCES:=debian/changelog \ +- debian/control \ +- debian/copyright \ +- debian/rules \ +- debian/docs \ +- $(wildcard debian/*.init) \ +- $(wildcard debian/*.default) \ +- $(wildcard debian/*.manpages) \ +- $(wildcard debian/*.docs) \ +- $(wildcard debian/*.doc-base) \ +- $(wildcard debian/*.desktop) + DOC_SOURCES:=docs/conf.py \ + $(wildcard docs/*.png) \ + $(wildcard docs/*.svg) \ +@@ -56,17 +30,6 @@ SUBDIRS:= + DIST_WHEEL=dist/$(NAME)-$(VER)-py2.py3-none-any.whl + DIST_TAR=dist/$(NAME)-$(VER).tar.gz + DIST_ZIP=dist/$(NAME)-$(VER).zip +-DIST_DEB=dist/python-$(NAME)_$(VER)$(DEB_SUFFIX)_all.deb \ +- dist/python3-$(NAME)_$(VER)$(DEB_SUFFIX)_all.deb \ +- dist/python-$(NAME)-doc_$(VER)$(DEB_SUFFIX)_all.deb \ +- dist/$(NAME)_$(VER)$(DEB_SUFFIX)_$(DEB_ARCH).build \ +- dist/$(NAME)_$(VER)$(DEB_SUFFIX)_$(DEB_ARCH).buildinfo \ +- dist/$(NAME)_$(VER)$(DEB_SUFFIX)_$(DEB_ARCH).changes +-DIST_DSC=dist/$(NAME)_$(VER)$(DEB_SUFFIX).tar.xz \ +- dist/$(NAME)_$(VER)$(DEB_SUFFIX).dsc \ +- dist/$(NAME)_$(VER)$(DEB_SUFFIX)_source.build \ +- dist/$(NAME)_$(VER)$(DEB_SUFFIX)_source.buildinfo \ +- dist/$(NAME)_$(VER)$(DEB_SUFFIX)_source.changes + + + # Default target +@@ -76,10 +39,9 @@ all: + @echo "make test - Run tests" + @echo "make doc - Generate HTML and PDF documentation" + @echo "make source - Create source package" +- @echo "make egg - Generate a PyPI egg package" ++ @echo "make wheel - Generate a PyPI wheel package" + @echo "make zip - Generate a source zip package" + @echo "make tar - Generate a source tar package" +- @echo "make deb - Generate Debian packages" + @echo "make dist - Generate all packages" + @echo "make clean - Get rid of all generated files" + @echo "make release - Create and tag a new release" +@@ -102,9 +64,7 @@ zip: $(DIST_ZIP) + + tar: $(DIST_TAR) + +-deb: $(DIST_DEB) $(DIST_DSC) +- +-dist: $(DIST_WHEEL) $(DIST_DEB) $(DIST_DSC) $(DIST_TAR) $(DIST_ZIP) ++dist: $(DIST_WHEEL) $(DIST_TAR) $(DIST_ZIP) + + develop: + @# These have to be done separately to avoid a cockup... +@@ -113,18 +73,17 @@ develop: + $(PIP) install -e .[doc,test] + + test: +- $(COVERAGE) run --rcfile coverage.cfg -m $(PYTEST) tests -v -r sx +- $(COVERAGE) report --rcfile coverage.cfg ++ $(PYTEST) tests + + clean: +- dh_clean +- rm -fr dist/ $(NAME).egg-info/ tags ++ rm -fr dist/ build/ .pytest_cache/ .mypy_cache/ $(NAME).egg-info/ tags .coverage + for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir clean; \ + done ++ find $(CURDIR) -name "*.pyc" -delete + + tags: $(PY_SOURCES) +- ctags -R --exclude="build/*" --exclude="debian/*" --exclude="docs/*" --languages="Python" ++ ctags -R --exclude="build/*" --exclude="docs/*" --languages="Python" + + $(SUBDIRS): + $(MAKE) -C $@ +@@ -138,37 +97,14 @@ $(DIST_ZIP): $(PY_SOURCES) $(SUBDIRS) + $(DIST_WHEEL): $(PY_SOURCES) $(SUBDIRS) + $(PYTHON) $(PYFLAGS) setup.py bdist_wheel --universal + +-$(DIST_DEB): $(PY_SOURCES) $(SUBDIRS) $(DEB_SOURCES) $(DIST_TAR) +- cp $(DIST_TAR) ../$(NAME)_$(VER).orig.tar.gz +- debuild -b +- mkdir -p dist/ +- for f in $(DIST_DEB); do cp ../$${f##*/} dist/; done +- +-$(DIST_DSC): $(PY_SOURCES) $(SUBDIRS) $(DEB_SOURCES) $(DIST_TAR) +- cp $(DIST_TAR) ../$(NAME)_$(VER).orig.tar.gz +- debuild -S +- mkdir -p dist/ +- for f in $(DIST_DSC); do cp ../$${f##*/} dist/; done +- +-copyrights: $(PY_SOURCES) $(DOC_SOURCES) +- ./copyrights +- +-changelog: $(PY_SOURCES) $(DOC_SOURCES) $(DEB_SOURCES) ++release: + $(MAKE) clean +- # ensure there are no current uncommitted changes + test -z "$(shell git status --porcelain)" +- # update the debian changelog with new release information +- dch --newversion $(VER)$(DEB_SUFFIX) +- # commit the changes and add a new tag +- git commit debian/changelog -m "Updated changelog for release $(VER)" +- +-release: $(DIST_DEB) $(DIST_DSC) $(DIST_TAR) $(DIST_WHEEL) + git tag -s v$(VER) -m "Release v$(VER)" +- git push --tags +- # build a source archive and upload to PyPI ++ git push origin v$(VER) ++ ++upload: $(DIST_TAR) $(DIST_WHEEL) ++ $(TWINE) check $(DIST_TAR) $(DIST_WHEEL) + $(TWINE) upload $(DIST_TAR) $(DIST_WHEEL) +- # build the deb source archive and upload to Raspbian +- dput raspberrypi dist/$(NAME)_$(VER)$(DEB_SUFFIX)_source.changes +- dput raspberrypi dist/$(NAME)_$(VER)$(DEB_SUFFIX)_$(DEB_ARCH).changes + +-.PHONY: all install develop test doc source egg wheel zip tar deb dist clean tags release upload $(SUBDIRS) ++.PHONY: all install develop test doc source wheel zip tar dist clean tags release upload $(SUBDIRS) +diff --git a/copyrights b/copyrights +index b709fc8..2f14e78 100755 +--- a/copyrights ++++ b/copyrights +@@ -6,10 +6,13 @@ derives the authorship and copyright years information from the git history + of the project; hence, this script must be run within a git repository. + """ + ++from __future__ import annotations ++ + import os + import sys + assert sys.version_info >= (3, 6), 'Script requires Python 3.6+' + import tempfile ++import typing as t + from argparse import ArgumentParser, Namespace + from configparser import ConfigParser + from operator import attrgetter +@@ -18,14 +21,13 @@ from datetime import datetime + from subprocess import Popen, PIPE, DEVNULL + from pathlib import Path + from fnmatch import fnmatch +-from typing import NamedTuple, Iterator, List, Tuple, Set, Union, Optional + + + SPDX_PREFIX = 'SPDX-License-Identifier:' + COPYRIGHT_PREFIX = 'Copyright (c)' + + +-def main(args: List[str] = None): ++def main(args: t.List[str] = None): + if args is None: + args = sys.argv[1:] + config = get_config(args) +@@ -41,7 +43,7 @@ def main(args: List[str] = None): + target.write(chunk) + + +-def get_config(args: List[str]) -> Namespace: ++def get_config(args: t.List[str]) -> Namespace: + config = ConfigParser( + defaults={ + 'include': '**/*', +@@ -52,10 +54,10 @@ def get_config(args: List[str]) -> Namespace: + 'spdx_prefix': SPDX_PREFIX, + 'copy_prefix': COPYRIGHT_PREFIX, + }, +- delimiters=('=',), default_section='settings', ++ delimiters=('=',), default_section='copyrights:settings', + empty_lines_in_values=False, interpolation=None, + converters={'list': lambda s: s.strip().splitlines() }) +- config.read('copyrights.cfg') ++ config.read('setup.cfg') + sect = config[config.default_section] + + parser = ArgumentParser(description=__doc__) +@@ -113,10 +115,10 @@ def get_config(args: List[str]) -> Namespace: + return ns + + +-class Copyright(NamedTuple): ++class Copyright(t.NamedTuple): + author: str + email: str +- years: Set[int] ++ years: t.Set[int] + + def __str__(self): + if len(self.years) > 1: +@@ -126,8 +128,8 @@ class Copyright(NamedTuple): + return f'{years} {self.author} <{self.email}>' + + +-def get_copyrights(include: Set[str], exclude: Set[str])\ +- -> Iterator[Tuple[Path, List[Copyright]]]: ++def get_copyrights(include: t.Set[str], exclude: t.Set[str])\ ++ -> t.Iterator[t.Tuple[Path, t.Container[Copyright]]]: + sorted_blame = sorted( + get_contributions(include, exclude), + key=lambda c: (c.path, c.author, c.email) +@@ -147,15 +149,15 @@ def get_copyrights(include: Set[str], exclude: Set[str])\ + yield path, copyrights + + +-class Contribution(NamedTuple): ++class Contribution(t.NamedTuple): + author: str + email: str + year: int + path: Path + + +-def get_contributions(include: Set[str], exclude: Set[str])\ +- -> Iterator[Contribution]: ++def get_contributions(include: t.Set[str], exclude: t.Set[str])\ ++ -> t.Iterator[Contribution]: + for path in get_source_paths(include, exclude): + blame = Popen( + ['git', 'blame', '--line-porcelain', 'HEAD', '--', str(path)], +@@ -186,7 +188,8 @@ def get_contributions(include: Set[str], exclude: Set[str])\ + assert blame.returncode == 0 + + +-def get_source_paths(include: Set[str], exclude: Set[str]) -> Iterator[Path]: ++def get_source_paths(include: t.Set[str], exclude: t.Set[str])\ ++ -> t.Iterator[Path]: + ls_tree = Popen( + ['git', 'ls-tree', '-r', '--name-only', 'HEAD'], + stdout=PIPE, stderr=DEVNULL, universal_newlines=True) +@@ -203,9 +206,9 @@ def get_source_paths(include: Set[str], exclude: Set[str]) -> Iterator[Path]: + assert ls_tree.returncode == 0 + + +-class License(NamedTuple): +- ident: Optional[str] +- text: List[str] ++class License(t.NamedTuple): ++ ident: t.Optional[str] ++ text: t.List[str] + + + def get_license(path: Path, *, spdx_prefix: str = SPDX_PREFIX) -> License: +@@ -253,20 +256,26 @@ class CopyWriter: + '.sql': '--', + } + +- def __init__(self, license='LICENSE.txt', preamble=(), +- spdx_prefix=SPDX_PREFIX, copy_prefix=COPYRIGHT_PREFIX): ++ def __init__(self, license: Path=Path('LICENSE.txt'), ++ preamble: t.List[str]=None, ++ spdx_prefix: str=SPDX_PREFIX, ++ copy_prefix: str=COPYRIGHT_PREFIX): ++ if preamble is None: ++ preamble = [] + self.license = get_license(license, spdx_prefix=spdx_prefix) + self.preamble = preamble + self.spdx_prefix = spdx_prefix + self.copy_prefix = copy_prefix + + @classmethod +- def from_config(cls, config): ++ def from_config(cls, config: Namespace) -> CopyWriter: + return cls( + config.license, config.preamble, + config.spdx_prefix, config.copy_prefix) + +- def transform(self, source, copyrights, *, comment_prefix=None): ++ def transform(self, source: t.TextIO, ++ copyrights: t.List[Copyright], *, ++ comment_prefix: str=None) -> t.Iterator[str]: + if comment_prefix is None: + comment_prefix = self.COMMENTS[Path(source.name).suffix] + license_start = self.license.text[0] +@@ -279,7 +288,7 @@ class CopyWriter: + yield line + empty = False + elif linenum < 3 and ( +- 'set fileencoding=' in line or '-*- coding:' in line): ++ 'fileencoding=' in line or '-*- coding:' in line): + yield line + empty = False + elif line.rstrip() == comment_prefix: +@@ -313,7 +322,8 @@ class CopyWriter: + elif state == 'body': + yield line + +- def _generate_header(self, copyrights, comment_prefix, empty): ++ def _generate_header(self, copyrights: t.Iterable[Copyright], ++ comment_prefix: str, empty: bool) -> t.Iterator[str]: + if not empty: + yield comment_prefix + '\n' + for line in self.preamble: +@@ -356,7 +366,7 @@ class AtomicReplaceFile: + If ``None`` (the default), the temporary file will be opened in binary + mode. Otherwise, this specifies the encoding to use with text mode. + """ +- def __init__(self, path: Union[str, Path], encoding: str = None): ++ def __init__(self, path: t.Union[str, Path], encoding: str = None): + if isinstance(path, str): + path = Path(path) + self._path = path +diff --git a/copyrights.cfg b/copyrights.cfg +deleted file mode 100644 +index de68dbe..0000000 +--- a/copyrights.cfg ++++ /dev/null +@@ -1,11 +0,0 @@ +-[settings] +-include= +- **/*.py +- **/*.rst +-exclude= +- docs/examples/*.py +- docs/license.rst +-license=LICENSE.rst +-preamble= +- GPIO Zero: a library for controlling the Raspberry Pi's GPIO pins +-strip-preamble=no +diff --git a/coverage.cfg b/coverage.cfg +deleted file mode 100644 +index e3f3349..0000000 +--- a/coverage.cfg ++++ /dev/null +@@ -1,18 +0,0 @@ +-[run] +-branch = True +-include = gpiozero/* +-;omit = */bar.py,*/baz.py +- +-[report] +-ignore_errors = True +-show_missing = True +-exclude_lines = +- pragma: no cover +- assert False +- raise AssertionError +- raise NotImplementedError +- pass +- if __name__ == .__main__.: +- +-[html] +-directory = coverage +diff --git a/docs/conf.py b/docs/conf.py +index 998ae91..626ae29 100644 +--- a/docs/conf.py ++++ b/docs/conf.py +@@ -11,62 +11,34 @@ + + import sys + import os ++from pathlib import Path + from datetime import datetime +-sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) +-on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +-import setup as _setup +- +-# Mock out certain modules while building documentation +-class Mock(object): +- __all__ = [] +- +- def __init__(self, *args, **kw): +- pass +- +- def __call__(self, *args, **kw): +- return Mock() +- +- def __mul__(self, other): +- return Mock() +- +- def __and__(self, other): +- return Mock() ++from setuptools.config import read_configuration + +- def __bool__(self): +- return False +- +- def __nonzero__(self): +- return False +- +- @classmethod +- def __getattr__(cls, name): +- if name in ('__file__', '__path__'): +- return '/dev/null' +- else: +- return Mock() +- +-sys.modules['RPi'] = Mock() +-sys.modules['RPi.GPIO'] = sys.modules['RPi'].GPIO +-sys.modules['lgpio'] = Mock() +-sys.modules['RPIO'] = Mock() +-sys.modules['RPIO.PWM'] = sys.modules['RPIO'].PWM +-sys.modules['RPIO.Exceptions'] = sys.modules['RPIO'].Exceptions +-sys.modules['pigpio'] = Mock() +-sys.modules['w1thermsensor'] = Mock() +-sys.modules['spidev'] = Mock() +-sys.modules['colorzero'] = Mock() ++on_rtd = os.environ.get('READTHEDOCS', None) == 'True' ++config = read_configuration(str(Path(__file__).parent / '..' / 'setup.cfg')) ++info = config['metadata'] + + # -- General configuration ------------------------------------------------ + + extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx'] ++if on_rtd: ++ needs_sphinx = '1.4.0' ++ extensions.append('sphinx.ext.imgmath') ++ imgmath_image_format = 'svg' ++ tags.add('rtd') ++else: ++ extensions.append('sphinx.ext.mathjax') ++ mathjax_path = '/usr/share/javascript/mathjax/MathJax.js?config=TeX-AMS_HTML' ++ + templates_path = ['_templates'] + source_suffix = '.rst' + #source_encoding = 'utf-8-sig' + master_doc = 'index' +-project = 'GPIO Zero' +-copyright = '2015-%s %s' % (datetime.now().year, _setup.__author__) +-version = _setup.__version__ +-release = _setup.__version__ ++project = info['name'] ++copyright = '2015-{now:%Y} {info[author]}'.format(now=datetime.now(), info=info) ++version = info['version'] ++#release = None + #language = None + #today_fmt = '%B %d, %Y' + exclude_patterns = ['_build'] +@@ -82,6 +54,15 @@ pygments_style = 'sphinx' + # -- Autodoc configuration ------------------------------------------------ + + autodoc_member_order = 'groupwise' ++autodoc_mock_imports = [ ++ 'RPi', ++ 'lgpio', ++ 'RPIO', ++ 'pigpio', ++ 'w1thermsensor', ++ 'spidev', ++ 'colorzero', ++] + + # -- Intersphinx configuration -------------------------------------------- + +@@ -94,7 +75,7 @@ intersphinx_mapping = { + # -- Options for HTML output ---------------------------------------------- + + html_theme = 'sphinx_rtd_theme' +-html_title = '%s %s Documentation' % (project, version) ++html_title = '{info[name]} {info[version]} Documentation'.format(info=info) + #html_theme_path = [] + #html_short_title = None + #html_logo = None +@@ -112,7 +93,7 @@ html_static_path = ['_static'] + #html_show_copyright = True + #html_use_opensearch = '' + #html_file_suffix = None +-htmlhelp_basename = '%sdoc' % _setup.__project__ ++htmlhelp_basename = '{info[name]}doc'.format(info=info) + + # Hack to make wide tables work properly in RTD + # See https://github.com/snide/sphinx_rtd_theme/issues/117 for details +@@ -131,12 +112,12 @@ latex_elements = { + + latex_documents = [ + ( +- 'index', # source start file +- '%s.tex' % _setup.__project__, # target filename +- '%s Documentation' % project, # title +- _setup.__author__, # author +- 'manual', # documentclass +- True, # documents ref'd from toctree only ++ 'index', # source start file ++ project + '.tex', # target filename ++ html_title, # title ++ info['author'], # author ++ 'manual', # documentclass ++ True, # documents ref'd from toctree only + ), + ] + +@@ -149,11 +130,11 @@ latex_show_urls = 'footnote' + + # -- Options for epub output ---------------------------------------------- + +-epub_basename = _setup.__project__ ++epub_basename = project + #epub_theme = 'epub' + #epub_title = html_title +-epub_author = _setup.__author__ +-epub_identifier = 'https://gpiozero.readthedocs.io/' ++epub_author = info['author'] ++epub_identifier = 'https://{info[name]}.readthedocs.io/'.format(info=info) + #epub_tocdepth = 3 + epub_show_urls = 'no' + #epub_use_index = True +@@ -161,8 +142,8 @@ epub_show_urls = 'no' + # -- Options for manual page output --------------------------------------- + + man_pages = [ +- ('cli_pinout', 'pinout', 'GPIO Zero pinout tool', [_setup.__author__], 1), +- ('remote_gpio', 'remote-gpio', 'GPIO Zero remote GPIO guide', [_setup.__author__], 7), ++ ('cli_pinout', 'pinout', 'GPIO Zero pinout tool', [info['author']], 1), ++ ('remote_gpio', 'remote-gpio', 'GPIO Zero remote GPIO guide', [info['author']], 7), + ] + + man_show_urls = True +diff --git a/setup.cfg b/setup.cfg +new file mode 100644 +index 0000000..db0cfa4 +--- /dev/null ++++ b/setup.cfg +@@ -0,0 +1,98 @@ ++[metadata] ++name = gpiozero ++version = 1.6.2 ++description = A simple interface to GPIO devices with Raspberry Pi ++long_description = file:README.rst ++author = Ben Nuttall ++author_email = ben@bennuttall.com ++url = https://gpiozero.readthedocs.io/ ++project_urls = ++ Documentation = https://gpiozero.readthedocs.io/ ++ Source Code = https://github.com/gpiozero/gpiozero ++ Issue Tracker = https://github.com/gpiozero/gpiozero/issues ++keywords = raspberrypi gpio ++license = BSD-3-Clause ++classifiers = ++ Development Status :: 5 - Production/Stable ++ Intended Audience :: Education ++ Intended Audience :: Developers ++ Topic :: Education ++ Topic :: System :: Hardware ++ License :: OSI Approved :: BSD License ++ Programming Language :: Python :: 2 ++ Programming Language :: Python :: 2.7 ++ Programming Language :: Python :: 3 ++ Programming Language :: Python :: 3.5 ++ Programming Language :: Python :: 3.6 ++ Programming Language :: Python :: 3.7 ++ Programming Language :: Python :: 3.8 ++ Programming Language :: Python :: 3.9 ++ Programming Language :: Python :: Implementation :: PyPy ++ ++[options] ++packages = find: ++install_requires = ++ colorzero ++ ++[options.package_data] ++gpiozero = ++ fonts/*.txt ++ ++[options.extras_require] ++test = ++ pytest ++ pytest-cov ++doc = ++ sphinx ++ sphinx-rtd-theme ++ ++[options.entry_points] ++console_scripts = ++ pinout = gpiozerocli.pinout:main ++gpiozero_pin_factories = ++ pigpio = gpiozero.pins.pigpio:PiGPIOFactory ++ lgpio = gpiozero.pins.lgpio:LGPIOFactory ++ rpigpio = gpiozero.pins.rpigpio:RPiGPIOFactory ++ rpio = gpiozero.pins.rpio:RPIOFactory ++ native = gpiozero.pins.native:NativeFactory ++ mock = gpiozero.pins.mock:MockFactory ++ PiGPIOPin = gpiozero.pins.pigpio:PiGPIOFactory ++ RPiGPIOPin = gpiozero.pins.rpigpio:RPiGPIOFactory ++ RPIOPin = gpiozero.pins.rpio:RPIOFactory ++ NativePin = gpiozero.pins.native:NativeFactory ++gpiozero_mock_pin_classes = ++ mockpin = gpiozero.pins.mock:MockPin ++ mockpwmpin = gpiozero.pins.mock:MockPWMPin ++ mockchargingpin = gpiozero.pins.mock:MockChargingPin ++ mocktriggerpin = gpiozero.pins.mock:MockTriggerPin ++ ++[tools:pytest] ++addopts = -rsx --cov --tb=short ++testpaths = tests ++ ++[coverage:run] ++source = gpiozero ++branch = true ++ ++[coverage:report] ++ignore_errors = true ++show_missing = true ++exclude_lines = ++ pragma: no cover ++ assert False ++ raise AssertionError ++ raise NotImplementedError ++ pass ++ if __name__ == .__main__.: ++ ++[copyrights:settings] ++include = ++ **/*.py ++ **/*.rst ++exclude = ++ docs/examples/*.py ++ docs/license.rst ++license = LICENSE.rst ++preamble = ++ GPIO Zero: a library for controlling the Raspberry Pi's GPIO pins ++strip-preamble = false +diff --git a/setup.py b/setup.py +index 621398a..fc644b6 100644 +--- a/setup.py ++++ b/setup.py +@@ -1,139 +1,29 @@ +-"A simple interface to GPIO devices with Raspberry Pi." ++from __future__ import ( ++ unicode_literals, ++ absolute_import, ++) ++str = type('') + + import io + import os +-import sys + import errno +-from setuptools import setup, find_packages ++from setuptools import setup, config + +-if sys.version_info[0] == 2: +- if not sys.version_info >= (2, 7): +- raise ValueError('This package requires Python 2.7 or above') +-elif sys.version_info[0] == 3: +- if not sys.version_info >= (3, 2): +- raise ValueError('This package requires Python 3.2 or above') +-else: +- raise ValueError('Unrecognized major version of Python') +- +-HERE = os.path.abspath(os.path.dirname(__file__)) +- +-# Workaround +-try: +- import multiprocessing +-except ImportError: +- pass +- +-__project__ = 'gpiozero' +-__version__ = '1.6.2' +-__author__ = 'Ben Nuttall' +-__author_email__ = 'ben@bennuttall.com' +-__url__ = 'https://github.com/gpiozero/gpiozero' +-__platforms__ = 'ALL' +- +-__classifiers__ = [ +- "Development Status :: 5 - Production/Stable", +- "Intended Audience :: Education", +- "Intended Audience :: Developers", +- "Topic :: Education", +- "Topic :: System :: Hardware", +- "License :: OSI Approved :: BSD License", +- "Programming Language :: Python :: 2", +- "Programming Language :: Python :: 2.7", +- "Programming Language :: Python :: 3", +- "Programming Language :: Python :: 3.5", +- "Programming Language :: Python :: 3.6", +- "Programming Language :: Python :: 3.7", +- "Programming Language :: Python :: 3.8", +- "Programming Language :: Python :: 3.9", +- "Programming Language :: Python :: Implementation :: PyPy", +-] +- +-__keywords__ = [ +- 'raspberrypi', +- 'gpio', +-] +- +-__requires__ = [ +- 'colorzero', +-] +- +-__extra_requires__ = { +- 'doc': ['sphinx', 'sphinx_rtd_theme'], +- 'test': ['pytest', 'coverage', 'mock'], +-} +- +-if sys.version_info[:2] == (3, 2): +- # Particular versions are required for Python 3.2 compatibility +- __extra_requires__['doc'].extend([ +- 'Jinja2<2.7', +- 'MarkupSafe<0.16', +- ]) +- __extra_requires__['test'][0] = 'pytest<3.0dev' +- __extra_requires__['test'][1] = 'coverage<4.0dev' +-elif sys.version_info[:2] == (3, 3): +- __extra_requires__['test'][0] = 'pytest<3.3dev' +-elif sys.version_info[:2] == (3, 4): +- __extra_requires__['test'][0] = 'pytest<5.0dev' ++cfg = config.read_configuration( ++ os.path.join(os.path.dirname(__file__), 'setup.cfg')) + + try: + # If we're executing on a Raspberry Pi, install all GPIO libraries for + # testing (except RPIO which doesn't work on the multi-core models yet) + with io.open('/proc/device-tree/model', 'r') as f: + if f.read().startswith('Raspberry Pi'): +- __extra_requires__['test'].append('RPi.GPIO') +- __extra_requires__['test'].append('pigpio') ++ cfg['options']['extras_require']['test'].append('RPI.GPIO') ++ cfg['options']['extras_require']['test'].append('pigpio') + except IOError as e: + if e.errno != errno.ENOENT: + raise + +-__entry_points__ = { +- 'gpiozero_pin_factories': [ +- 'pigpio = gpiozero.pins.pigpio:PiGPIOFactory', +- 'lgpio = gpiozero.pins.lgpio:LGPIOFactory', +- 'rpigpio = gpiozero.pins.rpigpio:RPiGPIOFactory', +- 'rpio = gpiozero.pins.rpio:RPIOFactory', +- 'native = gpiozero.pins.native:NativeFactory', +- 'mock = gpiozero.pins.mock:MockFactory', +- # Backwards compatible names +- 'PiGPIOPin = gpiozero.pins.pigpio:PiGPIOFactory', +- 'RPiGPIOPin = gpiozero.pins.rpigpio:RPiGPIOFactory', +- 'RPIOPin = gpiozero.pins.rpio:RPIOFactory', +- 'NativePin = gpiozero.pins.native:NativeFactory', +- ], +- 'gpiozero_mock_pin_classes': [ +- 'mockpin = gpiozero.pins.mock:MockPin', +- 'mockpwmpin = gpiozero.pins.mock:MockPWMPin', +- 'mockchargingpin = gpiozero.pins.mock:MockChargingPin', +- 'mocktriggerpin = gpiozero.pins.mock:MockTriggerPin', +- ], +- 'console_scripts': [ +- 'pinout = gpiozerocli.pinout:main', +- ] +-} +- +- +-def main(): +- import io +- with io.open(os.path.join(HERE, 'README.rst'), 'r') as readme: +- setup( +- name = __project__, +- version = __version__, +- description = __doc__, +- long_description = readme.read(), +- classifiers = __classifiers__, +- author = __author__, +- author_email = __author_email__, +- url = __url__, +- license = 'BSD-3-Clause', +- keywords = __keywords__, +- packages = find_packages(), +- include_package_data = True, +- platforms = __platforms__, +- install_requires = __requires__, +- extras_require = __extra_requires__, +- entry_points = __entry_points__, +- ) +- ++opts = cfg['metadata'] ++opts.update(cfg['options']) + +-if __name__ == '__main__': +- main() ++setup(**opts) +-- +2.41.0 +