1# Licensed under a 3-clause BSD style license - see LICENSE.rst 2""" 3Astropy is a package intended to contain core functionality and some 4common tools needed for performing astronomy and astrophysics research with 5Python. It also provides an index for other astronomy packages and tools for 6managing them. 7""" 8 9import sys 10import os 11from warnings import warn 12 13from .version import version as __version__ 14 15 16def _is_astropy_source(path=None): 17 """ 18 Returns whether the source for this module is directly in an astropy 19 source distribution or checkout. 20 """ 21 22 # If this __init__.py file is in ./astropy/ then import is within a source 23 # dir .astropy-root is a file distributed with the source, but that should 24 # not installed 25 if path is None: 26 path = os.path.join(os.path.dirname(__file__), os.pardir) 27 elif os.path.isfile(path): 28 path = os.path.dirname(path) 29 30 source_dir = os.path.abspath(path) 31 return os.path.exists(os.path.join(source_dir, '.astropy-root')) 32 33 34# The location of the online documentation for astropy 35# This location will normally point to the current released version of astropy 36if 'dev' in __version__: 37 online_docs_root = 'https://docs.astropy.org/en/latest/' 38else: 39 online_docs_root = f'https://docs.astropy.org/en/{__version__}/' 40 41 42from . import config as _config # noqa: E402 43 44 45class Conf(_config.ConfigNamespace): 46 """ 47 Configuration parameters for `astropy`. 48 """ 49 50 unicode_output = _config.ConfigItem( 51 False, 52 'When True, use Unicode characters when outputting values, and ' 53 'displaying widgets at the console.') 54 use_color = _config.ConfigItem( 55 sys.platform != 'win32', 56 'When True, use ANSI color escape sequences when writing to the console.', 57 aliases=['astropy.utils.console.USE_COLOR', 'astropy.logger.USE_COLOR']) 58 max_lines = _config.ConfigItem( 59 None, 60 description='Maximum number of lines in the display of pretty-printed ' 61 'objects. If not provided, try to determine automatically from the ' 62 'terminal size. Negative numbers mean no limit.', 63 cfgtype='integer(default=None)', 64 aliases=['astropy.table.pprint.max_lines']) 65 max_width = _config.ConfigItem( 66 None, 67 description='Maximum number of characters per line in the display of ' 68 'pretty-printed objects. If not provided, try to determine ' 69 'automatically from the terminal size. Negative numbers mean no ' 70 'limit.', 71 cfgtype='integer(default=None)', 72 aliases=['astropy.table.pprint.max_width']) 73 74 75conf = Conf() 76 77 78# Define a base ScienceState for configuring constants and units 79from .utils.state import ScienceState # noqa: E402 80 81 82class base_constants_version(ScienceState): 83 """ 84 Base class for the real version-setters below 85 """ 86 _value = 'test' 87 88 _versions = dict(test='test') 89 90 @classmethod 91 def validate(cls, value): 92 if value not in cls._versions: 93 raise ValueError(f'Must be one of {list(cls._versions.keys())}') 94 return cls._versions[value] 95 96 @classmethod 97 def set(cls, value): 98 """ 99 Set the current constants value. 100 """ 101 import sys 102 if 'astropy.units' in sys.modules: 103 raise RuntimeError('astropy.units is already imported') 104 if 'astropy.constants' in sys.modules: 105 raise RuntimeError('astropy.constants is already imported') 106 107 return super().set(value) 108 109 110class physical_constants(base_constants_version): 111 """ 112 The version of physical constants to use 113 """ 114 # Maintainers: update when new constants are added 115 _value = 'codata2018' 116 117 _versions = dict(codata2018='codata2018', codata2014='codata2014', 118 codata2010='codata2010', astropyconst40='codata2018', 119 astropyconst20='codata2014', astropyconst13='codata2010') 120 121 122class astronomical_constants(base_constants_version): 123 """ 124 The version of astronomical constants to use 125 """ 126 # Maintainers: update when new constants are added 127 _value = 'iau2015' 128 129 _versions = dict(iau2015='iau2015', iau2012='iau2012', 130 astropyconst40='iau2015', astropyconst20='iau2015', 131 astropyconst13='iau2012') 132 133 134# Create the test() function 135from .tests.runner import TestRunner # noqa: E402 136test = TestRunner.make_test_runner_in(__path__[0]) 137 138 139# if we are *not* in setup mode, import the logger and possibly populate the 140# configuration file with the defaults 141def _initialize_astropy(): 142 try: 143 from .utils import _compiler # noqa: F401 144 except ImportError: 145 if _is_astropy_source(): 146 raise ImportError('You appear to be trying to import astropy from ' 147 'within a source checkout or from an editable ' 148 'installation without building the extension ' 149 'modules first. Either run:\n\n' 150 ' pip install -e .\n\nor\n\n' 151 ' python setup.py build_ext --inplace\n\n' 152 'to make sure the extension modules are built ') 153 else: 154 # Outright broken installation, just raise standard error 155 raise 156 157 158# Set the bibtex entry to the article referenced in CITATION. 159def _get_bibtex(): 160 citation_file = os.path.join(os.path.dirname(__file__), 'CITATION') 161 162 with open(citation_file, 'r') as citation: 163 refs = citation.read().split('@ARTICLE')[1:] 164 if len(refs) == 0: 165 return '' 166 bibtexreference = f'@ARTICLE{refs[0]}' 167 return bibtexreference 168 169 170__citation__ = __bibtex__ = _get_bibtex() 171 172from .logger import _init_log, _teardown_log # noqa: E402, F401 173 174log = _init_log() 175 176_initialize_astropy() 177 178from .utils.misc import find_api_page # noqa: E402, F401 179 180 181def online_help(query): 182 """ 183 Search the online Astropy documentation for the given query. 184 Opens the results in the default web browser. Requires an active 185 Internet connection. 186 187 Parameters 188 ---------- 189 query : str 190 The search query. 191 """ 192 from urllib.parse import urlencode 193 import webbrowser 194 195 version = __version__ 196 if 'dev' in version: 197 version = 'latest' 198 else: 199 version = 'v' + version 200 201 url = f"https://docs.astropy.org/en/{version}/search.html?{urlencode({'q': query})}" 202 webbrowser.open(url) 203 204 205__dir_inc__ = ['__version__', '__githash__', 206 '__bibtex__', 'test', 'log', 'find_api_page', 'online_help', 207 'online_docs_root', 'conf', 'physical_constants', 208 'astronomical_constants'] 209 210 211from types import ModuleType as __module_type__ # noqa: E402 212# Clean up top-level namespace--delete everything that isn't in __dir_inc__ 213# or is a magic attribute, and that isn't a submodule of this package 214for varname in dir(): 215 if not ((varname.startswith('__') and varname.endswith('__')) or 216 varname in __dir_inc__ or 217 (varname[0] != '_' and 218 isinstance(locals()[varname], __module_type__) and 219 locals()[varname].__name__.startswith(__name__ + '.'))): 220 # The last clause in the the above disjunction deserves explanation: 221 # When using relative imports like ``from .. import config``, the 222 # ``config`` variable is automatically created in the namespace of 223 # whatever module ``..`` resolves to (in this case astropy). This 224 # happens a few times just in the module setup above. This allows 225 # the cleanup to keep any public submodules of the astropy package 226 del locals()[varname] 227 228del varname, __module_type__ 229