From e2ec1e8bcdb3541e323079127e204c0cdbd924b5 Mon Sep 17 00:00:00 2001 From: Sylvain Tricot Date: Fri, 27 Mar 2020 17:47:50 +0100 Subject: [PATCH] Documentation is now generated by scons --- .gitignore | 1 + doc/SConstruct | 88 +++++++++++ doc/source/conf.py | 8 +- doc/source/custom.py | 21 +-- doc/source/modules/calcio.rst | 1 - doc/source/sitemap-generate.py | 1 - doc/source/title_template.svg | 219 +++++++++++++++++++++++++++ src/MANIFEST.in | 8 +- SConstruct => src/SConstruct | 11 +- src/msspec/parameters.py | 2 - src/msspec/phagen/fortran/SConstruct | 5 +- src/msspec/spec/fortran/SConstruct | 63 ++++---- src/msspec/version.py | 3 +- src/requirements.txt | 1 + src/setup.py | 159 +++++++++++++------ 15 files changed, 481 insertions(+), 110 deletions(-) create mode 100644 doc/SConstruct create mode 100644 doc/source/title_template.svg rename SConstruct => src/SConstruct (92%) diff --git a/.gitignore b/.gitignore index 1ced045..5f14ae8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ __pycache__ htmlcov package/ src/msspec/results.txt +*venv/ diff --git a/doc/SConstruct b/doc/SConstruct new file mode 100644 index 0000000..ae9adb7 --- /dev/null +++ b/doc/SConstruct @@ -0,0 +1,88 @@ +# SCons file for Sphinx +import sys +sys.path.append('./source') + +import subprocess +from pathlib import Path +from sphinx.cmd.build import main as sphinx_build + +import custom + + +doc = Environment( + # You can set these variables from the command line. + SPHINXOPTS = "", + SPHINXBUILD = "sphinx-build", + PAPER = "", + BUILDDIR = "build") + +# Internal variables. +PAPEROPT_a4 = "-D latex_elements.papersize=a4paper" +#PAPEROPT_a4 = "-D latex_paper_size=a4" +#PAPEROPT_letter = "-D latex_paper_size=letter" +ALLSPHINXOPTS = f"-d {doc['BUILDDIR']}/doctrees {PAPEROPT_a4} {doc['SPHINXOPTS']} source" +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = "{PAPEROPT_a4} {SPHINXOPTS} source" + +# create the banner of the website +banner_src = "./source/title_template.svg" +banner_tgt = "./source/title.svg" +def build_banner(env, target, source): + custom.modify_banner(str(source[0]), str(target[0])) +banner = doc.Command(banner_tgt, banner_src, Action(build_banner, "Creating the website banner...")) +doc.Alias('banner', banner) + +# convert *.svg and *.gif to *.png +# first find all of them +src_dir = Path('./source') +svg_pictures = list(src_dir.glob('**/*.svg')) +gif_pictures = list(src_dir.glob('**/*.gif')) +# conversion +pictures = [] +for f in svg_pictures + banner: + pictures += doc.Command(str(f).replace('.svg', '.png'), str(f), + Action("convert -background none -density 150 $SOURCE $TARGET", + "Converting $SOURCE to PNG...")) + +for f in gif_pictures: + pictures += doc.Command(str(f).replace('.gif', '.png'), str(f), + Action("convert -background none -density 150 $SOURCE[0] $TARGET", + "Converting $SOURCE to PNG...")) +doc.Alias('pictures', pictures) +Depends(pictures, banner) + +# html +def html_builder(env, target, source): + return sphinx_build(f"-b html {ALLSPHINXOPTS} {doc['BUILDDIR']}/html".split()) + +html = doc.Command("html.target", [], Action(html_builder, "Building html...")) +Depends(html, [banner, pictures]) +AlwaysBuild(html) +Clean(html, f"{doc['BUILDDIR']}/html") +doc.Alias('html', html) + +# generate sitemap.xml +t = f"{doc['BUILDDIR']}/html/sitemap.xml" +cmd = f"python source/sitemap-generate.py --url https://msspec.cnrs.fr --path {doc['BUILDDIR']}/html {t}" +sitemap = doc.Command(t, [], cmd)#Action(cmd, "Generating sitemap.xml...")) +Depends(sitemap, html) +doc.Alias('html', sitemap) + +# install ownership +t = f"{doc['BUILDDIR']}/html" +s = Glob('source/google*.html') +ownership = doc.Install(t, s) +Depends(ownership, html) +doc.Alias('html', ownership) + +# LaTeX PDF +def latexpdf_builder(env, target, source): + rc = sphinx_build(f"-b latex {ALLSPHINXOPTS} {doc['BUILDDIR']}/latex".split()) + if rc == 0: + subprocess.call(f"make -C {doc['BUILDDIR']}/latex all-pdf".split()) + +latexpdf = doc.Command("latexpdf.target", [], Action(latexpdf_builder, "Building LaTeX PDF...")) +Depends(latexpdf, [banner, pictures]) +AlwaysBuild(latexpdf) +Clean(latexpdf, f"{doc['BUILDDIR']}/latex") +doc.Alias('latexpdf', latexpdf) diff --git a/doc/source/conf.py b/doc/source/conf.py index 5f931d1..c4e1083 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -18,9 +18,10 @@ import sys, os # 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. sys.path.append(os.path.abspath('./')) -sys.path.append(os.path.abspath('../../src')) +sys.path.append(os.path.abspath('../../src/msspec')) import custom +import msspec @@ -50,7 +51,7 @@ master_doc = 'index' # General information about the project. project = u'MsSpec-python' -copyright = u'2016, Rennes Institute of Physics' +copyright = u'2020, Rennes Institute of Physics' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -59,8 +60,7 @@ copyright = u'2016, Rennes Institute of Physics' # The short X.Y version. version, dev_version = custom.get_package_version() # The full version, including alpha/beta/rc tags. -#release = custom.get_package_version() -release = '{}.post{}'.format(version, dev_version).strip('.post') +release = msspec.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/custom.py b/doc/source/custom.py index 1c32387..ab77900 100644 --- a/doc/source/custom.py +++ b/doc/source/custom.py @@ -8,20 +8,15 @@ import re import numpy as np from lxml import etree -print(os.getcwd()) -sys.path.append('../../src') +import msspec from msspec.calculator import MSSPEC +from msspec.misc import set_log_level +set_log_level("error") def get_package_version(): - p = subprocess.run(["git describe|sed 's/-/.post/'|cut -d'-' -f1"], shell=True, stdout=subprocess.PIPE) - full_version = p.stdout.decode('utf-8').strip() - versions = full_version.split('.post') - version = versions[0] - dev_version = "" - if len(versions) > 1: - dev_version = versions[1] - return version, dev_version + version, *dev_version = msspec.__version__.split('.post') + return version, "".join(dev_version) def generate_download_page(): full_version = '.post'.join(get_package_version()).strip('.post') @@ -42,9 +37,9 @@ click :download:`here <{}>` to download the last version of MsSpec and """.format(setupfile_path, docfile_path) fd.write(content) -def modify_banner(): +def modify_banner(inputfile='./title_template.svg', outputfile='./title.svg'): version, dev_version = get_package_version() - xml = etree.parse('./title.svg') + xml = etree.parse(inputfile) old_content = etree.tostring(xml) svg = xml.getroot() elements = svg.findall(".//{http://www.w3.org/2000/svg}tspan") @@ -61,7 +56,7 @@ def modify_banner(): new_content = etree.tostring(xml).decode('utf-8') if new_content != old_content: - with open('./title.svg', 'w') as fd: + with open(outputfile, 'w') as fd: fd.write(new_content) def generate_parameters(spectroscopy=None): diff --git a/doc/source/modules/calcio.rst b/doc/source/modules/calcio.rst index 0663b46..e53c7e4 100644 --- a/doc/source/modules/calcio.rst +++ b/doc/source/modules/calcio.rst @@ -1,4 +1,3 @@ -.. .. :orphan: .. automodule:: calcio :members: diff --git a/doc/source/sitemap-generate.py b/doc/source/sitemap-generate.py index a3509f3..bf0400b 100644 --- a/doc/source/sitemap-generate.py +++ b/doc/source/sitemap-generate.py @@ -7,7 +7,6 @@ import re from lxml import etree import argparse - opt_defaults = {'include': ".*\.html|.*\.pdf", 'exclude': "google.*\.html", 'timezone': 'Europe/Paris'} diff --git a/doc/source/title_template.svg b/doc/source/title_template.svg new file mode 100644 index 0000000..97bf931 --- /dev/null +++ b/doc/source/title_template.svg @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.6 + 1.6 + + + MsSpec + MsSpec + + A multiple scattering package for spectroscopiesusing electrons to probe materials + post release: 51 + + + + + \ No newline at end of file diff --git a/src/MANIFEST.in b/src/MANIFEST.in index 36f3a5f..1633dfa 100644 --- a/src/MANIFEST.in +++ b/src/MANIFEST.in @@ -1,6 +1,4 @@ -include msspec/spec/fortran/*.so -include msspec/phagen/fortran/*.so -include msspec/results.txt -include VERSION -include README.md +recursive-include msspec *.f +recursive-include msspec *.inc +recursive-include . SConstruct include requirements.txt diff --git a/SConstruct b/src/SConstruct similarity index 92% rename from SConstruct rename to src/SConstruct index 9545e5d..cc630d9 100644 --- a/SConstruct +++ b/src/SConstruct @@ -87,8 +87,15 @@ env['BUILDERS']['F2PY'] = bld # exports +try: + Import('local_build') +except: + local_build = False + Export('env', 'conf') +print('local_build = ', local_build) -SConscript(['src/msspec/spec/fortran/SConstruct', - 'src/msspec/phagen/fortran/SConstruct']) +if not local_build: + SConscript(['msspec/spec/fortran/SConstruct', + 'msspec/phagen/fortran/SConstruct']) diff --git a/src/msspec/parameters.py b/src/msspec/parameters.py index fea0964..2bd96ed 100644 --- a/src/msspec/parameters.py +++ b/src/msspec/parameters.py @@ -248,7 +248,6 @@ class BaseParameters(object): '{}' is not an allowed attribute of {} class. Please use one of:\n{}""".format(key, self.__class__.__name__, data) - print(key, value) LOGGER.error('Unknown attribute!') raise AttributeError(err_msg) object.__setattr__(self, key, value) @@ -1549,7 +1548,6 @@ class CalculationParameters(BaseParameters): assert( p.value in p.allowed_values) else: assert( p.value is None ) - print(iren_map[p.value]) self.spec_parameters.calc_iren = iren_map[p.value] LOGGER.info("Renormalization activated with \'{}\' method".format(p.value)) except AssertionError: diff --git a/src/msspec/phagen/fortran/SConstruct b/src/msspec/phagen/fortran/SConstruct index 7b389d8..5e90901 100644 --- a/src/msspec/phagen/fortran/SConstruct +++ b/src/msspec/phagen/fortran/SConstruct @@ -1,8 +1,9 @@ - try: Import('env') except: - SConscript(['../../../../SConstruct']) + local_build = True + Export('local_build') + SConscript(['../../../SConstruct']) finally: Import('env') diff --git a/src/msspec/spec/fortran/SConstruct b/src/msspec/spec/fortran/SConstruct index 5b0e405..29e09e1 100644 --- a/src/msspec/spec/fortran/SConstruct +++ b/src/msspec/spec/fortran/SConstruct @@ -2,18 +2,21 @@ try: Import('env', 'conf') except: - SConscript(['../../../../SConstruct']) + local_build = True + Export('local_build') + SConscript(['../../../SConstruct']) finally: Import('env', 'conf') # Configuration: +env2 = env.Clone() if conf.CheckPKG('lapack'): - env.ParseConfig("pkg-config lapack --libs") + env2.ParseConfig("pkg-config lapack --libs") conf.Finish() dir = Dir('.').get_abspath() -env.Append(FORTRANFLAGS=['-I' + dir,'-J' + dir]) -env.Append(F2PY_OPTS=['-I' + dir]) +env2.Append(FORTRANFLAGS=['-I' + dir,'-J' + dir]) +env2.Append(F2PY_OPTS=['-I' + dir]) # define sources dim_mod = ['memalloc/dim_mod.f'] @@ -21,19 +24,15 @@ memalloc = ['memalloc/modules.f', 'memalloc/allocation.f'] cluster_gen = Glob('cluster_gen/*.f') common_sub = Glob('common_sub/*.f') renormalization = Glob('renormalization/*.f') -phd_se_noso_nosp_nosym = env.FilteredGlob('phd_se_noso_nosp_nosym/*.f', omit=['main.f']) -phd_mi_noso_nosp_nosym = env.FilteredGlob('phd_mi_noso_nosp_nosym/*.f', omit=['main.f']) +phd_se_noso_nosp_nosym = env2.FilteredGlob('phd_se_noso_nosp_nosym/*.f', omit=['main.f']) +phd_mi_noso_nosp_nosym = env2.FilteredGlob('phd_mi_noso_nosp_nosym/*.f', omit=['main.f']) eig_common = Glob('eig/common/*.f') -eig_mi = env.FilteredGlob('eig/mi/*.f', omit=['main.f']) -eig_pw = env.FilteredGlob('eig/pw/*.f', omit=['main.f']) +eig_mi = env2.FilteredGlob('eig/mi/*.f', omit=['main.f']) +eig_pw = env2.FilteredGlob('eig/pw/*.f', omit=['main.f']) -#for f in eig_mi: -# print(f) -#exit() - -if 'lapack' in env['LIBS']: - env.Append(F2PY_OPTS = "-llapack") +if 'lapack' in env2['LIBS']: + env2.Append(F2PY_OPTS = "-llapack") eig_mi = [f for f in eig_mi if str(f).find('lapack') == -1] phd_mi_noso_nosp_nosym = [f for f in phd_mi_noso_nosp_nosym if str(f).find('lapack') == -1] @@ -41,37 +40,37 @@ sources = dim_mod + memalloc + cluster_gen + common_sub + renormalization + phd sources += phd_mi_noso_nosp_nosym + eig_common + eig_pw + eig_mi # define objects -dim_mod_obj = env.Object(dim_mod) -memalloc_obj = env.Object(memalloc) -cluster_gen_obj = env.Object(cluster_gen) -common_sub_obj = env.Object(common_sub) -renormalization_obj = env.Object(renormalization) -phd_se_noso_nosp_nosym_obj = env.Object(phd_se_noso_nosp_nosym) -phd_mi_noso_nosp_nosym_obj = env.Object(phd_mi_noso_nosp_nosym) -eig_common_obj = env.Object(eig_common) -eig_pw_obj = env.Object(eig_pw) -eig_mi_obj = env.Object(eig_mi) +dim_mod_obj = env2.Object(dim_mod) +memalloc_obj = env2.Object(memalloc) +cluster_gen_obj = env2.Object(cluster_gen) +common_sub_obj = env2.Object(common_sub) +renormalization_obj = env2.Object(renormalization) +phd_se_noso_nosp_nosym_obj = env2.Object(phd_se_noso_nosp_nosym) +phd_mi_noso_nosp_nosym_obj = env2.Object(phd_mi_noso_nosp_nosym) +eig_common_obj = env2.Object(eig_common) +eig_pw_obj = env2.Object(eig_pw) +eig_mi_obj = env2.Object(eig_mi) Requires(memalloc_obj, dim_mod_obj) # define Python extensions common_deps = dim_mod_obj + memalloc_obj + cluster_gen_obj + common_sub_obj deps = common_deps + renormalization_obj + phd_se_noso_nosp_nosym_obj -phd_se_mod = env.F2PY('_phd_se_noso_nosp_nosym', ['phd_se_noso_nosp_nosym/main.f'] + deps) +phd_se_mod = env2.F2PY('_phd_se_noso_nosp_nosym', ['phd_se_noso_nosp_nosym/main.f'] + deps) Requires(phd_se_mod, deps) -env.Alias('phd_se', phd_se_mod) +env2.Alias('phd_se', phd_se_mod) deps = common_deps + renormalization_obj + phd_mi_noso_nosp_nosym_obj -phd_mi_mod = env.F2PY('_phd_mi_noso_nosp_nosym', ['phd_mi_noso_nosp_nosym/main.f'] + deps) +phd_mi_mod = env2.F2PY('_phd_mi_noso_nosp_nosym', ['phd_mi_noso_nosp_nosym/main.f'] + deps) Requires(phd_mi_mod, deps) -env.Alias('phd_mi', phd_mi_mod) +env2.Alias('phd_mi', phd_mi_mod) deps = common_deps + renormalization_obj + eig_common_obj + eig_mi_obj -eig_mi_mod = env.F2PY('_eig_mi', ['eig/mi/main.f'] + deps) +eig_mi_mod = env2.F2PY('_eig_mi', ['eig/mi/main.f'] + deps) Requires(eig_mi_mod, deps) -env.Alias('eig_mi', eig_mi_mod) +env2.Alias('eig_mi', eig_mi_mod) deps = common_deps + renormalization_obj + eig_common_obj + eig_pw_obj -eig_pw_mod = env.F2PY('_eig_pw', ['eig/pw/main.f'] + deps) +eig_pw_mod = env2.F2PY('_eig_pw', ['eig/pw/main.f'] + deps) Requires(eig_pw_mod, deps) -env.Alias('eig_pw', eig_pw_mod) +env2.Alias('eig_pw', eig_pw_mod) diff --git a/src/msspec/version.py b/src/msspec/version.py index 9eb35c6..b00c003 100644 --- a/src/msspec/version.py +++ b/src/msspec/version.py @@ -3,7 +3,6 @@ from setuptools_scm import get_version from pkg_resources import parse_version, DistributionNotFound, get_distribution -from msspec.misc import LOGGER import os # find the version number @@ -27,5 +26,5 @@ except (LookupError, ImportError): try: __version__ = get_distribution(__name__.strip('.version')).version except DistributionNotFound: - LOGGER.error("Unable to get the version number!") + print("Unable to get the version number!") diff --git a/src/requirements.txt b/src/requirements.txt index 1b25442..86a721d 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -8,3 +8,4 @@ pycairo coverage sphinx setuptools_scm +wxPython diff --git a/src/setup.py b/src/setup.py index 2f05c02..de7ccaf 100644 --- a/src/setup.py +++ b/src/setup.py @@ -1,53 +1,120 @@ # coding: utf-8 -# vim: set fdm=indent ts=4 sw=4 sts=4 et tw=80 ai cc=+0 mouse=a nu : # +# vim: set fdm=indent ts=4 sw=4 sts=4 et tw=80 ai cc=+0 mouse=a nu : -from setuptools import setup, find_packages -from msspec.version import __version__ +from setuptools import setup, Extension, find_packages +from distutils.file_util import copy_file +from distutils.command.build import build as _build +from setuptools.command.build_ext import build_ext as _build_ext +from setuptools.command.install import install as _install +from distutils.command.clean import clean as _clean + +import subprocess +import traceback +import os +import sys +sys.path.insert(0, "msspec") + + +from version import __version__ + + +SETUP_REQUIRES = ['scons', 'setuptools_scm'] with open('requirements.txt', 'r') as fd: - requirements = fd.read().strip().split('\n') + REQUIREMENTS = fd.read().strip().split('\n') -setup(name='msspec', - setup_requires=['setuptools_scm'], - version=__version__, - author='Didier Sébilleau, Sylvain Tricot', - author_email='sylvain.tricot@univ-rennes1.fr', - maintainer='Sylvain Tricot', - maintainer_email='sylvain.tricot@univ-rennes1.fr', - url='https://msspec.cnrs.fr', - description=('A multiple scattering package for sepectroscopies using ' - 'electrons to probe materials'), - long_description="""MsSpec is a Fortran package to compute the - cross-section of several spectroscopies involving one (or more) - electron(s) as the probe. This package provides a python interface to - control all the steps of the calculation. +subprocess.call(["pip", "install"] + SETUP_REQUIRES) - Available spectroscopies: - * Photoelectron diffraction - * Auger electron diffraction - * Low energy electron diffraction - * X-Ray absorption spectroscopy - * Auger Photoelectron coincidence spectroscopy - * Computation of the spectral radius""", - download_url='https://msspec.cnrs.fr/downloads.html', - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Environment :: Console', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: GNU General Public License (GPL)', - 'Natural Language :: English', - 'Operating System :: Microsoft :: Windows :: Windows 10', - 'Operating System :: POSIX :: Linux', - 'Operating System :: MacOS :: MacOS X', - 'Programming Language :: Fortran', - 'Programming Language :: Python :: 3 :: Only', - 'Topic :: Scientific/Engineering :: Physics', - ], - keywords='spectroscopy atom electron photon multiple scattering', - license='GPL', - include_package_data=True, - packages=find_packages(include='msspec.*'), - install_requires=requirements - ) +class BuildExtCmd(_build_ext): + def run(self): + src_dir = "." + subprocess.call(['scons']) + for ext in self.extensions: + fullname = self.get_ext_fullname(ext.name) + filename = self.get_ext_filename(fullname) + print("building ", filename) + + src_filename = filename + dest_filename = os.path.join(self.build_lib, filename) + + os.makedirs(os.path.dirname(dest_filename), exist_ok=True) + copy_file(src_filename, dest_filename, verbose=self.verbose, + dry_run=self.dry_run) + + +class BuildCmd(_build): + def run(self): + print("build_lib ", self.build_lib) + self.run_command("build_ext") + _build.run(self) + +class InstallCmd(_install): + def run(self): + self.run_command("build") + _install.run(self) + +class CleanCmd(_clean): + def run(self): + subprocess.call(['scons', '-c']) + _clean.run(self) + + + +if __name__ == "__main__": + module_phagen = Extension('msspec.phagen.fortran.libphagen',['msspec/phagen/fortran/main.f']) + module_spec_phd_mi = Extension('msspec.spec.fortran._phd_mi_noso_nosp_nosym',['msspec/spec/fortran/phd_mi_noso_nosp_nosym/main.f']) + module_spec_phd_se = Extension('msspec.spec.fortran._phd_se_noso_nosp_nosym',['msspec/spec/fortran/phd_se_noso_nosp_nosym/main.f']) + module_eig_mi = Extension('msspec.spec.fortran._eig_mi',['msspec/spec/fortran/eig/mi/main.f']) + module_eig_pw = Extension('msspec.spec.fortran._eig_pw',['msspec/spec/fortran/eig/pw/main.f']) + + setup(name='msspec', + version=__version__, + include_package_data=True, + ext_modules=[module_phagen, module_spec_phd_mi, module_spec_phd_se, module_eig_mi, module_eig_pw], + cmdclass={'build' : BuildCmd, + 'build_ext': BuildExtCmd, + 'clean' : CleanCmd, + 'install' : InstallCmd, + }, + packages=find_packages(include='msspec.*'), + setup_requires=SETUP_REQUIRES, + install_requires=REQUIREMENTS, + + author='Didier Sébilleau, Sylvain Tricot', + author_email='sylvain.tricot@univ-rennes1.fr', + maintainer='Sylvain Tricot', + maintainer_email='sylvain.tricot@univ-rennes1.fr', + url='https://msspec.cnrs.fr', + description=('A multiple scattering package for sepectroscopies using ' + 'electrons to probe materials'), + long_description="""MsSpec is a Fortran package to compute the + cross-section of several spectroscopies involving one (or more) + electron(s) as the probe. This package provides a python interface to + control all the steps of the calculation. + + Available spectroscopies: + * Photoelectron diffraction + * Auger electron diffraction + * Low energy electron diffraction + * X-Ray absorption spectroscopy + * Auger Photoelectron coincidence spectroscopy + * Computation of the spectral radius""", + download_url='https://msspec.cnrs.fr/downloads.html', + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Console', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Natural Language :: English', + 'Operating System :: Microsoft :: Windows :: Windows 10', + 'Operating System :: POSIX :: Linux', + 'Operating System :: MacOS :: MacOS X', + 'Programming Language :: Fortran', + 'Programming Language :: Python :: 3 :: Only', + 'Topic :: Scientific/Engineering :: Physics', + ], + keywords='spectroscopy atom electron photon multiple scattering', + license='GPL', + )