Initial import.
Strongly deriving from current pywwt, but I've tried to go through and rip out all actual content. I want to start right off with docs, testing, code coverage, and so on.
This commit is contained in:
Коммит
983731b028
|
@ -0,0 +1,12 @@
|
|||
[run]
|
||||
omit =
|
||||
wwt_api_client/*tests/*
|
||||
|
||||
[report]
|
||||
omit =
|
||||
wwt_api_client/*tests/*
|
||||
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
if __name__ == .__main__.:
|
||||
raise NotImplementedError
|
|
@ -0,0 +1,9 @@
|
|||
/*.egg
|
||||
/*.egg-info
|
||||
*.py[cod]
|
||||
.coverage
|
||||
__pycache__/
|
||||
build
|
||||
dist
|
||||
MANIFEST
|
||||
sdist
|
|
@ -0,0 +1,31 @@
|
|||
language: c
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
sudo: false
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
env:
|
||||
global:
|
||||
- CONDA_DEPENDENCIES="pytest pytest-cov nomkl"
|
||||
- PIP_DEPENDENCIES="sphinx-automodapi numpydoc sphinx_rtd_theme pytest-faulthandler codecov"
|
||||
matrix:
|
||||
- PYTHON_VERSION=2.7
|
||||
- PYTHON_VERSION=3.6
|
||||
- PYTHON_VERSION=3.7
|
||||
|
||||
install:
|
||||
- git clone git://github.com/astropy/ci-helpers.git
|
||||
- source ci-helpers/travis/setup_conda.sh
|
||||
|
||||
script:
|
||||
- python setup.py sdist
|
||||
- cd dist; pip install *.tar.gz --verbose; cd ..
|
||||
- pytest wwt_api_client --cov wwt_api_client
|
||||
- cd docs ; make html linkcheck ; cd ..
|
||||
|
||||
after_success:
|
||||
- codecov
|
|
@ -0,0 +1,4 @@
|
|||
0.1.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Nothing as yet.
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2019 the .Net Foundation
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the WorldWide Telescope project nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,19 @@
|
|||
include LICENSE.rst
|
||||
include README.rst
|
||||
include CHANGES.rst
|
||||
|
||||
include setupbase.py
|
||||
include pytest.ini
|
||||
include .coveragerc
|
||||
|
||||
graft docs
|
||||
prune docs/build
|
||||
prune docs/gh-pages
|
||||
prune docs/dist
|
||||
|
||||
global-exclude *~
|
||||
global-exclude *.pyc
|
||||
global-exclude *.pyo
|
||||
global-exclude .git
|
||||
global-exclude __pycache__
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
.. image:: https://travis-ci.org/WorldWideTelescope/wwt_api_client.svg?branch=tests
|
||||
:target: https://travis-ci.org/WorldWideTelescope/wwt_api_client
|
||||
|
||||
.. image:: https://readthedocs.org/projects/wwt_api_client/badge/?version=latest
|
||||
:target: http://wwt_api_client.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
|
||||
Accessing the AAS WorldWide Telescope Web Service from Python
|
||||
=============================================================
|
||||
|
||||
The wwt_api_client package provides a Python interface to the various web
|
||||
services that power the `AAS <https://aas.org/>`_ `WorldWide Telescope
|
||||
<http://www.worldwidetelescope.org/>`_ project.
|
||||
|
||||
The documentation, including installation instructions, can be found at
|
||||
http://wwt_api_client.readthedocs.io/
|
||||
|
||||
|
||||
Reporting issues
|
||||
----------------
|
||||
|
||||
If you run into any issues, please open an issue `here
|
||||
<https://github.com/WorldWideTelescope/wwt_api_client/issues>`_
|
||||
|
||||
|
||||
Acknowledgments
|
||||
---------------
|
||||
|
||||
This work is funded through the American Astronomical Society’s support of the
|
||||
WorldWide Telescope project.
|
|
@ -0,0 +1,47 @@
|
|||
Releasing
|
||||
=========
|
||||
|
||||
(Copied from ``pywwt``.)
|
||||
|
||||
To do a release, first edit the ``CHANGES.rst`` file to include the date of
|
||||
the release after the version number, and make sure the changelog is up to
|
||||
date.
|
||||
|
||||
Then edit the following files to update the version numbers:
|
||||
|
||||
* ``docs/conf.py``
|
||||
* ``wwt_api_client/_version.py`` (make sure the string in the tuple is set to ``final``)
|
||||
|
||||
At this point, commit all changes and use the following for the commit
|
||||
message::
|
||||
|
||||
Preparing release v<version>
|
||||
|
||||
Now make sure there are no temporary files in the repository::
|
||||
|
||||
git clean -fxd
|
||||
|
||||
and build the release files::
|
||||
|
||||
python setup.py sdist bdist_wheel --universal
|
||||
|
||||
Go inside the ``dist`` directory, and you should see a tar file and a wheel.
|
||||
At this point, if you wish, you can untar the tar file and try installing and
|
||||
testing the installation. Once you are satisfied that the release is good you
|
||||
can upload the release using twine::
|
||||
|
||||
twine upload wwt_api_client-<version>.tar.gz wwt_api_client-<version>-py2.py3-none-any.whl
|
||||
|
||||
If you don't have twine installed, you can get it with ``pip install twine``.
|
||||
|
||||
At this point, you can tag the release with::
|
||||
|
||||
git tag -m v<version> v<version>
|
||||
|
||||
If you have PGP keys set up, you can sign the tag by also including ``-s``.
|
||||
|
||||
Now change the versions in the files listed above to the next version — and
|
||||
for the ``wwt_api_client/_version.py`` file, change ``final`` to ``dev``.
|
||||
Commit the changes with::
|
||||
|
||||
Back to development: v<next_version>
|
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS = -W
|
||||
SPHINXBUILD = python -msphinx
|
||||
SPHINXPROJ = wwt_api_client
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -0,0 +1,6 @@
|
|||
API Documentation
|
||||
=================
|
||||
|
||||
.. automodapi:: wwt_api_client
|
||||
:no-inheritance-diagram:
|
||||
:no-inherited-members:
|
|
@ -0,0 +1,191 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# wwt_api_client documentation build configuration file, copied from pywwt.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.autodoc',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx_automodapi.automodapi',
|
||||
'sphinx_automodapi.smart_resolver',
|
||||
'numpydoc']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'wwt_api_client'
|
||||
author = 'Peter K. G. Williams'
|
||||
copyright = '2019 ' + author
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1.0dev0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# This is required for the alabaster theme
|
||||
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
|
||||
html_sidebars = {
|
||||
'**': [
|
||||
'about.html',
|
||||
'navigation.html',
|
||||
'relations.html', # needs 'show_related': True theme option to display
|
||||
'searchbox.html',
|
||||
'donate.html',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'wwt_api_clientdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'wwt_api_client.tex', 'wwt_api_client Documentation',
|
||||
'Thomas P. Robitaille', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'wwt_api_client', 'wwt_api_client Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'wwt_api_client', 'wwt_api_client Documentation',
|
||||
author, 'wwt_api_client', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
||||
# Configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {
|
||||
'python': ('https://docs.python.org/3/',
|
||||
(None, 'http://data.astropy.org/intersphinx/python3.inv')),
|
||||
}
|
||||
numpydoc_show_class_members = False
|
||||
|
||||
nitpicky = True
|
||||
nitpick_ignore = [('py:class', 'ipywidgets.widgets.domwidget.DOMWidget')]
|
||||
|
||||
default_role = 'obj'
|
||||
|
||||
html_logo = 'images/logo.png'
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 266 KiB |
|
@ -0,0 +1,34 @@
|
|||
wwt_api_client: Pythonic access to the WorldWide Telescope web services
|
||||
=======================================================================
|
||||
|
||||
The AAS `WorldWide Telescope <http://worldwidetelescope.org/home>`_ is a free
|
||||
and powerful visualization engine developed by the `American Astronomical
|
||||
Society <https://aas.org/>`_ that can display astronomical and planetary data.
|
||||
This engine is powered by a large (multi-terabyte) collection of astronomical
|
||||
survey data stored in the cloud. The ``wwt_api_client`` package allows you to
|
||||
invoke the web APIs that constitute the WWT backend API.
|
||||
|
||||
|
||||
User guide
|
||||
----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
installation
|
||||
api
|
||||
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
If you run into any issues when using ``wwt_api_client``, please open an issue
|
||||
`on its GitHub repository
|
||||
<https://github.com/WorldWideTelescope/wwt_api_client/issues>`_.
|
||||
|
||||
|
||||
Acknowledgments
|
||||
---------------
|
||||
|
||||
Work on ``wwt_api_client`` is funded through the American Astronomical
|
||||
Society’s support of the WorldWide Telescope project.
|
|
@ -0,0 +1,30 @@
|
|||
Installation
|
||||
============
|
||||
|
||||
Try without installing
|
||||
----------------------
|
||||
|
||||
Not yet implemented.
|
||||
|
||||
Installing wwt_api_client with conda (recommended)
|
||||
-----------------------------------------
|
||||
|
||||
Not yet implemented.
|
||||
|
||||
Installing wwt_api_client with pip
|
||||
-------------------------
|
||||
|
||||
You can also install the latest release of wwt_api_client using `pip
|
||||
<https://pip.pypa.io/en/stable/>`_::
|
||||
|
||||
pip install wwt_api_client
|
||||
|
||||
Installing the developer version
|
||||
--------------------------------
|
||||
|
||||
If you want to use the very latest developer version, you can clone this
|
||||
repository and install the package manually::
|
||||
|
||||
git clone https://github.com/WorldWideTelescope/wwt_api_client.git
|
||||
cd wwt_api_client
|
||||
pip install -e .
|
|
@ -0,0 +1,2 @@
|
|||
[pytest]
|
||||
addopts=-p no:logging
|
|
@ -0,0 +1,10 @@
|
|||
build:
|
||||
image: latest
|
||||
|
||||
python:
|
||||
version: 3.7
|
||||
pip_install: true
|
||||
extra_requirements: ['docs']
|
||||
|
||||
# Don't build any extra formats
|
||||
formats: []
|
|
@ -0,0 +1,5 @@
|
|||
[bdist_wheel]
|
||||
universal=1
|
||||
|
||||
[metadata]
|
||||
description-file = README.rst
|
|
@ -0,0 +1,66 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- mode: python; coding: utf-8 -*-
|
||||
# Copyright 2019 the .Net Foundation
|
||||
# Distributed under the terms of the revised (3-clause) BSD license.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from os.path import join as pjoin
|
||||
from setuptools import setup
|
||||
|
||||
from setupbase import find_packages, get_version
|
||||
|
||||
name = 'wwt_api_client'
|
||||
version = get_version(pjoin(name, '_version.py'))
|
||||
|
||||
with open('README.rst') as f:
|
||||
LONG_DESCRIPTION = f.read()
|
||||
|
||||
setup_args = dict(
|
||||
name = name,
|
||||
description = 'An API client for the AAS WorldWide Telescope web services',
|
||||
long_description = LONG_DESCRIPTION,
|
||||
version = version,
|
||||
packages = find_packages(),
|
||||
author = 'Peter K. G. Williams',
|
||||
author_email = 'peter@newton.cx',
|
||||
url = 'https://github.com/WorldWideTelescope/wwt_api_client',
|
||||
license = 'BSD',
|
||||
platforms = "Linux, Mac OS X, Windows",
|
||||
keywords = ['Science'],
|
||||
classifiers = [
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Science/Research',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Topic :: Multimedia :: Graphics',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
],
|
||||
include_package_data = True,
|
||||
install_requires = [
|
||||
'six'
|
||||
],
|
||||
extras_require = {
|
||||
'test': [
|
||||
'pytest',
|
||||
'pytest-cov',
|
||||
],
|
||||
'docs': [
|
||||
'sphinx>=1.6',
|
||||
'sphinx-automodapi',
|
||||
'numpydoc',
|
||||
'sphinx_rtd_theme',
|
||||
],
|
||||
},
|
||||
entry_points = {
|
||||
},
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
setup(**setup_args)
|
|
@ -0,0 +1,702 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- mode: python; coding: utf-8 -*-
|
||||
# Copyright (c) Jupyter Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
"""This file originates from the 'jupyter-packaging' package. We borrowed it
|
||||
from pywwt. We only use a couple of simple functions and could probably just
|
||||
as well skip it.
|
||||
|
||||
"""
|
||||
from collections import defaultdict
|
||||
from os.path import join as pjoin
|
||||
import io
|
||||
import os
|
||||
import functools
|
||||
import pipes
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
|
||||
# update it when the contents of directories change.
|
||||
if os.path.exists('MANIFEST'): os.remove('MANIFEST')
|
||||
|
||||
|
||||
from distutils.cmd import Command
|
||||
from distutils.command.build_py import build_py
|
||||
from distutils.command.sdist import sdist
|
||||
from distutils import log
|
||||
|
||||
from setuptools.command.develop import develop
|
||||
from setuptools.command.bdist_egg import bdist_egg
|
||||
|
||||
try:
|
||||
from wheel.bdist_wheel import bdist_wheel
|
||||
except ImportError:
|
||||
bdist_wheel = None
|
||||
|
||||
if sys.platform == 'win32':
|
||||
from subprocess import list2cmdline
|
||||
else:
|
||||
def list2cmdline(cmd_list):
|
||||
return ' '.join(map(pipes.quote, cmd_list))
|
||||
|
||||
|
||||
__version__ = '0.2.0'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Top Level Variables
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||
is_repo = os.path.exists(pjoin(HERE, '.git'))
|
||||
node_modules = pjoin(HERE, 'node_modules')
|
||||
|
||||
SEPARATORS = os.sep if os.altsep is None else os.sep + os.altsep
|
||||
|
||||
npm_path = ':'.join([
|
||||
pjoin(HERE, 'node_modules', '.bin'),
|
||||
os.environ.get('PATH', os.defpath),
|
||||
])
|
||||
|
||||
if "--skip-npm" in sys.argv:
|
||||
print("Skipping npm install as requested.")
|
||||
skip_npm = True
|
||||
sys.argv.remove("--skip-npm")
|
||||
else:
|
||||
skip_npm = False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Public Functions
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def get_version(file, name='__version__'):
|
||||
"""Get the version of the package from the given file by
|
||||
executing it and extracting the given `name`.
|
||||
"""
|
||||
path = os.path.realpath(file)
|
||||
version_ns = {}
|
||||
with io.open(path, encoding="utf8") as f:
|
||||
exec(f.read(), {}, version_ns)
|
||||
return version_ns[name]
|
||||
|
||||
|
||||
def ensure_python(specs):
|
||||
"""Given a list of range specifiers for python, ensure compatibility.
|
||||
"""
|
||||
if not isinstance(specs, (list, tuple)):
|
||||
specs = [specs]
|
||||
v = sys.version_info
|
||||
part = '%s.%s' % (v.major, v.minor)
|
||||
for spec in specs:
|
||||
if part == spec:
|
||||
return
|
||||
try:
|
||||
if eval(part + spec):
|
||||
return
|
||||
except SyntaxError:
|
||||
pass
|
||||
raise ValueError('Python version %s unsupported' % part)
|
||||
|
||||
|
||||
def find_packages(top=HERE):
|
||||
"""
|
||||
Find all of the packages.
|
||||
"""
|
||||
packages = []
|
||||
for d, dirs, _ in os.walk(top, followlinks=True):
|
||||
if os.path.exists(pjoin(d, '__init__.py')):
|
||||
packages.append(os.path.relpath(d, top).replace(os.path.sep, '.'))
|
||||
elif d != top:
|
||||
# Do not look for packages in subfolders if current is not a package
|
||||
dirs[:] = []
|
||||
return packages
|
||||
|
||||
|
||||
def update_package_data(distribution):
|
||||
"""update build_py options to get package_data changes"""
|
||||
build_py = distribution.get_command_obj('build_py')
|
||||
build_py.finalize_options()
|
||||
|
||||
|
||||
class bdist_egg_disabled(bdist_egg):
|
||||
"""Disabled version of bdist_egg
|
||||
|
||||
Prevents setup.py install performing setuptools' default easy_install,
|
||||
which it should never ever do.
|
||||
"""
|
||||
def run(self):
|
||||
sys.exit("Aborting implicit building of eggs. Use `pip install .` "
|
||||
" to install from source.")
|
||||
|
||||
|
||||
def create_cmdclass(prerelease_cmd=None, package_data_spec=None,
|
||||
data_files_spec=None):
|
||||
"""Create a command class with the given optional prerelease class.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
prerelease_cmd: (name, Command) tuple, optional
|
||||
The command to run before releasing.
|
||||
package_data_spec: dict, optional
|
||||
A dictionary whose keys are the dotted package names and
|
||||
whose values are a list of glob patterns.
|
||||
data_files_spec: list, optional
|
||||
A list of (path, dname, pattern) tuples where the path is the
|
||||
`data_files` install path, dname is the source directory, and the
|
||||
pattern is a glob pattern.
|
||||
|
||||
Notes
|
||||
-----
|
||||
We use specs so that we can find the files *after* the build
|
||||
command has run.
|
||||
|
||||
The package data glob patterns should be relative paths from the package
|
||||
folder containing the __init__.py file, which is given as the package
|
||||
name.
|
||||
e.g. `dict(foo=['./bar/*', './baz/**'])`
|
||||
|
||||
The data files directories should be absolute paths or relative paths
|
||||
from the root directory of the repository. Data files are specified
|
||||
differently from `package_data` because we need a separate path entry
|
||||
for each nested folder in `data_files`, and this makes it easier to
|
||||
parse.
|
||||
e.g. `('share/foo/bar', 'pkgname/bizz, '*')`
|
||||
"""
|
||||
wrapped = [prerelease_cmd] if prerelease_cmd else []
|
||||
if package_data_spec or data_files_spec:
|
||||
wrapped.append('handle_files')
|
||||
wrapper = functools.partial(_wrap_command, wrapped)
|
||||
handle_files = _get_file_handler(package_data_spec, data_files_spec)
|
||||
|
||||
if 'bdist_egg' in sys.argv:
|
||||
egg = wrapper(bdist_egg, strict=True)
|
||||
else:
|
||||
egg = bdist_egg_disabled
|
||||
|
||||
cmdclass = dict(
|
||||
build_py=wrapper(build_py, strict=is_repo),
|
||||
bdist_egg=egg,
|
||||
sdist=wrapper(sdist, strict=True),
|
||||
handle_files=handle_files,
|
||||
)
|
||||
|
||||
if bdist_wheel:
|
||||
cmdclass['bdist_wheel'] = wrapper(bdist_wheel, strict=True)
|
||||
|
||||
cmdclass['develop'] = wrapper(develop, strict=True)
|
||||
return cmdclass
|
||||
|
||||
|
||||
def command_for_func(func):
|
||||
"""Create a command that calls the given function."""
|
||||
|
||||
class FuncCommand(BaseCommand):
|
||||
|
||||
def run(self):
|
||||
func()
|
||||
update_package_data(self.distribution)
|
||||
|
||||
return FuncCommand
|
||||
|
||||
|
||||
def run(cmd, **kwargs):
|
||||
"""Echo a command before running it. Defaults to repo as cwd"""
|
||||
log.info('> ' + list2cmdline(cmd))
|
||||
kwargs.setdefault('cwd', HERE)
|
||||
kwargs.setdefault('shell', os.name == 'nt')
|
||||
if not isinstance(cmd, (list, tuple)) and os.name != 'nt':
|
||||
cmd = shlex.split(cmd)
|
||||
cmd[0] = which(cmd[0])
|
||||
return subprocess.check_call(cmd, **kwargs)
|
||||
|
||||
|
||||
def is_stale(target, source):
|
||||
"""Test whether the target file/directory is stale based on the source
|
||||
file/directory.
|
||||
"""
|
||||
if not os.path.exists(target):
|
||||
return True
|
||||
target_mtime = recursive_mtime(target) or 0
|
||||
return compare_recursive_mtime(source, cutoff=target_mtime)
|
||||
|
||||
|
||||
class BaseCommand(Command):
|
||||
"""Empty command because Command needs subclasses to override too much"""
|
||||
user_options = []
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def get_inputs(self):
|
||||
return []
|
||||
|
||||
def get_outputs(self):
|
||||
return []
|
||||
|
||||
|
||||
def combine_commands(*commands):
|
||||
"""Return a Command that combines several commands."""
|
||||
|
||||
class CombinedCommand(Command):
|
||||
user_options = []
|
||||
|
||||
def initialize_options(self):
|
||||
self.commands = []
|
||||
for C in commands:
|
||||
self.commands.append(C(self.distribution))
|
||||
for c in self.commands:
|
||||
c.initialize_options()
|
||||
|
||||
def finalize_options(self):
|
||||
for c in self.commands:
|
||||
c.finalize_options()
|
||||
|
||||
def run(self):
|
||||
for c in self.commands:
|
||||
c.run()
|
||||
return CombinedCommand
|
||||
|
||||
|
||||
def compare_recursive_mtime(path, cutoff, newest=True):
|
||||
"""Compare the newest/oldest mtime for all files in a directory.
|
||||
|
||||
Cutoff should be another mtime to be compared against. If an mtime that is
|
||||
newer/older than the cutoff is found it will return True.
|
||||
E.g. if newest=True, and a file in path is newer than the cutoff, it will
|
||||
return True.
|
||||
"""
|
||||
if os.path.isfile(path):
|
||||
mt = mtime(path)
|
||||
if newest:
|
||||
if mt > cutoff:
|
||||
return True
|
||||
elif mt < cutoff:
|
||||
return True
|
||||
for dirname, _, filenames in os.walk(path, topdown=False):
|
||||
for filename in filenames:
|
||||
mt = mtime(pjoin(dirname, filename))
|
||||
if newest: # Put outside of loop?
|
||||
if mt > cutoff:
|
||||
return True
|
||||
elif mt < cutoff:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def recursive_mtime(path, newest=True):
|
||||
"""Gets the newest/oldest mtime for all files in a directory."""
|
||||
if os.path.isfile(path):
|
||||
return mtime(path)
|
||||
current_extreme = None
|
||||
for dirname, dirnames, filenames in os.walk(path, topdown=False):
|
||||
for filename in filenames:
|
||||
mt = mtime(pjoin(dirname, filename))
|
||||
if newest: # Put outside of loop?
|
||||
if mt >= (current_extreme or mt):
|
||||
current_extreme = mt
|
||||
elif mt <= (current_extreme or mt):
|
||||
current_extreme = mt
|
||||
return current_extreme
|
||||
|
||||
|
||||
def mtime(path):
|
||||
"""shorthand for mtime"""
|
||||
return os.stat(path).st_mtime
|
||||
|
||||
|
||||
def install_npm(path=None, build_dir=None, source_dir=None, build_cmd='build', force=False, npm=None):
|
||||
"""Return a Command for managing an npm installation.
|
||||
|
||||
Note: The command is skipped if the `--skip-npm` flag is used.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path: str, optional
|
||||
The base path of the node package. Defaults to the repo root.
|
||||
build_dir: str, optional
|
||||
The target build directory. If this and source_dir are given,
|
||||
the JavaScript will only be build if necessary.
|
||||
source_dir: str, optional
|
||||
The source code directory.
|
||||
build_cmd: str, optional
|
||||
The npm command to build assets to the build_dir.
|
||||
npm: str or list, optional.
|
||||
The npm executable name, or a tuple of ['node', executable].
|
||||
"""
|
||||
|
||||
class NPM(BaseCommand):
|
||||
description = 'install package.json dependencies using npm'
|
||||
|
||||
def run(self):
|
||||
if skip_npm:
|
||||
log.info('Skipping npm-installation')
|
||||
return
|
||||
node_package = path or HERE
|
||||
node_modules = pjoin(node_package, 'node_modules')
|
||||
is_yarn = os.path.exists(pjoin(node_package, 'yarn.lock'))
|
||||
|
||||
npm_cmd = npm
|
||||
|
||||
if npm is None:
|
||||
if is_yarn:
|
||||
npm_cmd = ['yarn']
|
||||
else:
|
||||
npm_cmd = ['npm']
|
||||
|
||||
if not which(npm_cmd[0]):
|
||||
log.error("`{0}` unavailable. If you're running this command "
|
||||
"using sudo, make sure `{0}` is availble to sudo"
|
||||
.format(npm_cmd[0]))
|
||||
return
|
||||
|
||||
if force or is_stale(node_modules, pjoin(node_package, 'package.json')):
|
||||
log.info('Installing build dependencies with npm. This may '
|
||||
'take a while...')
|
||||
run(npm_cmd + ['install'], cwd=node_package)
|
||||
if build_dir and source_dir and not force:
|
||||
should_build = is_stale(build_dir, source_dir)
|
||||
else:
|
||||
should_build = True
|
||||
if should_build:
|
||||
run(npm_cmd + ['run', build_cmd], cwd=node_package)
|
||||
|
||||
return NPM
|
||||
|
||||
|
||||
def ensure_targets(targets):
|
||||
"""Return a Command that checks that certain files exist.
|
||||
|
||||
Raises a ValueError if any of the files are missing.
|
||||
|
||||
Note: The check is skipped if the `--skip-npm` flag is used.
|
||||
"""
|
||||
|
||||
class TargetsCheck(BaseCommand):
|
||||
def run(self):
|
||||
if skip_npm:
|
||||
log.info('Skipping target checks')
|
||||
return
|
||||
missing = [t for t in targets if not os.path.exists(t)]
|
||||
if missing:
|
||||
raise ValueError(('missing files: %s' % missing))
|
||||
|
||||
return TargetsCheck
|
||||
|
||||
|
||||
# `shutils.which` function copied verbatim from the Python-3.3 source.
|
||||
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
||||
"""Given a command, mode, and a PATH string, return the path which
|
||||
conforms to the given mode on the PATH, or None if there is no such
|
||||
file.
|
||||
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
|
||||
of os.environ.get("PATH"), or can be overridden with a custom search
|
||||
path.
|
||||
"""
|
||||
|
||||
# Check that a given file can be accessed with the correct mode.
|
||||
# Additionally check that `file` is not a directory, as on Windows
|
||||
# directories pass the os.access check.
|
||||
def _access_check(fn, mode):
|
||||
return (os.path.exists(fn) and os.access(fn, mode) and
|
||||
not os.path.isdir(fn))
|
||||
|
||||
# Short circuit. If we're given a full path which matches the mode
|
||||
# and it exists, we're done here.
|
||||
if _access_check(cmd, mode):
|
||||
return cmd
|
||||
|
||||
path = (path or os.environ.get("PATH", os.defpath)).split(os.pathsep)
|
||||
|
||||
if sys.platform == "win32":
|
||||
# The current directory takes precedence on Windows.
|
||||
if os.curdir not in path:
|
||||
path.insert(0, os.curdir)
|
||||
|
||||
# PATHEXT is necessary to check on Windows.
|
||||
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
|
||||
# See if the given file matches any of the expected path extensions.
|
||||
# This will allow us to short circuit when given "python.exe".
|
||||
matches = [cmd for ext in pathext if cmd.lower().endswith(ext.lower())]
|
||||
# If it does match, only test that one, otherwise we have to try
|
||||
# others.
|
||||
files = [cmd] if matches else [cmd + ext.lower() for ext in pathext]
|
||||
else:
|
||||
# On other platforms you don't have things like PATHEXT to tell you
|
||||
# what file suffixes are executable, so just pass on cmd as-is.
|
||||
files = [cmd]
|
||||
|
||||
seen = set()
|
||||
for dir in path:
|
||||
dir = os.path.normcase(dir)
|
||||
if dir not in seen:
|
||||
seen.add(dir)
|
||||
for thefile in files:
|
||||
name = os.path.join(dir, thefile)
|
||||
if _access_check(name, mode):
|
||||
return name
|
||||
return None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Private Functions
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _wrap_command(cmds, cls, strict=True):
|
||||
"""Wrap a setup command
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cmds: list(str)
|
||||
The names of the other commands to run prior to the command.
|
||||
strict: boolean, optional
|
||||
Wether to raise errors when a pre-command fails.
|
||||
"""
|
||||
class WrappedCommand(cls):
|
||||
|
||||
def run(self):
|
||||
if not getattr(self, 'uninstall', None):
|
||||
try:
|
||||
[self.run_command(cmd) for cmd in cmds]
|
||||
except Exception:
|
||||
if strict:
|
||||
raise
|
||||
else:
|
||||
pass
|
||||
# update package data
|
||||
update_package_data(self.distribution)
|
||||
|
||||
result = cls.run(self)
|
||||
return result
|
||||
return WrappedCommand
|
||||
|
||||
|
||||
def _get_file_handler(package_data_spec, data_files_spec):
|
||||
"""Get a package_data and data_files handler command.
|
||||
"""
|
||||
class FileHandler(BaseCommand):
|
||||
|
||||
def run(self):
|
||||
package_data = self.distribution.package_data
|
||||
package_spec = package_data_spec or dict()
|
||||
|
||||
for (key, patterns) in package_spec.items():
|
||||
package_data[key] = _get_package_data(key, patterns)
|
||||
|
||||
self.distribution.data_files = _get_data_files(
|
||||
data_files_spec, self.distribution.data_files
|
||||
)
|
||||
|
||||
return FileHandler
|
||||
|
||||
|
||||
def _get_data_files(data_specs, existing):
|
||||
"""Expand data file specs into valid data files metadata.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data_specs: list of tuples
|
||||
See [createcmdclass] for description.
|
||||
existing: list of tuples
|
||||
The existing distrubution data_files metadata.
|
||||
|
||||
Returns
|
||||
-------
|
||||
A valid list of data_files items.
|
||||
"""
|
||||
# Extract the existing data files into a staging object.
|
||||
file_data = defaultdict(list)
|
||||
for (path, files) in existing or []:
|
||||
file_data[path] = files
|
||||
|
||||
# Extract the files and assign them to the proper data
|
||||
# files path.
|
||||
for (path, dname, pattern) in data_specs or []:
|
||||
dname = dname.replace(os.sep, '/')
|
||||
offset = len(dname) + 1
|
||||
|
||||
files = _get_files(pjoin(dname, pattern))
|
||||
for fname in files:
|
||||
# Normalize the path.
|
||||
root = os.path.dirname(fname)
|
||||
full_path = '/'.join([path, root[offset:]])
|
||||
if full_path.endswith('/'):
|
||||
full_path = full_path[:-1]
|
||||
file_data[full_path].append(fname)
|
||||
|
||||
# Construct the data files spec.
|
||||
data_files = []
|
||||
for (path, files) in file_data.items():
|
||||
data_files.append((path, files))
|
||||
return data_files
|
||||
|
||||
|
||||
def _get_files(file_patterns, top=HERE):
|
||||
"""Expand file patterns to a list of paths.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
file_patterns: list or str
|
||||
A list of glob patterns for the data file locations.
|
||||
The globs can be recursive if they include a `**`.
|
||||
They should be relative paths from the top directory or
|
||||
absolute paths.
|
||||
top: str
|
||||
the directory to consider for data files
|
||||
|
||||
Note:
|
||||
Files in `node_modules` are ignored.
|
||||
"""
|
||||
if not isinstance(file_patterns, (list, tuple)):
|
||||
file_patterns = [file_patterns]
|
||||
|
||||
for i, p in enumerate(file_patterns):
|
||||
if os.path.isabs(p):
|
||||
file_patterns[i] = os.path.relpath(p, top)
|
||||
|
||||
matchers = [_compile_pattern(p) for p in file_patterns]
|
||||
|
||||
files = set()
|
||||
|
||||
for root, dirnames, filenames in os.walk(top):
|
||||
# Don't recurse into node_modules
|
||||
if 'node_modules' in dirnames:
|
||||
dirnames.remove('node_modules')
|
||||
for m in matchers:
|
||||
for filename in filenames:
|
||||
fn = os.path.relpath(pjoin(root, filename), top)
|
||||
if m(fn):
|
||||
files.add(fn.replace(os.sep, '/'))
|
||||
|
||||
return list(files)
|
||||
|
||||
|
||||
def _get_package_data(root, file_patterns=None):
|
||||
"""Expand file patterns to a list of `package_data` paths.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
root: str
|
||||
The relative path to the package root from `HERE`.
|
||||
file_patterns: list or str, optional
|
||||
A list of glob patterns for the data file locations.
|
||||
The globs can be recursive if they include a `**`.
|
||||
They should be relative paths from the root or
|
||||
absolute paths. If not given, all files will be used.
|
||||
|
||||
Note:
|
||||
Files in `node_modules` are ignored.
|
||||
"""
|
||||
if file_patterns is None:
|
||||
file_patterns = ['*']
|
||||
return _get_files(file_patterns, pjoin(HERE, root))
|
||||
|
||||
|
||||
def _compile_pattern(pat, ignore_case=True):
|
||||
"""Translate and compile a glob pattern to a regular expression matcher."""
|
||||
if isinstance(pat, bytes):
|
||||
pat_str = pat.decode('ISO-8859-1')
|
||||
res_str = _translate_glob(pat_str)
|
||||
res = res_str.encode('ISO-8859-1')
|
||||
else:
|
||||
res = _translate_glob(pat)
|
||||
flags = re.IGNORECASE if ignore_case else 0
|
||||
return re.compile(res, flags=flags).match
|
||||
|
||||
|
||||
def _iexplode_path(path):
|
||||
"""Iterate over all the parts of a path.
|
||||
|
||||
Splits path recursively with os.path.split().
|
||||
"""
|
||||
(head, tail) = os.path.split(path)
|
||||
if not head or (not tail and head == path):
|
||||
if head:
|
||||
yield head
|
||||
if tail or not head:
|
||||
yield tail
|
||||
return
|
||||
for p in _iexplode_path(head):
|
||||
yield p
|
||||
yield tail
|
||||
|
||||
|
||||
def _translate_glob(pat):
|
||||
"""Translate a glob PATTERN to a regular expression."""
|
||||
translated_parts = []
|
||||
for part in _iexplode_path(pat):
|
||||
translated_parts.append(_translate_glob_part(part))
|
||||
os_sep_class = '[%s]' % re.escape(SEPARATORS)
|
||||
res = _join_translated(translated_parts, os_sep_class)
|
||||
return '{res}\\Z(?ms)'.format(res=res)
|
||||
|
||||
|
||||
def _join_translated(translated_parts, os_sep_class):
|
||||
"""Join translated glob pattern parts.
|
||||
|
||||
This is different from a simple join, as care need to be taken
|
||||
to allow ** to match ZERO or more directories.
|
||||
"""
|
||||
res = ''
|
||||
for part in translated_parts[:-1]:
|
||||
if part == '.*':
|
||||
# drop separator, since it is optional
|
||||
# (** matches ZERO or more dirs)
|
||||
res += part
|
||||
else:
|
||||
res += part + os_sep_class
|
||||
|
||||
if translated_parts[-1] == '.*':
|
||||
# Final part is **
|
||||
res += '.+'
|
||||
# Follow stdlib/git convention of matching all sub files/directories:
|
||||
res += '({os_sep_class}?.*)?'.format(os_sep_class=os_sep_class)
|
||||
else:
|
||||
res += translated_parts[-1]
|
||||
return res
|
||||
|
||||
|
||||
def _translate_glob_part(pat):
|
||||
"""Translate a glob PATTERN PART to a regular expression."""
|
||||
# Code modified from Python 3 standard lib fnmatch:
|
||||
if pat == '**':
|
||||
return '.*'
|
||||
i, n = 0, len(pat)
|
||||
res = []
|
||||
while i < n:
|
||||
c = pat[i]
|
||||
i = i + 1
|
||||
if c == '*':
|
||||
# Match anything but path separators:
|
||||
res.append('[^%s]*' % SEPARATORS)
|
||||
elif c == '?':
|
||||
res.append('[^%s]?' % SEPARATORS)
|
||||
elif c == '[':
|
||||
j = i
|
||||
if j < n and pat[j] == '!':
|
||||
j = j + 1
|
||||
if j < n and pat[j] == ']':
|
||||
j = j + 1
|
||||
while j < n and pat[j] != ']':
|
||||
j = j + 1
|
||||
if j >= n:
|
||||
res.append('\\[')
|
||||
else:
|
||||
stuff = pat[i:j].replace('\\', '\\\\')
|
||||
i = j + 1
|
||||
if stuff[0] == '!':
|
||||
stuff = '^' + stuff[1:]
|
||||
elif stuff[0] == '^':
|
||||
stuff = '\\' + stuff
|
||||
res.append('[%s]' % stuff)
|
||||
else:
|
||||
res.append(re.escape(c))
|
||||
return ''.join(res)
|
|
@ -0,0 +1,5 @@
|
|||
# -*- mode: python; coding: utf-8 -*-
|
||||
# Copyright 2019 the .Net Foundation
|
||||
# Distributed under the terms of the revised (3-clause) BSD license.
|
||||
|
||||
from ._version import version_info, __version__ # noqa
|
|
@ -0,0 +1,9 @@
|
|||
# -*- mode: python; coding: utf-8 -*-
|
||||
# Copyright 2019 the .Net Foundation
|
||||
# Distributed under the terms of the revised (3-clause) BSD license.
|
||||
|
||||
version_info = (0, 1, 0, 'dev', 0)
|
||||
|
||||
_specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': '', 'dev': 'dev'}
|
||||
_ext = '' if version_info[3] == 'final' else _specifier_[version_info[3]] + str(version_info[4])
|
||||
__version__ = '%s.%s.%s%s' % (version_info[0], version_info[1], version_info[2], ext)
|
|
@ -0,0 +1,7 @@
|
|||
# -*- mode: python; coding: utf-8 -*-
|
||||
# Copyright 2019 the .Net Foundation
|
||||
# Distributed under the terms of the revised (3-clause) BSD license.
|
||||
|
||||
"""This module contains tests of the wwt_api_client package.
|
||||
|
||||
"""
|
|
@ -0,0 +1,21 @@
|
|||
[run]
|
||||
source = {packagename}
|
||||
omit =
|
||||
{packagename}/tests/*
|
||||
|
||||
[report]
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
|
||||
# Don't complain about packages we have installed
|
||||
except ImportError
|
||||
|
||||
# Don't complain if tests don't hit assertions
|
||||
raise AssertionError
|
||||
raise NotImplementedError
|
||||
|
||||
# Don't complain about script hooks
|
||||
def main\(.*\):
|
||||
|
||||
# Ignore branches that don't pertain to this version of Python
|
||||
pragma: py{ignore_python_version}
|
|
@ -0,0 +1,10 @@
|
|||
# -*- mode: python; coding: utf-8 -*-
|
||||
# Copyright 2019 the .Net Foundation
|
||||
# Distributed under the terms of the revised (3-clause) BSD license.
|
||||
|
||||
import pytest
|
||||
|
||||
#from ..core import BaseWWTWidget
|
||||
|
||||
def test_something():
|
||||
pass
|
Загрузка…
Ссылка в новой задаче