#!/usr/bin/env python
#
# This file is part of the django-environ.
#
# Copyright (c) 2021, Serghei Iakovlev <egrep@protonmail.ch>
# Copyright (c) 2013-2021, Daniele Faraglia <daniele.faraglia@gmail.com>
#
# For the full copyright and license information, please view
# the LICENSE.txt file that was distributed with this source code.
import codecs
import re
from os import path
from setuptools import find_packages, setup
def read_file(filepath):
"""Read content from a UTF-8 encoded text file."""
with codecs.open(filepath, 'rb', 'utf-8') as file_handle:
return file_handle.read()
PKG_NAME = 'django-environ'
PKG_DIR = path.abspath(path.dirname(__file__))
META_PATH = path.join(PKG_DIR, 'environ', '__init__.py')
META_CONTENTS = read_file(META_PATH)
def load_long_description():
"""Load long description from file README.rst."""
def changes():
changelog = path.join(PKG_DIR, 'CHANGELOG.rst')
pattern = (
r'(`(v\d+.\d+.\d+)`_( - \d{1,2}-\w+-\d{4}\r?\n-+\r?\n.*?))'
r'\r?\n\r?\n\r?\n`v\d+.\d+.\d+`_'
)
result = re.search(pattern, read_file(changelog), re.S)
return result.group(2) + result.group(3) if result else ''
try:
title = PKG_NAME
head = '=' * (len(title))
contents = (
head,
format(title.strip(' .')),
head,
read_file(path.join(PKG_DIR, 'README.rst')).split(
'.. -teaser-begin-'
)[1],
'',
read_file(path.join(PKG_DIR, 'CONTRIBUTING.rst')),
'',
'Release Information',
'===================\n',
changes(),
'',
'`Full changelog <{}/en/latest/changelog.html>`_.'.format(
find_meta('url')
),
'',
read_file(path.join(PKG_DIR, 'SECURITY.rst')),
'',
read_file(path.join(PKG_DIR, 'AUTHORS.rst')),
)
return '\n'.join(contents)
except (RuntimeError, FileNotFoundError) as read_error:
message = 'Long description could not be read from README.rst'
raise RuntimeError('%s: %s' % (message, read_error)) from read_error
def is_canonical_version(version):
"""Check if a version string is in the canonical format of PEP 440."""
pattern = (
r'^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))'
r'*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))'
r'?(\.dev(0|[1-9][0-9]*))?$')
return re.match(pattern, version) is not None
def find_meta(meta):
"""Extract __*meta*__ from META_CONTENTS."""
meta_match = re.search(
r"^__{meta}__\s+=\s+['\"]([^'\"]*)['\"]".format(meta=meta),
META_CONTENTS,
re.M
)
if meta_match:
return meta_match.group(1)
raise RuntimeError(
'Unable to find __%s__ string in package meta file' % meta)
def get_version_string():
"""Return package version as listed in `__version__` in meta file."""
# Parse version string
version_string = find_meta('version')
# Check validity
if not is_canonical_version(version_string):
message = (
'The detected version string "{}" is not in canonical '
'format as defined in PEP 440.'.format(version_string))
raise ValueError(message)
return version_string
# What does this project relate to.
KEYWORDS = [
'environment',
'django',
'variables',
'12factor',
]
# Classifiers: available ones listed at https://pypi.org/classifiers
CLASSIFIERS = [
'Development Status :: 5 - Production/Stable',
'Framework :: Django',
'Framework :: Django :: 1.11',
'Framework :: Django :: 2.0',
'Framework :: Django :: 2.1',
'Framework :: Django :: 2.2',
'Framework :: Django :: 3.0',
'Framework :: Django :: 3.1',
'Framework :: Django :: 3.2',
'Framework :: Django :: 4.0',
'Operating System :: OS Independent',
'Intended Audience :: Developers',
'Natural Language :: English',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'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 :: 3.10',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Utilities',
'License :: OSI Approved :: MIT License',
]
# Dependencies that are downloaded by pip on installation and why.
INSTALL_REQUIRES = []
DEPENDENCY_LINKS = []
# List additional groups of dependencies here (e.g. testing dependencies).
# You can install these using the following syntax, for example:
#
# $ pip install -e .[testing,docs,develop]
#
EXTRAS_REQUIRE = {
# Dependencies that are required to run tests
'testing': [
'coverage[toml]>=5.0a4', # Code coverage measurement for Python
'pytest>=4.6.11', # Our tests framework
],
# Dependencies that are required to build documentation
'docs': [
'furo>=2021.8.17b43,==2021.8.*', # Sphinx documentation theme
'sphinx>=3.5.0', # Python documentation generator
'sphinx-notfound-page', # Create a custom 404 page
],
}
# Dependencies that are required to develop package
DEVELOP_REQUIRE = []
# Dependencies that are required to develop package
EXTRAS_REQUIRE['develop'] = \
DEVELOP_REQUIRE + EXTRAS_REQUIRE['testing'] + EXTRAS_REQUIRE['docs']
# Project's URLs
PROJECT_URLS = {
'Documentation': find_meta('url'),
'Funding': 'https://opencollective.com/django-environ',
'Say Thanks!': 'https://saythanks.io/to/joke2k',
'Changelog': '{}/en/latest/changelog.html'.format(find_meta('url')),
'Bug Tracker': 'https://github.com/joke2k/django-environ/issues',
'Source Code': 'https://github.com/joke2k/django-environ',
}
if __name__ == '__main__':
setup(
name=PKG_NAME,
version=get_version_string(),
author=find_meta('author'),
author_email=find_meta('author_email'),
maintainer=find_meta('maintainer'),
maintainer_email=find_meta('maintainer_email'),
license=find_meta('license'),
description=find_meta('description'),
long_description=load_long_description(),
long_description_content_type='text/x-rst',
keywords=KEYWORDS,
url=find_meta('url'),
project_urls=PROJECT_URLS,
classifiers=CLASSIFIERS,
packages=find_packages(exclude=['tests.*', 'tests']),
platforms=['any'],
include_package_data=True,
zip_safe=False,
python_requires='>=3.4,<4',
install_requires=INSTALL_REQUIRES,
dependency_links=DEPENDENCY_LINKS,
extras_require=EXTRAS_REQUIRE,
)