# *****************************************************************************
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# ******************************************************************************
import os
import sys
from setuptools import find_packages
"""Author of the package email address"""
[docs]AUTHOR_EMAIL = 'dev@dlab.apache.org'
""" author of the package """
[docs]AUTHOR = 'Apache Software Foundation'
"""
Gives the index and pip some additional metadata about your package. In this
case, the package is only compatible with Python 3, is licensed under the MIT
license, and is OS-independent. You should always include at least which
version(s) of Python your package works on, which license your package is
available under, and which operating systems your package will work on. For a
complete list of classifiers, see https://pypi.org/classifiers/.
"""
[docs]CLASSIFIERS = [
"Development Status :: 1 - Planning ",
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"Topic :: Software Development",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Clustering",
"Topic :: System :: Software Distribution",
"Topic :: System :: Systems Administration",
]
"""
Type of markup is used for the long description. In this case, it's Markdown.
"""
[docs]DESCRIPTION_CONTENT_TYPE = "text/markdown"
"""
Text indicating the license covering the package where the license is not a
selection from the "License" Trove classifiers. See the Classifier field.
Notice that there's a licence distribution option which is deprecated but still
acts as an alias for license.
"""
"""
Appropriate PEP 440 version specifier string will prevent pip from installing
the project on other Python versions
"""
[docs]PYTHON_REQUIRES = ', '.join([
'>=2.7',
'!=3.0.*',
'!=3.1.*',
'!=3.2.*',
'!=3.3.*'
])
"""
URL for the homepage of the project. For many projects, this will just be a
link to GitHub, GitLab, Bitbucket, or similar code hosting service.
"""
[docs]URL = "https://github.com/apache/incubator-dlab"
""" Version file name location """
[docs]VERSION_FILE = '__version__.py'
""" Readme file location """
[docs]README_FILE = 'README.md'
""" requirements.txt file location """
[docs]REQUIREMENTS_FILE = 'requirements.txt'
[docs]class SetupException(Exception):
"""Class for Setup exceptions."""
pass
[docs]class FileNotFoundException(IOError):
"""Exception class thrown when a file couldn't be found"""
pass
[docs]class SetupParametersDirector:
"""Construct an parameters dict using the BaseSetupParametersBuilder
interface.
"""
def __init__(self):
"""Director constructor.
"""
self._builder = None
[docs] def build(self, builder):
"""Build setup parameters.
:param builder: Parameters builder.
:type builder: BaseSetupParametersBuilder
:return: None
"""
self._builder = builder
self._builder.set_packages()
self._builder.set_requirements()
self._builder.set_version()
self._builder.set_long_description()
self._builder.set_entry_points()
self._builder.set_package_data()
@property
[docs] def parameters(self):
"""Get parameters list as dict for setup.py
:return: dict
"""
builder = self._builder # type: SetupParametersBuilder
return builder.parameters
[docs]class SetupParametersBuilder(object):
"""Creating parts of a setup parameters dict see PEP 561 for more details
about Distributing and Packaging Type Information
"""
def __init__(self, name, description):
"""Builder constructor.
:type name: str
:param name: Distribution name of your package.
:type description: str
:param description: Short, one-sentence summary of the package.
"""
self._name = name
self._parameters = {
'name': name,
'description': description,
'classifiers': CLASSIFIERS,
'url': URL,
'author': AUTHOR,
'author_email': AUTHOR_EMAIL,
'license': LICENSE,
'python_requires': PYTHON_REQUIRES,
'long_description_content_type': DESCRIPTION_CONTENT_TYPE,
'packages': None,
'install_requires': None,
'version': None,
'long_description': None,
}
@property
[docs] def entry_points(self):
"""Get setup entry points
:return: dict
"""
return {}
@property
[docs] def package_data(self):
"""Get setup package data
:return: dict
"""
return {}
@property
[docs] def parameters(self):
"""Get parameters list as dict for setup.py
:return: dict
"""
return self._parameters
@staticmethod
[docs] def _read_file(name):
"""Get content by filename.
:type name: str
:param name: File location.
:return: str
"""
if not os.path.isfile(name):
raise FileNotFoundException(
"No such file or directory: '{}'".format(name)
)
try:
with open(name, "r") as fh:
return fh.read()
except IOError as e:
if hasattr(e, 'filename'):
e = SetupException("{}: '{}'".format(
e.strerror,
e.filename
))
raise e
[docs] def set_packages(self):
"""Set list of all Python import packages that should be included in
the distribution package. Instead of listing each package manually, we
can use find_packages() to automatically discover all packages and
subpackages. In this case, the list of packages will be example_pkg as
that's the only package present.
:return: None
"""
self._parameters['packages'] = find_packages()
[docs] def set_requirements(self):
"""Set libraries list that should be used to specify what a project
minimally needs to run correctly. When the project is installed by pip,
this is the specification that is used to install its dependencies.
:return: None
"""
content = self._read_file(REQUIREMENTS_FILE)
self._parameters['install_requires'] = content.splitlines()
if sys.platform == 'win32':
self._parameters['install_requires'].append('pypiwin32')
@property
[docs] def lib_file(self):
"""Get library file location.
:return: str
"""
return self._name + '.py'
@property
[docs] def version_file(self):
"""Get version file location.
:return: str
"""
return os.path.join(self._name, VERSION_FILE)
[docs] def set_version(self):
"""Set package version see PEP 440 for more details on versions.
:return: None
"""
_locals = {}
try:
content = self._read_file(self.lib_file)
except FileNotFoundException:
content = None
try:
if content is None:
content = self._read_file(self.version_file)
exec(content, None, _locals)
self._parameters['version'] = _locals['__version__']
except SyntaxError as e:
raise SetupException(e.text)
except KeyError:
raise SetupException("name '{}' is not defined".format(
'__version__'
))
except FileNotFoundException:
raise SetupException('No version or library file')
[docs] def set_long_description(self):
"""Set detailed description of the package. This is shown on the
package detail package on the Python Package Index. In this case, the
long description is loaded from README.md which is a common pattern.
:return: None
"""
content = self._read_file(README_FILE)
self._parameters['long_description'] = content
[docs] def set_entry_points(self):
"""
A dictionary mapping entry point group names to strings or lists of
strings defining the entry points. Entry points are used to support
dynamic discovery of services or plugins provided by a project. See
Dynamic Discovery of Services and Plugins for details and examples of
the format of this argument. In addition, this keyword is used to
support Automatic Script Creation.
:return: None
"""
if self.entry_points:
self._parameters['entry_points'] = self.entry_points
[docs] def set_package_data(self):
"""
Include package data
:return: None
"""
if self.package_data:
self._parameters['package_data'] = self.package_data
self._parameters['include_package_data'] = True