From fdd6fd2c7701b58926d863c2858e62a65520212d Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 24 May 2022 14:40:04 -0700 Subject: [PATCH 1/6] prepare for release --- .pre-commit-config.yaml | 105 +-- LICENSE | 27 - LICENSE.rst | 2 +- azure-pipelines.yml | 27 +- docs/conf.py | 83 +-- pyproject.toml | 29 +- radiospectra/__init__.py | 9 +- radiospectra/_dev/__init__.py | 1 + radiospectra/_dev/scm_version.py | 6 +- radiospectra/net/__init__.py | 3 +- radiospectra/net/attrs.py | 6 +- radiospectra/net/sources/callisto.py | 51 +- radiospectra/net/sources/eovsa.py | 36 +- radiospectra/net/sources/psp.py | 104 ++- radiospectra/net/sources/rstn.py | 54 +- radiospectra/net/sources/stereo.py | 108 +-- .../net/sources/tests/test_callisto_client.py | 24 +- .../net/sources/tests/test_eovsa_client.py | 21 +- .../net/sources/tests/test_psp_client.py | 85 ++- .../net/sources/tests/test_rstn_client.py | 35 +- .../net/sources/tests/test_stereo_client.py | 53 +- .../net/sources/tests/test_wind_client.py | 53 +- radiospectra/net/sources/wind.py | 85 ++- radiospectra/sources/__init__.py | 2 +- radiospectra/sources/callisto.py | 187 ++--- radiospectra/sources/swaves.py | 40 +- radiospectra/spectrogram.py | 357 +++++----- radiospectra/spectrogram2/__init__.py | 5 +- radiospectra/spectrogram2/sources.py | 60 +- radiospectra/spectrogram2/spectrogram.py | 340 +++++---- .../spectrogram2/tests/test_callisto.py | 279 ++++++-- radiospectra/spectrogram2/tests/test_eovsa.py | 591 +++++++++++++--- .../spectrogram2/tests/test_psp_rfs.py | 254 +++++-- radiospectra/spectrogram2/tests/test_rstn.py | 30 +- .../spectrogram2/tests/test_swaves.py | 109 ++- radiospectra/spectrogram2/tests/test_waves.py | 52 +- radiospectra/spectrum.py | 5 +- radiospectra/tests/setup_package.py | 3 +- radiospectra/tests/test_callisto.py | 148 ++-- radiospectra/tests/test_spectrogram.py | 647 ++++++++++-------- radiospectra/tests/test_util.py | 44 +- radiospectra/util.py | 172 ++--- radiospectra/version.py | 8 +- setup.py | 8 +- tox.ini | 27 +- 45 files changed, 2533 insertions(+), 1842 deletions(-) delete mode 100644 LICENSE diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 82f8820..0f67641 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,95 +1,38 @@ -ci: - autofix_prs: false repos: - # The warnings/errors we check for here are: - # E101 - mix of tabs and spaces - # E11 - Fix indentation. - # E111 - 4 spaces per indentation level - # E112 - 4 spaces per indentation level - # E113 - 4 spaces per indentation level - # E121 - Fix indentation to be a multiple of four. - # E122 - Add absent indentation for hanging indentation. - # E123 - Align closing bracket to match opening bracket. - # E124 - Align closing bracket to match visual indentation. - # E125 - Indent to distinguish line from next logical line. - # E126 - Fix over-indented hanging indentation. - # E127 - Fix visual indentation. - # E128 - Fix visual indentation. - # E129 - Fix visual indentation. - # E131 - Fix hanging indent for unaligned continuation line. - # E133 - Fix missing indentation for closing bracket. - # E20 - Remove extraneous whitespace. - # E211 - Remove extraneous whitespace. - # E231 - Add missing whitespace. - # E241 - Fix extraneous whitespace around keywords. - # E242 - Remove extraneous whitespace around operator. - # E251 - Remove whitespace around parameter '=' sign. - # E252 - Missing whitespace around parameter equals. - # E26 - Fix spacing after comment hash for inline comments. - # E265 - Fix spacing after comment hash for block comments. - # E266 - Fix too many leading '#' for block comments. - # E27 - Fix extraneous whitespace around keywords. - # E301 - Add missing blank line. - # E302 - Add missing 2 blank lines. - # E303 - Remove extra blank lines. - # E304 - Remove blank line following function decorator. - # E305 - expected 2 blank lines after class or function definition - # E305 - Expected 2 blank lines after end of function or class. - # E306 - expected 1 blank line before a nested definition - # E306 - Expected 1 blank line before a nested definition. - # E401 - Put imports on separate lines. - # E402 - Fix module level import not at top of file - # E502 - Remove extraneous escape of newline. - # E701 - Put colon-separated compound statement on separate lines. - # E711 - Fix comparison with None. - # E712 - Fix comparison with boolean. - # E713 - Use 'not in' for test for membership. - # E714 - Use 'is not' test for object identity. - # E722 - Fix bare except. - # E731 - Use a def when use do not assign a lambda expression. - # E901 - SyntaxError or IndentationError - # E902 - IOError - # F822 - undefined name in __all__ - # F823 - local variable name referenced before assignment - # W291 - Remove trailing whitespace. - # W292 - Add a single newline at the end of the file. - # W293 - Remove trailing whitespace on blank line. - # W391 - Remove trailing blank lines. - # W601 - Use "in" rather than "has_key()". - # W602 - Fix deprecated form of raising exception. - # W603 - Use "!=" instead of "<>" - # W604 - Use "repr()" instead of backticks. - # W605 - Fix invalid escape sequence 'x'. - # W690 - Fix various deprecated code (via lib2to3). - - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + - repo: https://github.com/myint/docformatter + rev: v1.4 hooks: - - id: flake8 - args: ['--count', '--select', 'E101,E11,E111,E112,E113,E121,E122,E123,E124,E125,E126,E127,E128,E129,E131,E133,E20,E211,E231,E241,E242,E251,E252,E26,E265,E266,E27,E301,E302,E303,E304,E305,E306,E401,E402,E502,E701,E711,E712,E713,E714,E722,E731,E901,E902,F822,F823,W191,W291,W292,W293,W391,W601,W602,W603,W604,W605,W690'] - exclude: ".*(.fits|.fts|.fit|.txt|tca.*|extern.*|.rst|.md)$" + - id: docformatter + args: [--in-place, --pre-summary-newline, --make-summary-multi] - repo: https://github.com/myint/autoflake rev: v1.4 hooks: - id: autoflake args: ['--in-place', '--remove-all-unused-imports', '--remove-unused-variable'] exclude: ".*(.fits|.fts|.fit|.txt|tca.*|extern.*|.rst|.md|__init__.py|docs/conf.py)$" - - repo: https://github.com/PyCQA/isort - rev: 5.10.1 - hooks: + - repo: https://github.com/psf/black + rev: 22.3.0 + hooks: + - id: black + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + - repo: https://github.com/PyCQA/isort + rev: 5.10.1 + hooks: - id: isort - args: ['--sp','setup.cfg'] - exclude: ".*(.fits|.fts|.fit|.txt|tca.*|extern.*|.rst|.md|docs/conf.py)$" - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 - hooks: + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.2.0 + hooks: - id: check-ast - id: check-case-conflict - id: trailing-whitespace - exclude: ".*(.fits|.fts|.fit|.txt)$" + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + - id: mixed-line-ending + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + - id: end-of-file-fixer + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" - id: check-yaml - id: debug-statements - - id: check-added-large-files - - id: end-of-file-fixer - exclude: ".*(.fits|.fts|.fit|.txt|tca.*)$" - - id: mixed-line-ending - exclude: ".*(.fits|.fts|.fit|.txt|tca.*)$" + +ci: + autofix_prs: false diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 5196656..0000000 --- a/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -BSD 2-Clause License - -Copyright (c) 2018-2019, The SunPy developers -All rights reserved. - -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. - -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. diff --git a/LICENSE.rst b/LICENSE.rst index 138bc16..c98bfd7 100644 --- a/LICENSE.rst +++ b/LICENSE.rst @@ -1,4 +1,4 @@ -Copyright (c) 2018-2021, The SunPy Developers +Copyright (c) 2018-2022, The SunPy Developers Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4c58480..6da43e9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -44,18 +44,15 @@ stages: coverage: codecov toxdeps: tox-pypi-filter posargs: -n=4 - libraries: apt: - libopenjp2-7 - envs: - linux: codestyle name: style_check pytest: false libraries: {} - - - linux: py38 + - linux: py310 - stage: SecondPhaseTests displayName: Stage 2 Tests @@ -68,30 +65,20 @@ stages: coverage: codecov toxdeps: tox-pypi-filter posargs: -n=4 - libraries: apt: - libopenjp2-7 - graphviz brew: - openjpeg - envs: - - macos: py37 - + - macos: py38 - windows: py39 - - linux: build_docs posargs: " " pytest: false - - - linux: py38-online - - - linux: py37-oldestdeps - - - linux: py38-conda - libraries: {} - + - linux: py39-online + - linux: py38-oldestdeps - ${{ if or(eq(variables['Build.Reason'], 'Schedule'), eq(variables['Build.Reason'], 'Manual')) }}: - stage: CronTests @@ -105,13 +92,13 @@ stages: coverage: codecov toxdeps: tox-pypi-filter posargs: -n=4 - libraries: apt: - libopenjp2-7 - envs: - - linux: py38-devdeps + - linux: py310-devdeps + - linux: py39-conda + libraries: {} # On branches which aren't main, and not Pull Requests, build the wheels but only upload them on tags - ${{ if and(ne(variables['Build.Reason'], 'PullRequest'), or(ne(variables['Build.SourceBranchName'], 'main'), eq(variables['Build.Reason'], 'Schedule'), eq(variables['Build.Reason'], 'Manual'))) }}: diff --git a/docs/conf.py b/docs/conf.py index 79a51bf..093ce82 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,6 @@ """ Configuration file for the Sphinx documentation builder. + isort:skip_file """ # flake8: NOQA: E402 @@ -30,32 +31,34 @@ # -- Read the Docs Specific Configuration -------------------------------------- # This needs to be done before sunpy is imported -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" if on_rtd: - os.environ['SUNPY_CONFIGDIR'] = '/home/docs/' - os.environ['HOME'] = '/home/docs/' - os.environ['LANG'] = 'C' - os.environ['LC_ALL'] = 'C' - os.environ['HIDE_PARFIVE_PROGESS'] = 'True' + os.environ["SUNPY_CONFIGDIR"] = "/home/docs/" + os.environ["HOME"] = "/home/docs/" + os.environ["LANG"] = "C" + os.environ["LC_ALL"] = "C" + os.environ["HIDE_PARFIVE_PROGESS"] = "True" # -- Non stdlib imports -------------------------------------------------------- from radiospectra import __version__ # NOQA # -- Project information ------------------------------------------------------- -project = 'radiospectra' -author = 'The SunPy Community' -copyright = '{}, {}'.format(datetime.datetime.now().year, author) +project = "radiospectra" +author = "The SunPy Community" +copyright = "{}, {}".format(datetime.datetime.now().year, author) # The full version, including alpha/beta/rc tags release = __version__ radiospectra_version = Version(__version__) -is_release = not(radiospectra_version.is_prerelease or radiospectra_version.is_devrelease) +is_release = not (radiospectra_version.is_prerelease or radiospectra_version.is_devrelease) # For the linkcheck -linkcheck_ignore = [r"https://doi.org/\d+", - r"https://element.io/\d+", - r"https://github.com/\d+", - r"https://docs.sunpy.org/\d+"] +linkcheck_ignore = [ + r"https://doi.org/\d+", + r"https://element.io/\d+", + r"https://github.com/\d+", + r"https://docs.sunpy.org/\d+", +] linkcheck_anchors = False # This is added to the end of RST files - a good place to put substitutions to @@ -71,25 +74,27 @@ # Suppress warnings about overriding directives as we overload some of the # doctest extensions. -suppress_warnings = ['app.add_directive', ] +suppress_warnings = [ + "app.add_directive", +] # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'matplotlib.sphinxext.plot_directive', - 'sphinx_automodapi.automodapi', - 'sphinx_automodapi.smart_resolver', - 'sphinx_changelog', - 'sphinx.ext.autodoc', - 'sphinx.ext.coverage', - 'sphinx.ext.doctest', - 'sphinx.ext.inheritance_diagram', - 'sphinx.ext.intersphinx', - 'sphinx.ext.mathjax', - 'sphinx.ext.napoleon', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode', + "matplotlib.sphinxext.plot_directive", + "sphinx_automodapi.automodapi", + "sphinx_automodapi.smart_resolver", + "sphinx_changelog", + "sphinx.ext.autodoc", + "sphinx.ext.coverage", + "sphinx.ext.doctest", + "sphinx.ext.inheritance_diagram", + "sphinx.ext.intersphinx", + "sphinx.ext.mathjax", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", ] # Add any paths that contain templates here, relative to this directory. @@ -102,20 +107,20 @@ # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. -html_extra_path = ['robots.txt'] +html_extra_path = ["robots.txt"] -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # The reST default role (used for this markup: `text`) to use for all # documents. Set to the "smart" one. -default_role = 'obj' +default_role = "obj" # Disable having a separate return type row napoleon_use_rtype = False @@ -173,10 +178,10 @@ graphviz_output_format = "svg" graphviz_dot_args = [ - '-Nfontsize=10', - '-Nfontname=Helvetica Neue, Helvetica, Arial, sans-serif', - '-Efontsize=10', - '-Efontname=Helvetica Neue, Helvetica, Arial, sans-serif', - '-Gfontsize=10', - '-Gfontname=Helvetica Neue, Helvetica, Arial, sans-serif' + "-Nfontsize=10", + "-Nfontname=Helvetica Neue, Helvetica, Arial, sans-serif", + "-Efontsize=10", + "-Efontname=Helvetica Neue, Helvetica, Arial, sans-serif", + "-Gfontsize=10", + "-Gfontname=Helvetica Neue, Helvetica, Arial, sans-serif", ] diff --git a/pyproject.toml b/pyproject.toml index 1155469..c7698f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,32 @@ [build-system] requires = [ - "setuptools", - "setuptools_scm", - "wheel", - ] + "setuptools>=56,!=61.0.0", + "setuptools_scm[toml]>=6.2", + "wheel", +] build-backend = 'setuptools.build_meta' +[tool.black] +line-length = 120 +include = '\.pyi?$' +exclude = ''' +( + /( + \.eggs + | \.git + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + | docs + | .history + )/ +) +''' + [ tool.gilesbot ] [ tool.gilesbot.pull_requests ] enabled = true diff --git a/radiospectra/__init__.py b/radiospectra/__init__.py index 0b30c5a..a049695 100644 --- a/radiospectra/__init__.py +++ b/radiospectra/__init__.py @@ -17,12 +17,13 @@ class UnsupportedPythonError(Exception): - """Running on an unsupported version of Python.""" + """ + Running on an unsupported version of Python. + """ -if sys.version_info < tuple(int(val) for val in __minimum_python_version__.split('.')): +if sys.version_info < tuple(int(val) for val in __minimum_python_version__.split(".")): # This has to be .format to keep backwards compatibly. - raise UnsupportedPythonError( - "sunpy does not support Python < {}".format(__minimum_python_version__)) + raise UnsupportedPythonError("sunpy does not support Python < {}".format(__minimum_python_version__)) __all__ = ["__version__"] diff --git a/radiospectra/_dev/__init__.py b/radiospectra/_dev/__init__.py index 72583c0..6415980 100644 --- a/radiospectra/_dev/__init__.py +++ b/radiospectra/_dev/__init__.py @@ -1,6 +1,7 @@ """ This package contains utilities that are only used when developing drms in a copy of the source repository. + These files are not installed, and should not be assumed to exist at runtime. """ diff --git a/radiospectra/_dev/scm_version.py b/radiospectra/_dev/scm_version.py index b33a5ba..b8913a9 100644 --- a/radiospectra/_dev/scm_version.py +++ b/radiospectra/_dev/scm_version.py @@ -5,8 +5,8 @@ try: from setuptools_scm import get_version - version = get_version(root=os.path.join('..', '..'), relative_to=__file__) + version = get_version(root=os.path.join("..", ".."), relative_to=__file__) except ImportError: - raise ImportError('setuptools_scm not installed') + raise ImportError("setuptools_scm not installed") except Exception as e: - raise ValueError(f'setuptools_scm broken with {e}') + raise ValueError(f"setuptools_scm broken with {e}") diff --git a/radiospectra/net/__init__.py b/radiospectra/net/__init__.py index c595da4..b868a50 100644 --- a/radiospectra/net/__init__.py +++ b/radiospectra/net/__init__.py @@ -6,5 +6,4 @@ from radiospectra.net.sources.stereo import SWAVESClient from radiospectra.net.sources.wind import WAVESClient -__all__ = ['CALLISTOClient', 'EOVSAClient', 'RFSClient', 'SWAVESClient', 'RSTNClient', - 'WAVESClient'] +__all__ = ["CALLISTOClient", "EOVSAClient", "RFSClient", "SWAVESClient", "RSTNClient", "WAVESClient"] diff --git a/radiospectra/net/attrs.py b/radiospectra/net/attrs.py index 1568fc1..98e7654 100644 --- a/radiospectra/net/attrs.py +++ b/radiospectra/net/attrs.py @@ -1,6 +1,6 @@ from sunpy.net.attr import SimpleAttr -__all__ = ['Spacecraft', 'Observatory', 'PolType'] +__all__ = ["Spacecraft", "Observatory", "PolType"] class Spacecraft(SimpleAttr): @@ -11,11 +11,11 @@ class Spacecraft(SimpleAttr): class Observatory(SimpleAttr): """ - Observatory + Observatory. """ class PolType(SimpleAttr): """ - Polarisation Type + Polarisation Type. """ diff --git a/radiospectra/net/sources/callisto.py b/radiospectra/net/sources/callisto.py index 370900b..ecd59f0 100644 --- a/radiospectra/net/sources/callisto.py +++ b/radiospectra/net/sources/callisto.py @@ -8,9 +8,10 @@ class CALLISTOClient(GenericClient): """ - Provides access to eCallisto radio spectrometer network - `archive `__ at - `FHNW, `__. + Provides access to eCallisto radio spectrometer network `archive. + + `__ + at `FHNW, `__. For further information `see `-- @@ -38,18 +39,23 @@ class CALLISTOClient(GenericClient): """ - baseurl = r'http://soleil80.cs.technik.fhnw.ch/solarradio/data/2002-20yy_Callisto/' \ - r'%Y/%m/%d/{obs}_%Y%m%d_%H%M%S_(\d){{2}}.fit.gz' - pattern = r'{}/2002-20yy_Callisto/{year:4d}/{month:2d}/{day:2d}/' \ - r'{Observatory}_{year:4d}{month:2d}{day:2d}' \ - r'_{hour:2d}{minute:2d}{second:2d}_{ID:2d}.fit.gz' + + baseurl = ( + r"http://soleil80.cs.technik.fhnw.ch/solarradio/data/2002-20yy_Callisto/" + r"%Y/%m/%d/{obs}_%Y%m%d_%H%M%S_(\d){{2}}.fit.gz" + ) + pattern = ( + r"{}/2002-20yy_Callisto/{year:4d}/{month:2d}/{day:2d}/" + r"{Observatory}_{year:4d}{month:2d}{day:2d}" + r"_{hour:2d}{minute:2d}{second:2d}_{ID:2d}.fit.gz" + ) @classmethod def pre_search_hook(cls, *args, **kwargs): baseurl, pattern, matchdict = super().pre_search_hook(*args, **kwargs) - obs = matchdict.pop('Observatory') - if obs[0] == '*': - baseurl = baseurl.format(obs=r'.*') + obs = matchdict.pop("Observatory") + if obs[0] == "*": + baseurl = baseurl.format(obs=r".*") else: # Need case sensitive so have to override obs_attr = [a for a in args if isinstance(a, Observatory)][0] @@ -59,24 +65,23 @@ def pre_search_hook(cls, *args, **kwargs): def post_search_hook(self, exdict, matchdict): original = super().post_search_hook(exdict, matchdict) # Files are 15 minute duration - original['End Time'] = original['Start Time'] + (15 * u.min - 1 * u.ms) + original["End Time"] = original["Start Time"] + (15 * u.min - 1 * u.ms) return original @classmethod def register_values(cls): adict = { - a.Provider: [('eCALLISTO', 'International Network of Solar Radio Spectrometers.')], - a.Instrument: [('eCALLISTO', - 'e-Callisto - International Network of Solar Radio Spectrometers.')], - Observatory: [('*', 'Observatory Location')]} + a.Provider: [("eCALLISTO", "International Network of Solar Radio Spectrometers.")], + a.Instrument: [("eCALLISTO", "e-Callisto - International Network of Solar Radio Spectrometers.")], + Observatory: [("*", "Observatory Location")], + } return adict @classmethod def _can_handle_query(cls, *query): """ - Method the - `sunpy.net.fido_factory.UnifiedDownloaderFactory` - class uses to dispatch queries to this Client. + Method the `sunpy.net.fido_factory.UnifiedDownloaderFactory` class uses + to dispatch queries to this Client. """ regattrs_dict = cls.register_values() optional = {k for k in regattrs_dict.keys()} - cls.required @@ -85,7 +90,11 @@ class uses to dispatch queries to this Client. for key in regattrs_dict: all_vals = [i[0].lower() for i in regattrs_dict[key]] for x in query: - if (isinstance(x, key) and issubclass(key, SimpleAttr) - and x.type_name != 'observatory' and str(x.value).lower() not in all_vals): + if ( + isinstance(x, key) + and issubclass(key, SimpleAttr) + and x.type_name != "observatory" + and str(x.value).lower() not in all_vals + ): return False return True diff --git a/radiospectra/net/sources/eovsa.py b/radiospectra/net/sources/eovsa.py index 532f842..fc8d85c 100644 --- a/radiospectra/net/sources/eovsa.py +++ b/radiospectra/net/sources/eovsa.py @@ -6,8 +6,9 @@ class EOVSAClient(GenericClient): """ - Client provides access to `Extended Owens Valley Solar Array `__ - (EOVSA) data. + Client provides access to `Extended Owens Valley Solar Array. + + `__ (EOVSA) data. Examples -------- @@ -27,36 +28,29 @@ class EOVSAClient(GenericClient): """ - baseurl = r'http://ovsa.njit.edu/fits/synoptic/%Y/%m/%d/' \ - r'EOVSA_.*_%Y%m%d.fts' - pattern = r'{}/synoptic/{year:4d}/{month:2d}/{day:2d}/' \ - r'EOVSA_{PolType:5l}_{year:4d}{month:2d}{day:2d}.fts' - - pol_map = { - 'Total': 'TPall', - 'Cross': 'XPall', - 'TPall': 'Total', - 'XPall': 'Cross' - } + + baseurl = r"http://ovsa.njit.edu/fits/synoptic/%Y/%m/%d/" r"EOVSA_.*_%Y%m%d.fts" + pattern = r"{}/synoptic/{year:4d}/{month:2d}/{day:2d}/" r"EOVSA_{PolType:5l}_{year:4d}{month:2d}{day:2d}.fts" + + pol_map = {"Total": "TPall", "Cross": "XPall", "TPall": "Total", "XPall": "Cross"} @classmethod def pre_search_hook(cls, *args, **kwargs): baseurl, pattern, matchdict = super().pre_search_hook(*args, **kwargs) - pol_values = [cls.pol_map[p.capitalize()] for p in matchdict['PolType']] - matchdict['PolType'] = pol_values + pol_values = [cls.pol_map[p.capitalize()] for p in matchdict["PolType"]] + matchdict["PolType"] = pol_values return baseurl, pattern, matchdict def post_search_hook(self, exdict, matchdict): original = super().post_search_hook(exdict, matchdict) - original['PolType'] = self.pol_map[original['PolType']] + original["PolType"] = self.pol_map[original["PolType"]] return original @classmethod def register_values(cls): adict = { - a.Provider: [('EOVSA', 'EOVSA')], - a.Instrument: [('EOVSA', - 'ExtendedOwens Valley Solar Array.')], - PolType: [('Total', 'Total polarisation'), - ('Cross', 'Cross polarisation')]} + a.Provider: [("EOVSA", "EOVSA")], + a.Instrument: [("EOVSA", "ExtendedOwens Valley Solar Array.")], + PolType: [("Total", "Total polarisation"), ("Cross", "Cross polarisation")], + } return adict diff --git a/radiospectra/net/sources/psp.py b/radiospectra/net/sources/psp.py index 393309d..050fea1 100644 --- a/radiospectra/net/sources/psp.py +++ b/radiospectra/net/sources/psp.py @@ -4,19 +4,19 @@ from sunpy.time.timerange import TimeRange from sunpy.util.scraper import Scraper -__all__ = ['RFSClient'] +__all__ = ["RFSClient"] RECEIVER_FREQUENCIES = { - 'rfs_lfr': a.Wavelength(10*u.kHz, 1.7*u.MHz), - 'rfs_hfr': a.Wavelength(1.3*u.MHz, 19.2*u.MHz) + "rfs_lfr": a.Wavelength(10 * u.kHz, 1.7 * u.MHz), + "rfs_hfr": a.Wavelength(1.3 * u.MHz, 19.2 * u.MHz), } class RFSClient(GenericClient): """ - Provides access to Parker Solar Probe FIELDS Radio Frequency Spectrometer data - `archive `__ at `NASA Goddard Space Physics - Data Facility (SPDF) `__. + Provides access to Parker Solar Probe FIELDS Radio Frequency Spectrometer + data `archive `__ at `NASA + Goddard Space Physics Data Facility (SPDF) `__. Examples -------- @@ -44,16 +44,17 @@ class RFSClient(GenericClient): """ - baseurl = (r'https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/{Wavelength}/' - r'{year}/psp_fld_l2_(\w){{7}}_(\d){{8}}_v(\d){{2}}.cdf') - pattern = r'{}/{Wavelength}/{year:4d}/' \ - r'psp_fld_l2_{Wavelength}_{year:4d}{month:2d}{day:2d}_v{:2d}.cdf' + baseurl = ( + r"https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/{Wavelength}/" + r"{year}/psp_fld_l2_(\w){{7}}_(\d){{8}}_v(\d){{2}}.cdf" + ) + pattern = r"{}/{Wavelength}/{year:4d}/" r"psp_fld_l2_{Wavelength}_{year:4d}{month:2d}{day:2d}_v{:2d}.cdf" @classmethod def _check_wavelengths(cls, wavelength): """ - Check for overlap between given wavelength and receiver frequency coverage defined in - `RECEIVER_FREQUENCIES`. + Check for overlap between given wavelength and receiver frequency + coverage defined in `RECEIVER_FREQUENCIES`. Parameters ---------- @@ -70,47 +71,44 @@ def _check_wavelengths(cls, wavelength): # If not defined need to continue if not receivers: # Overlaps but not contained in, either max in lfr or min hfr - if wavelength.min in RECEIVER_FREQUENCIES['rfs_hfr'] or \ - wavelength.max in RECEIVER_FREQUENCIES['rfs_hfr']: - receivers.append('rfs_hfr') - if wavelength.min in RECEIVER_FREQUENCIES['rfs_lfr'] or \ - wavelength.max in RECEIVER_FREQUENCIES['rfs_lfr']: - receivers.append('rfs_lfr') + if wavelength.min in RECEIVER_FREQUENCIES["rfs_hfr"] or wavelength.max in RECEIVER_FREQUENCIES["rfs_hfr"]: + receivers.append("rfs_hfr") + if wavelength.min in RECEIVER_FREQUENCIES["rfs_lfr"] or wavelength.max in RECEIVER_FREQUENCIES["rfs_lfr"]: + receivers.append("rfs_lfr") # min in lfr and max in hfr # min and max of combined lft and hfr contained in give wavelength range - if a.Wavelength(RECEIVER_FREQUENCIES['rfs_lfr'].min, - RECEIVER_FREQUENCIES['rfs_hfr'].max) in wavelength: - receivers = ['rfs_lfr', 'rfs_hfr'] + if a.Wavelength(RECEIVER_FREQUENCIES["rfs_lfr"].min, RECEIVER_FREQUENCIES["rfs_hfr"].max) in wavelength: + receivers = ["rfs_lfr", "rfs_hfr"] # If we get here the is no overlap so set to empty list return receivers def search(self, *args, **kwargs): """ - Query this client for a list of results. - - Parameters - ---------- - *args: `tuple` - `sunpy.net.attrs` objects representing the query. - **kwargs: `dict` - Any extra keywords to refine the search. - - Returns - ------- - A `QueryResponse` instance containing the query result. - """ + Query this client for a list of results. + + Parameters + ---------- + *args: `tuple` + `sunpy.net.attrs` objects representing the query. + **kwargs: `dict` + Any extra keywords to refine the search. + + Returns + ------- + A `QueryResponse` instance containing the query result. + """ matchdict = self._get_match_dict(*args, **kwargs) - req_wave = matchdict.get('Wavelength', None) + req_wave = matchdict.get("Wavelength", None) receivers = RECEIVER_FREQUENCIES.keys() if req_wave is not None: receivers = self._check_wavelengths(req_wave) metalist = [] - start_year = matchdict['Start Time'].datetime.year - end_year = matchdict['End Time'].datetime.year - tr = TimeRange(matchdict['Start Time'], matchdict['End Time']) + start_year = matchdict["Start Time"].datetime.year + end_year = matchdict["End Time"].datetime.year + tr = TimeRange(matchdict["Start Time"], matchdict["End Time"]) for receiver in receivers: - for year in range(start_year, end_year+1): + for year in range(start_year, end_year + 1): urlpattern = self.baseurl.format(Wavelength=receiver, year=year) scraper = Scraper(urlpattern, regex=True) filesmeta = scraper._extract_files_meta(tr, extractor=self.pattern) @@ -122,24 +120,24 @@ def search(self, *args, **kwargs): def post_search_hook(self, exdict, matchdict): """ - This method converts 'rfs_hfr' and 'rfs_lfr' in the url's metadata - to the frequency ranges of for low and high frequency receivers. + This method converts 'rfs_hfr' and 'rfs_lfr' in the url's metadata to + the frequency ranges of for low and high frequency receivers. """ rowdict = super().post_search_hook(exdict, matchdict) - if rowdict['Wavelength'] == 'rfs_hfr': - fr = RECEIVER_FREQUENCIES['rfs_hfr'] - rowdict['Wavelength'] = u.Quantity([float(fr.min.value), float(fr.max.value)], - unit=fr.unit) - elif rowdict['Wavelength'] == 'rfs_lfr': - fr = RECEIVER_FREQUENCIES['rfs_lfr'] - rowdict['Wavelength'] = u.Quantity([float(fr.min.value), float(fr.max.value)], - unit=fr.unit) + if rowdict["Wavelength"] == "rfs_hfr": + fr = RECEIVER_FREQUENCIES["rfs_hfr"] + rowdict["Wavelength"] = u.Quantity([float(fr.min.value), float(fr.max.value)], unit=fr.unit) + elif rowdict["Wavelength"] == "rfs_lfr": + fr = RECEIVER_FREQUENCIES["rfs_lfr"] + rowdict["Wavelength"] = u.Quantity([float(fr.min.value), float(fr.max.value)], unit=fr.unit) return rowdict @classmethod def register_values(cls): - adict = {a.Instrument: [('RFS', ('Radio Frequency Spectrometer'))], - a.Source: [('PSP', 'Parker Solar Probe')], - a.Provider: [('SPDF', 'NASA Goddard Space Physics Data Facility')], - a.Wavelength: [('*')]} + adict = { + a.Instrument: [("RFS", ("Radio Frequency Spectrometer"))], + a.Source: [("PSP", "Parker Solar Probe")], + a.Provider: [("SPDF", "NASA Goddard Space Physics Data Facility")], + a.Wavelength: [("*")], + } return adict diff --git a/radiospectra/net/sources/rstn.py b/radiospectra/net/sources/rstn.py index 44c8201..55332ce 100644 --- a/radiospectra/net/sources/rstn.py +++ b/radiospectra/net/sources/rstn.py @@ -5,13 +5,13 @@ from radiospectra.net.attrs import Observatory -__all__ = ['RSTNClient'] +__all__ = ["RSTNClient"] class RSTNClient(GenericClient): """ - Radio Spectrometer Telescope Network (RSTN) hosted at NOAA - `National Geophysical Data `__ (NGDC) archive. + Radio Spectrometer Telescope Network (RSTN) hosted at NOAA `National + Geophysical Data `__ (NGDC) archive. Examples -------- @@ -30,28 +30,29 @@ class RSTNClient(GenericClient): """ - baseurl = r'https://www.ngdc.noaa.gov/stp/space-weather/solar-data/' \ - r'solar-features/solar-radio/rstn-spectral/{obs}/%Y/%m/.*.gz' - pattern = r'{}/rstn-spectral/{obs}/{year:4d}/{month:2d}/' \ - r'{obs_short:2l}{year2:2d}{month2:2d}{day:2d}.SRS.gz' + + baseurl = ( + r"https://www.ngdc.noaa.gov/stp/space-weather/solar-data/" + r"solar-features/solar-radio/rstn-spectral/{obs}/%Y/%m/.*.gz" + ) + pattern = r"{}/rstn-spectral/{obs}/{year:4d}/{month:2d}/" r"{obs_short:2l}{year2:2d}{month2:2d}{day:2d}.SRS.gz" observatory_map = { - 'Holloman': 'holloman', - 'Learmonth': 'learmonth', - 'Palehua': 'palehua', - 'Sagamore Hill': 'sagamore', - 'San Vito': 'san-vito', + "Holloman": "holloman", + "Learmonth": "learmonth", + "Palehua": "palehua", + "Sagamore Hill": "sagamore", + "San Vito": "san-vito", } observatory_map = {**observatory_map, **dict(map(reversed, observatory_map.items()))} def search(self, *args, **kwargs): baseurl, pattern, matchdict = self.pre_search_hook(*args, **kwargs) metalist = [] - for obs in matchdict['Observatory']: + for obs in matchdict["Observatory"]: scraper = Scraper(baseurl.format(obs=self.observatory_map[obs.title()]), regex=True) - tr = TimeRange(matchdict['Start Time'], matchdict['End Time']) - filesmeta = scraper._extract_files_meta(tr, extractor=pattern, - matcher=matchdict) + tr = TimeRange(matchdict["Start Time"], matchdict["End Time"]) + filesmeta = scraper._extract_files_meta(tr, extractor=pattern, matcher=matchdict) for i in filesmeta: rowdict = self.post_search_hook(i, matchdict) @@ -61,18 +62,21 @@ def search(self, *args, **kwargs): def post_search_hook(self, exdict, matchdict): original = super().post_search_hook(exdict, matchdict) - obs, *_ = [original.pop(name) for name in ['obs', 'year2', 'month2', 'obs_short']] - original['Observatory'] = self.observatory_map[obs] + obs, *_ = [original.pop(name) for name in ["obs", "year2", "month2", "obs_short"]] + original["Observatory"] = self.observatory_map[obs] return original @classmethod def register_values(cls): adict = { - a.Provider: [('RSTN', 'Radio Solar Telescope Network.')], - a.Instrument: [('RSTN', 'Radio Solar Telescope Network.')], - Observatory: [('Holloman', 'Holloman'), - ('Learmonth', 'Learmonth'), - ('Palehua', 'Palehua'), - ('Sagamore Hill', 'Sagamore Hill'), - ('San Vito', 'San Vito')]} + a.Provider: [("RSTN", "Radio Solar Telescope Network.")], + a.Instrument: [("RSTN", "Radio Solar Telescope Network.")], + Observatory: [ + ("Holloman", "Holloman"), + ("Learmonth", "Learmonth"), + ("Palehua", "Palehua"), + ("Sagamore Hill", "Sagamore Hill"), + ("San Vito", "San Vito"), + ], + } return adict diff --git a/radiospectra/net/sources/stereo.py b/radiospectra/net/sources/stereo.py index 13415bb..ed9fe11 100644 --- a/radiospectra/net/sources/stereo.py +++ b/radiospectra/net/sources/stereo.py @@ -8,19 +8,21 @@ from radiospectra.net import attrs as ra -__all__ = ['SWAVESClient'] +__all__ = ["SWAVESClient"] RECEIVER_FREQUENCIES = { - 'lfr': a.Wavelength(10*u.kHz, 160*u.kHz), - 'hfr': a.Wavelength(0.125*u.MHz, 16*u.MHz), + "lfr": a.Wavelength(10 * u.kHz, 160 * u.kHz), + "hfr": a.Wavelength(0.125 * u.MHz, 16 * u.MHz), } class SWAVESClient(GenericClient): """ - Provides access to STEREO `S-WAVES `__ radio - data `archive `__ + Provides access to STEREO `S-WAVES. + + `__ radio data `archive + `__ Examples -------- @@ -44,17 +46,18 @@ class SWAVESClient(GenericClient): """ - baseurl = (r'https://solar-radio.gsfc.nasa.gov/data/stereo/summary/{year}/' - r'swaves_average_(\d){{8}}_{Spacecraft}_{Wavelength}.dat') + baseurl = ( + r"https://solar-radio.gsfc.nasa.gov/data/stereo/summary/{year}/" + r"swaves_average_(\d){{8}}_{Spacecraft}_{Wavelength}.dat" + ) - pattern = r'{}/{year:4d}/' \ - r'swaves_average_{year:4d}{month:2d}{day:2d}_{Spacecraft}_{Wavelength}.dat' + pattern = r"{}/{year:4d}/" r"swaves_average_{year:4d}{month:2d}{day:2d}_{Spacecraft}_{Wavelength}.dat" @classmethod def _check_wavelengths(cls, wavelength): """ - Check for overlap between given wavelength and receiver frequency coverage defined in - `RECEIVER_FREQUENCIES`. + Check for overlap between given wavelength and receiver frequency + coverage defined in `RECEIVER_FREQUENCIES`. Parameters ---------- @@ -71,49 +74,46 @@ def _check_wavelengths(cls, wavelength): # If not defined need to continue if not receivers: # Overlaps but not contained in, either max in lfr or min hfr - if wavelength.min in RECEIVER_FREQUENCIES['hfr'] or \ - wavelength.max in RECEIVER_FREQUENCIES['hfr']: - receivers.append('hfr') - if wavelength.min in RECEIVER_FREQUENCIES['lfr'] or \ - wavelength.max in RECEIVER_FREQUENCIES['lfr']: - receivers.append('lfr') + if wavelength.min in RECEIVER_FREQUENCIES["hfr"] or wavelength.max in RECEIVER_FREQUENCIES["hfr"]: + receivers.append("hfr") + if wavelength.min in RECEIVER_FREQUENCIES["lfr"] or wavelength.max in RECEIVER_FREQUENCIES["lfr"]: + receivers.append("lfr") # min in lfr and max in hfr # min and max of combined lft and hfr contained in give wavelength range - if a.Wavelength(RECEIVER_FREQUENCIES['lfr'].min, - RECEIVER_FREQUENCIES['hfr'].max) in wavelength: - receivers = ['lfr', 'hfr'] + if a.Wavelength(RECEIVER_FREQUENCIES["lfr"].min, RECEIVER_FREQUENCIES["hfr"].max) in wavelength: + receivers = ["lfr", "hfr"] # If we get here the is no overlap so set to empty list return receivers def search(self, *args, **kwargs): """ - Query this client for a list of results. - - Parameters - ---------- - *args: `tuple` - `sunpy.net.attrs` objects representing the query. - **kwargs: `dict` - Any extra keywords to refine the search. - - Returns - ------- - A `QueryResponse` instance containing the query result. - """ + Query this client for a list of results. + + Parameters + ---------- + *args: `tuple` + `sunpy.net.attrs` objects representing the query. + **kwargs: `dict` + Any extra keywords to refine the search. + + Returns + ------- + A `QueryResponse` instance containing the query result. + """ matchdict = self._get_match_dict(*args, **kwargs) - req_wave = matchdict.get('Wavelength', None) + req_wave = matchdict.get("Wavelength", None) receivers = RECEIVER_FREQUENCIES.keys() if req_wave is not None: receivers = self._check_wavelengths(req_wave) - spacecraft = matchdict.get('spacecraft', ['a', 'b']) + spacecraft = matchdict.get("spacecraft", ["a", "b"]) metalist = [] - start_year = matchdict['Start Time'].datetime.year - end_year = matchdict['End Time'].datetime.year - tr = TimeRange(matchdict['Start Time'], matchdict['End Time']) + start_year = matchdict["Start Time"].datetime.year + end_year = matchdict["End Time"].datetime.year + tr = TimeRange(matchdict["Start Time"], matchdict["End Time"]) for spc, receiver in product(spacecraft, receivers): - for year in range(start_year, end_year+1): + for year in range(start_year, end_year + 1): urlpattern = self.baseurl.format(Wavelength=receiver, Spacecraft=spc, year=year) scraper = Scraper(urlpattern, regex=True) filesmeta = scraper._extract_files_meta(tr, extractor=self.pattern) @@ -125,25 +125,25 @@ def search(self, *args, **kwargs): def post_search_hook(self, exdict, matchdict): """ - This method converts 'rfs_hfr' and 'rfs_lfr' in the url's metadata - to the frequency ranges of for low and high frequency receivers. + This method converts 'rfs_hfr' and 'rfs_lfr' in the url's metadata to + the frequency ranges of for low and high frequency receivers. """ rowdict = super().post_search_hook(exdict, matchdict) - if rowdict['Wavelength'] == 'hfr': - fr = RECEIVER_FREQUENCIES['hfr'] - rowdict['Wavelength'] = u.Quantity([float(fr.min.value), float(fr.max.value)], - unit=fr.unit) - elif rowdict['Wavelength'] == 'lfr': - fr = RECEIVER_FREQUENCIES['lfr'] - rowdict['Wavelength'] = u.Quantity([float(fr.min.value), float(fr.max.value)], - unit=fr.unit) + if rowdict["Wavelength"] == "hfr": + fr = RECEIVER_FREQUENCIES["hfr"] + rowdict["Wavelength"] = u.Quantity([float(fr.min.value), float(fr.max.value)], unit=fr.unit) + elif rowdict["Wavelength"] == "lfr": + fr = RECEIVER_FREQUENCIES["lfr"] + rowdict["Wavelength"] = u.Quantity([float(fr.min.value), float(fr.max.value)], unit=fr.unit) return rowdict @classmethod def register_values(cls): - adict = {a.Instrument: [('SWAVES', 'STEREO WAVES - SWAVES')], - a.Source: [('STEREO', 'Solar Terrestrial Relations Observatory')], - ra.Spacecraft: [('A', 'Ahead'), ('B', 'Behind')], - a.Provider: [('NASA', 'NASA Goddard Space Flight Center')], - a.Wavelength: [('*')]} + adict = { + a.Instrument: [("SWAVES", "STEREO WAVES - SWAVES")], + a.Source: [("STEREO", "Solar Terrestrial Relations Observatory")], + ra.Spacecraft: [("A", "Ahead"), ("B", "Behind")], + a.Provider: [("NASA", "NASA Goddard Space Flight Center")], + a.Wavelength: [("*")], + } return adict diff --git a/radiospectra/net/sources/tests/test_callisto_client.py b/radiospectra/net/sources/tests/test_callisto_client.py index 7dabd73..16909dc 100644 --- a/radiospectra/net/sources/tests/test_callisto_client.py +++ b/radiospectra/net/sources/tests/test_callisto_client.py @@ -20,8 +20,7 @@ def client(): @pytest.fixture def http_responses(): - paths = [Path(__file__).parent / 'data' / n for n in ['ecallisto_resp1.html.gz', - 'ecallisto_resp2.html.gz']] + paths = [Path(__file__).parent / "data" / n for n in ["ecallisto_resp1.html.gz", "ecallisto_resp2.html.gz"]] response_htmls = [] for p in paths: with gzip.open(p) as f: @@ -34,12 +33,10 @@ def test_client(urlopen, client, http_responses): urlopen.return_value.read = mock.MagicMock() urlopen.return_value.read.side_effect = http_responses urlopen.close = mock.MagicMock(return_value=None) - query = client.search(a.Time('2019/10/05 23:00', '2019/10/06 00:59'), - a.Instrument('eCALLISTO')) + query = client.search(a.Time("2019/10/05 23:00", "2019/10/06 00:59"), a.Instrument("eCALLISTO")) assert urlopen.call_count == 2 # 2nd call - urlopen.assert_called_with( - 'http://soleil80.cs.technik.fhnw.ch/solarradio/data/2002-20yy_Callisto/2019/10/06/') + urlopen.assert_called_with("http://soleil80.cs.technik.fhnw.ch/solarradio/data/2002-20yy_Callisto/2019/10/06/") assert len(query) == 156 @@ -48,18 +45,19 @@ def test_client_with_observeratory(urlopen, client, http_responses): urlopen.return_value.read = mock.MagicMock() urlopen.return_value.read.side_effect = http_responses urlopen.close = mock.MagicMock(return_value=None) - query = client.search(a.Time('2019/10/05 23:00', '2019/10/06 00:59'), - a.Instrument('eCALLISTO'), Observatory('ALASKA')) + query = client.search( + a.Time("2019/10/05 23:00", "2019/10/06 00:59"), a.Instrument("eCALLISTO"), Observatory("ALASKA") + ) assert urlopen.call_count == 2 # 2nd call - urlopen.assert_called_with( - 'http://soleil80.cs.technik.fhnw.ch/solarradio/data/2002-20yy_Callisto/2019/10/06/') + urlopen.assert_called_with("http://soleil80.cs.technik.fhnw.ch/solarradio/data/2002-20yy_Callisto/2019/10/06/") assert len(query) == 8 @pytest.mark.remote_data def test_fido(): - query = Fido.search(a.Time('2019/10/05 23:00', '2019/10/06 00:59'), - a.Instrument('eCALLISTO'), Observatory('ALASKA')) + query = Fido.search( + a.Time("2019/10/05 23:00", "2019/10/06 00:59"), a.Instrument("eCALLISTO"), Observatory("ALASKA") + ) assert len(query[0]) == 8 - assert all(query[0]['Observatory'] == 'ALASKA') + assert all(query[0]["Observatory"] == "ALASKA") diff --git a/radiospectra/net/sources/tests/test_eovsa_client.py b/radiospectra/net/sources/tests/test_eovsa_client.py index 8bbc624..2f090ea 100644 --- a/radiospectra/net/sources/tests/test_eovsa_client.py +++ b/radiospectra/net/sources/tests/test_eovsa_client.py @@ -21,10 +21,10 @@ def client(): @pytest.fixture def http_responses(): - paths = [Path(__file__).parent / 'data' / n for n in ['eovsa_resp1.html', 'eovsa_resp2.html']] + paths = [Path(__file__).parent / "data" / n for n in ["eovsa_resp1.html", "eovsa_resp2.html"]] response_htmls = [] for p in paths: - with p.open('r') as f: + with p.open("r") as f: response_htmls.append(f.read()) return response_htmls @@ -35,11 +35,10 @@ def test_client(urlopen, client, http_responses): urlopen.return_value.read = mock.MagicMock() urlopen.return_value.read.side_effect = http_responses urlopen.close = mock.MagicMock(return_value=None) - query = client.search(a.Time('2020/10/05 00:00', '2020/10/06 23:00'), - a.Instrument('EOVSA')) + query = client.search(a.Time("2020/10/05 00:00", "2020/10/06 23:00"), a.Instrument("EOVSA")) assert urlopen.call_count == 2 # last call should be for 2020/10/06 - assert urlopen.call_args[0][0] == 'http://ovsa.njit.edu/fits/synoptic/2020/10/06/' + assert urlopen.call_args[0][0] == "http://ovsa.njit.edu/fits/synoptic/2020/10/06/" assert len(query) == 4 @@ -48,18 +47,16 @@ def test_client_observatory(urlopen, client, http_responses): urlopen.return_value.read = mock.MagicMock() urlopen.return_value.read.side_effect = http_responses urlopen.close = mock.MagicMock(return_value=None) - query = client.search(a.Time('2020/10/05 00:00', '2020/10/06 00:00'), - a.Instrument('EOVSA'), PolType.cross) + query = client.search(a.Time("2020/10/05 00:00", "2020/10/06 00:00"), a.Instrument("EOVSA"), PolType.cross) assert urlopen.call_count == 2 # last call should be for 2020/10/06 - assert urlopen.call_args[0][0] == 'http://ovsa.njit.edu/fits/synoptic/2020/10/06/' + assert urlopen.call_args[0][0] == "http://ovsa.njit.edu/fits/synoptic/2020/10/06/" assert len(query) == 2 - assert np.all(query['PolType'] == 'Cross') + assert np.all(query["PolType"] == "Cross") @pytest.mark.remote_data def test_fido(): - query = Fido.search(a.Time('2020/10/05 00:00', '2020/10/06 00:00'), - a.Instrument('EOVSA'), PolType.cross) + query = Fido.search(a.Time("2020/10/05 00:00", "2020/10/06 00:00"), a.Instrument("EOVSA"), PolType.cross) assert len(query[0]) == 2 - assert np.all(query[0]['PolType'] == 'Cross') + assert np.all(query[0]["PolType"] == "Cross") diff --git a/radiospectra/net/sources/tests/test_psp_client.py b/radiospectra/net/sources/tests/test_psp_client.py index 62f0fc7..a83a7d5 100644 --- a/radiospectra/net/sources/tests/test_psp_client.py +++ b/radiospectra/net/sources/tests/test_psp_client.py @@ -21,22 +21,25 @@ def client(): return RFSClient() -@pytest.mark.parametrize("req_wave,receivers", [ - # Completely contain the both receiver ranges - (a.Wavelength(1*u.kHz, 25000*u.kHz), ['rfs_lfr', 'rfs_hfr']), - # Min in lower freq and max in high freq receiver - (a.Wavelength(20*u.kHz, 15*u.MHz), ['rfs_lfr', 'rfs_hfr']), - # Min below and max in low freq receiver - (a.Wavelength(1*u.kHz, 100*u.kHz), ['rfs_lfr']), - # Min and max in low freq receiver - (a.Wavelength(20*u.kHz, 100*u.kHz), ['rfs_lfr']), - # Min and max in high freq receiver - (a.Wavelength(1800*u.kHz, 18000*u.kHz), ['rfs_hfr']), - # Min in high freq receiver and max above - (a.Wavelength(1800*u.kHz, 20000*u.kHz), ['rfs_hfr']), - # Min and max in the over lap - (a.Wavelength(1.4*u.MHz, 1.5*u.MHz), ['rfs_lfr', 'rfs_hfr']) -]) +@pytest.mark.parametrize( + "req_wave,receivers", + [ + # Completely contain the both receiver ranges + (a.Wavelength(1 * u.kHz, 25000 * u.kHz), ["rfs_lfr", "rfs_hfr"]), + # Min in lower freq and max in high freq receiver + (a.Wavelength(20 * u.kHz, 15 * u.MHz), ["rfs_lfr", "rfs_hfr"]), + # Min below and max in low freq receiver + (a.Wavelength(1 * u.kHz, 100 * u.kHz), ["rfs_lfr"]), + # Min and max in low freq receiver + (a.Wavelength(20 * u.kHz, 100 * u.kHz), ["rfs_lfr"]), + # Min and max in high freq receiver + (a.Wavelength(1800 * u.kHz, 18000 * u.kHz), ["rfs_hfr"]), + # Min in high freq receiver and max above + (a.Wavelength(1800 * u.kHz, 20000 * u.kHz), ["rfs_hfr"]), + # Min and max in the over lap + (a.Wavelength(1.4 * u.MHz, 1.5 * u.MHz), ["rfs_lfr", "rfs_hfr"]), + ], +) def test_check_wavelength(req_wave, receivers, client): res = client._check_wavelengths(req_wave) assert set(res) == set(receivers) @@ -44,18 +47,18 @@ def test_check_wavelength(req_wave, receivers, client): @pytest.mark.remote_data def test_fido(): - atr = a.Time('2019/10/01', '2019/10/02') - res = Fido.search(atr, a.Instrument('rfs')) + atr = a.Time("2019/10/01", "2019/10/02") + res = Fido.search(atr, a.Instrument("rfs")) res0 = res[0] isinstance(res0.client, RFSClient) assert len(res0) == 4 - assert res['rfs']['Start Time'].min() == Time('2019-10-01T00:00').datetime - assert res['rfs']['End Time'].max() == Time('2019-10-02T23:59:59.999').datetime + assert res["rfs"]["Start Time"].min() == Time("2019-10-01T00:00").datetime + assert res["rfs"]["End Time"].max() == Time("2019-10-02T23:59:59.999").datetime @pytest.fixture def http_responces(): - paths = [Path(__file__).parent / 'data' / n for n in ['psp_resp1.html.gz', 'psp_resp2.html.gz']] + paths = [Path(__file__).parent / "data" / n for n in ["psp_resp1.html.gz", "psp_resp2.html.gz"]] response_htmls = [] for p in paths: with gzip.open(p) as f: @@ -68,42 +71,38 @@ def test_search_with_wavelength(mock_urlopen, client, http_responces): mock_urlopen.return_value.read = mock.MagicMock() mock_urlopen.return_value.read.side_effect = http_responces mock_urlopen.close = mock.MagicMock(return_value=None) - tr = a.Time('2019/10/13', '2019/10/15') - wr1 = a.Wavelength(1*u.kHz, 1.1*u.MHz) + tr = a.Time("2019/10/13", "2019/10/15") + wr1 = a.Wavelength(1 * u.kHz, 1.1 * u.MHz) res1 = client.search(tr, wr1) - mock_urlopen.assert_called_with( - 'https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/rfs_lfr/2019/') - assert np.array_equal(res1[0]['Wavelength'], [10, 1700] * u.kHz) + mock_urlopen.assert_called_with("https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/rfs_lfr/2019/") + assert np.array_equal(res1[0]["Wavelength"], [10, 1700] * u.kHz) assert len(res1) == 3 - assert res1['Start Time'].min().datetime == Time('2019-10-13T00:00').datetime - assert res1['End Time'].max().datetime == Time('2019-10-15T23:59:59.999').datetime - wr2 = a.Wavelength(2*u.MHz, 20*u.MHz) + assert res1["Start Time"].min().datetime == Time("2019-10-13T00:00").datetime + assert res1["End Time"].max().datetime == Time("2019-10-15T23:59:59.999").datetime + wr2 = a.Wavelength(2 * u.MHz, 20 * u.MHz) res2 = client.search(tr, wr2) - mock_urlopen.assert_called_with( - 'https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/rfs_hfr/2019/') - assert np.array_equal(res2[0]['Wavelength'], [1300, 19200] * u.kHz) + mock_urlopen.assert_called_with("https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/rfs_hfr/2019/") + assert np.array_equal(res2[0]["Wavelength"], [1300, 19200] * u.kHz) assert len(res2) == 3 - assert res2.time_range().start == Time('2019-10-13T00:00').datetime - assert res2.time_range().end == Time('2019-10-15T23:59:59.999').datetime + assert res2.time_range().start == Time("2019-10-13T00:00").datetime + assert res2.time_range().end == Time("2019-10-15T23:59:59.999").datetime @pytest.mark.remote_data def test_get_url_for_time_range(client): - url_start = 'https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/rfs_lfr/2019/' \ - 'psp_fld_l2_rfs_lfr_20191001_v02.cdf' - url_end = 'https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/rfs_hfr/2019/' \ - 'psp_fld_l2_rfs_hfr_20191015_v02.cdf' - tr = a.Time('2019/10/01', '2019/10/15') + url_start = "https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/rfs_lfr/2019/" "psp_fld_l2_rfs_lfr_20191001_v02.cdf" + url_end = "https://spdf.gsfc.nasa.gov/pub/data/psp/fields/l2/rfs_hfr/2019/" "psp_fld_l2_rfs_hfr_20191015_v02.cdf" + tr = a.Time("2019/10/01", "2019/10/15") res = client.search(tr) - urls = [i['url'] for i in res] + urls = [i["url"] for i in res] assert urls[0] == url_start assert urls[-1] == url_end def test_can_handle_query(client): - atr = a.Time('2019/10/01', '2019/11/01') - res = client._can_handle_query(atr, a.Instrument('rfs')) + atr = a.Time("2019/10/01", "2019/11/01") + res = client._can_handle_query(atr, a.Instrument("rfs")) assert res is True res = client._can_handle_query(atr) assert res is False @@ -111,6 +110,6 @@ def test_can_handle_query(client): @pytest.mark.remote_data def test_download(client): - query = client.search(a.Time('2019/10/05', '2019/10/06'), a.Instrument('rfs')) + query = client.search(a.Time("2019/10/05", "2019/10/06"), a.Instrument("rfs")) download_list = client.fetch(query) assert len(download_list) == len(query) diff --git a/radiospectra/net/sources/tests/test_rstn_client.py b/radiospectra/net/sources/tests/test_rstn_client.py index 99a8762..133286b 100644 --- a/radiospectra/net/sources/tests/test_rstn_client.py +++ b/radiospectra/net/sources/tests/test_rstn_client.py @@ -20,17 +20,17 @@ def client(): @pytest.fixture def http_responses(): - paths = [Path(__file__).parent / 'data' / n for n in ['rstn_holloman.html', - 'rstn_learmonth.html', - 'rstn_san-vito.html']] + paths = [ + Path(__file__).parent / "data" / n for n in ["rstn_holloman.html", "rstn_learmonth.html", "rstn_san-vito.html"] + ] response_htmls = [] for p in paths: - with p.open('r') as f: + with p.open("r") as f: response_htmls.append(f.read()) # For the chosen test dates there was no data form Palehua or Sagamore so insert two empty # responses in there place - response_htmls = response_htmls[:2] + ['', ''] + [response_htmls[-1]] + response_htmls = response_htmls[:2] + ["", ""] + [response_htmls[-1]] return response_htmls @@ -39,12 +39,13 @@ def test_client(urlopen, client, http_responses): urlopen.return_value.read = mock.MagicMock() urlopen.return_value.read.side_effect = http_responses urlopen.close = mock.MagicMock(return_value=None) - query = client.search(a.Time('2003/03/15 00:00', '2003/03/15 23:59'), - a.Instrument('RSTN')) + query = client.search(a.Time("2003/03/15 00:00", "2003/03/15 23:59"), a.Instrument("RSTN")) assert urlopen.call_count == 5 # last call arg should be san-vito url - assert urlopen.call_args[0][0] == 'https://www.ngdc.noaa.gov/stp/space-weather/solar-data/' \ - 'solar-features/solar-radio/rstn-spectral/san-vito/2003/03/' + assert ( + urlopen.call_args[0][0] == "https://www.ngdc.noaa.gov/stp/space-weather/solar-data/" + "solar-features/solar-radio/rstn-spectral/san-vito/2003/03/" + ) assert len(query) == 3 @@ -53,17 +54,17 @@ def test_client_observatory(urlopen, client, http_responses): urlopen.return_value.read = mock.MagicMock() urlopen.return_value.read.side_effect = http_responses[-1:] urlopen.close = mock.MagicMock(return_value=None) - query = client.search(a.Time('2003/03/15 00:00', '2003/03/15 23:59'), - a.Instrument('RSTN'), Observatory('San Vito')) - urlopen.assert_called_once_with('https://www.ngdc.noaa.gov/stp/space-weather/solar-data/' - 'solar-features/solar-radio/rstn-spectral/san-vito/2003/03/') + query = client.search(a.Time("2003/03/15 00:00", "2003/03/15 23:59"), a.Instrument("RSTN"), Observatory("San Vito")) + urlopen.assert_called_once_with( + "https://www.ngdc.noaa.gov/stp/space-weather/solar-data/" + "solar-features/solar-radio/rstn-spectral/san-vito/2003/03/" + ) assert len(query) == 1 - assert query['Observatory'] == 'San Vito' + assert query["Observatory"] == "San Vito" @pytest.mark.remote_data def test_fido(): - query = Fido.search(a.Time('2003/03/15 00:00', '2003/03/15 23:59'), - a.Instrument('RSTN'), Observatory('San Vito')) + query = Fido.search(a.Time("2003/03/15 00:00", "2003/03/15 23:59"), a.Instrument("RSTN"), Observatory("San Vito")) assert len(query[0]) == 1 - assert all(query[0]['Observatory'] == 'San Vito') + assert all(query[0]["Observatory"] == "San Vito") diff --git a/radiospectra/net/sources/tests/test_stereo_client.py b/radiospectra/net/sources/tests/test_stereo_client.py index 31047e7..557b184 100644 --- a/radiospectra/net/sources/tests/test_stereo_client.py +++ b/radiospectra/net/sources/tests/test_stereo_client.py @@ -22,8 +22,8 @@ def client(): @pytest.mark.remote_data def test_fido(): - atr = a.Time('2010/10/01', '2010/10/02') - res = Fido.search(atr, a.Instrument('swaves')) + atr = a.Time("2010/10/01", "2010/10/02") + res = Fido.search(atr, a.Instrument("swaves")) assert isinstance(res[1].client, SWAVESClient) assert len(res[1]) == 8 @@ -93,31 +93,34 @@ def test_fido(): def test_swaves_client(mock_urlopen, client): mock_urlopen.return_value.read = mock.MagicMock(return_value=http_cont) mock_urlopen.close = mock.MagicMock(return_value=None) - atr = a.Time('2010/01/02', '2010/01/03') - query = client.search(atr, a.Instrument('swaves'), Spacecraft('a')) - mock_urlopen.assert_called_with('https://solar-radio.gsfc.nasa.gov/data/stereo/summary/2010/') + atr = a.Time("2010/01/02", "2010/01/03") + query = client.search(atr, a.Instrument("swaves"), Spacecraft("a")) + mock_urlopen.assert_called_with("https://solar-radio.gsfc.nasa.gov/data/stereo/summary/2010/") assert len(query) == 8 - assert query[0]['Source'] == 'STEREO' - assert query[0]['Spacecraft'] == 'a' - assert np.array_equal(query[0]['Wavelength'], [10, 160] * u.kHz) - assert query[0]['Start Time'].datetime == datetime(2010, 1, 2) - assert query[0]['End Time'].datetime == datetime(2010, 1, 2, 23, 59, 59, 999000) - assert query[7]['Source'] == 'STEREO' - assert query[7]['Spacecraft'] == 'b' - assert np.array_equal(query[7]['Wavelength'], [125, 16000] * u.kHz) - assert query[7]['Start Time'].datetime == datetime(2010, 1, 3) - assert query[7]['End Time'].datetime == datetime(2010, 1, 3, 23, 59, 59, 999000) + assert query[0]["Source"] == "STEREO" + assert query[0]["Spacecraft"] == "a" + assert np.array_equal(query[0]["Wavelength"], [10, 160] * u.kHz) + assert query[0]["Start Time"].datetime == datetime(2010, 1, 2) + assert query[0]["End Time"].datetime == datetime(2010, 1, 2, 23, 59, 59, 999000) + assert query[7]["Source"] == "STEREO" + assert query[7]["Spacecraft"] == "b" + assert np.array_equal(query[7]["Wavelength"], [125, 16000] * u.kHz) + assert query[7]["Start Time"].datetime == datetime(2010, 1, 3) + assert query[7]["End Time"].datetime == datetime(2010, 1, 3, 23, 59, 59, 999000) -@pytest.mark.parametrize("query_wave, receivers", [(a.Wavelength(1*u.GHz, 2*u.GHz), []), - (a.Wavelength(1*u.Hz, 2*u.Hz), []), - (a.Wavelength(20*u.kHz, 150*u.kHz), ['lfr']), - (a.Wavelength(0.13*u.MHz, 15*u.MHz), ['hfr']), - (a.Wavelength(10*u.MHz, 200*u.MHz), ['hfr']), - (a.Wavelength(100*u.Hz, 100*u.kHz), ['lfr']), - (a.Wavelength(20*u.kHz, 15*u.MHz), - ['lfr', 'hfr']), - (a.Wavelength(5*u.kHz, 20*u.MHz), - ['lfr', 'hfr'])]) +@pytest.mark.parametrize( + "query_wave, receivers", + [ + (a.Wavelength(1 * u.GHz, 2 * u.GHz), []), + (a.Wavelength(1 * u.Hz, 2 * u.Hz), []), + (a.Wavelength(20 * u.kHz, 150 * u.kHz), ["lfr"]), + (a.Wavelength(0.13 * u.MHz, 15 * u.MHz), ["hfr"]), + (a.Wavelength(10 * u.MHz, 200 * u.MHz), ["hfr"]), + (a.Wavelength(100 * u.Hz, 100 * u.kHz), ["lfr"]), + (a.Wavelength(20 * u.kHz, 15 * u.MHz), ["lfr", "hfr"]), + (a.Wavelength(5 * u.kHz, 20 * u.MHz), ["lfr", "hfr"]), + ], +) def test_check_wavelength(query_wave, receivers, client): assert set(client._check_wavelengths(query_wave)) == set(receivers) diff --git a/radiospectra/net/sources/tests/test_wind_client.py b/radiospectra/net/sources/tests/test_wind_client.py index a54f94c..675fe73 100644 --- a/radiospectra/net/sources/tests/test_wind_client.py +++ b/radiospectra/net/sources/tests/test_wind_client.py @@ -21,8 +21,8 @@ def client(): @pytest.mark.remote_data def test_fido(): - atr = a.Time('2010/10/01', '2010/10/02') - res = Fido.search(atr, a.Instrument('waves')) + atr = a.Time("2010/10/01", "2010/10/02") + res = Fido.search(atr, a.Instrument("waves")) assert isinstance(res[0].client, WAVESClient) assert len(res[0]) == 4 @@ -77,35 +77,40 @@ def test_waves_client(mock_urlopen, client, html_responses): mock_urlopen.return_value.read = mock.MagicMock() mock_urlopen.return_value.read.side_effect = html_responses mock_urlopen.close = mock.MagicMock(return_value=None) - atr = a.Time('2010/01/02', '2010/01/03') + atr = a.Time("2010/01/02", "2010/01/03") query = client.search(atr) - called_urls = ['https://solar-radio.gsfc.nasa.gov/data/wind/rad1/2010/rad1/', - 'https://solar-radio.gsfc.nasa.gov/data/wind/rad2/2010/rad2/'] + called_urls = [ + "https://solar-radio.gsfc.nasa.gov/data/wind/rad1/2010/rad1/", + "https://solar-radio.gsfc.nasa.gov/data/wind/rad2/2010/rad2/", + ] assert called_urls == [call[0][0] for call in mock_urlopen.call_args_list] assert len(query) == 4 - assert query[0]['Source'] == 'WIND' + assert query[0]["Source"] == "WIND" wave = [20, 1040] * u.kHz - assert np.array_equal(query[0]['Wavelength'], wave) - assert query[0]['Start Time'].datetime == datetime(2010, 1, 2) - assert query[0]['End Time'].datetime == datetime(2010, 1, 2, 23, 59, 59, 999000) + assert np.array_equal(query[0]["Wavelength"], wave) + assert query[0]["Start Time"].datetime == datetime(2010, 1, 2) + assert query[0]["End Time"].datetime == datetime(2010, 1, 2, 23, 59, 59, 999000) wave = [1075, 13825] * u.kHz - assert np.array_equal(query[3]['Wavelength'], wave) - assert query[3]['Start Time'].datetime == datetime(2010, 1, 3) - assert query[3]['End Time'].datetime == datetime(2010, 1, 3, 23, 59, 59, 999000) - - -@pytest.mark.parametrize("query_wave, receivers", [(a.Wavelength(1*u.GHz, 2*u.GHz), []), - (a.Wavelength(1*u.Hz, 2*u.Hz), []), - (a.Wavelength(20*u.kHz, 150*u.kHz), ['rad1']), - (a.Wavelength(1.5*u.MHz, 15*u.MHz), ['rad2']), - (a.Wavelength(5*u.MHz, 10*u.MHz), ['rad2']), - (a.Wavelength(100*u.Hz, 100*u.kHz), ['rad1']), - (a.Wavelength(20*u.kHz, 15*u.MHz), - ['rad1', 'rad2']), - (a.Wavelength(5*u.kHz, 20*u.MHz), - ['rad1', 'rad2'])]) + assert np.array_equal(query[3]["Wavelength"], wave) + assert query[3]["Start Time"].datetime == datetime(2010, 1, 3) + assert query[3]["End Time"].datetime == datetime(2010, 1, 3, 23, 59, 59, 999000) + + +@pytest.mark.parametrize( + "query_wave, receivers", + [ + (a.Wavelength(1 * u.GHz, 2 * u.GHz), []), + (a.Wavelength(1 * u.Hz, 2 * u.Hz), []), + (a.Wavelength(20 * u.kHz, 150 * u.kHz), ["rad1"]), + (a.Wavelength(1.5 * u.MHz, 15 * u.MHz), ["rad2"]), + (a.Wavelength(5 * u.MHz, 10 * u.MHz), ["rad2"]), + (a.Wavelength(100 * u.Hz, 100 * u.kHz), ["rad1"]), + (a.Wavelength(20 * u.kHz, 15 * u.MHz), ["rad1", "rad2"]), + (a.Wavelength(5 * u.kHz, 20 * u.MHz), ["rad1", "rad2"]), + ], +) def test_check_wavelength(query_wave, receivers, client): assert set(client._check_wavelengths(query_wave)) == set(receivers) diff --git a/radiospectra/net/sources/wind.py b/radiospectra/net/sources/wind.py index 64890e6..06fe455 100644 --- a/radiospectra/net/sources/wind.py +++ b/radiospectra/net/sources/wind.py @@ -1,28 +1,29 @@ - import astropy.units as u from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse from sunpy.time import TimeRange from sunpy.util.scraper import Scraper -__all__ = ['WAVESClient'] +__all__ = ["WAVESClient"] RECEIVER_FREQUENCIES = { - 'rad1': a.Wavelength(20*u.kHz, 1040*u.kHz), - 'rad2': a.Wavelength(1.075*u.MHz, 13.825*u.MHz), + "rad1": a.Wavelength(20 * u.kHz, 1040 * u.kHz), + "rad2": a.Wavelength(1.075 * u.MHz, 13.825 * u.MHz), } RECEIVER_EXT = { - 'rad1': 'R1', - 'rad2': 'R2', + "rad1": "R1", + "rad2": "R2", } class WAVESClient(GenericClient): """ - Provides access to WIND `WAVES `__ radio - data `archive `__ + Provides access to WIND `WAVES `__ radio data `archive. + + `__ Examples -------- @@ -45,16 +46,15 @@ class WAVESClient(GenericClient): """ - baseurl = (r'https://solar-radio.gsfc.nasa.gov/data/wind/{Wavelength}/{year}/{Wavelength}/' - r'(\d){{8}}.{ext}') + baseurl = r"https://solar-radio.gsfc.nasa.gov/data/wind/{Wavelength}/{year}/{Wavelength}/" r"(\d){{8}}.{ext}" - pattern = r'{}/{Wavelength}/{year:4d}/{Wavelength}/{year:4d}{month:2d}{day:2d}.{ext}' + pattern = r"{}/{Wavelength}/{year:4d}/{Wavelength}/{year:4d}{month:2d}{day:2d}.{ext}" @classmethod def _check_wavelengths(cls, wavelength): """ - Check for overlap between given wavelength and receiver frequency coverage defined in - `RECEIVER_FREQUENCIES`. + Check for overlap between given wavelength and receiver frequency + coverage defined in `RECEIVER_FREQUENCIES`. Parameters ---------- @@ -71,17 +71,14 @@ def _check_wavelengths(cls, wavelength): # If not defined need to continue if not receivers: # Overlaps but not contained in, either max in lfr or min hfr - if wavelength.min in RECEIVER_FREQUENCIES['rad2'] or \ - wavelength.max in RECEIVER_FREQUENCIES['rad2']: - receivers.append('rad2') - if wavelength.min in RECEIVER_FREQUENCIES['rad1'] or \ - wavelength.max in RECEIVER_FREQUENCIES['rad1']: - receivers.append('rad1') + if wavelength.min in RECEIVER_FREQUENCIES["rad2"] or wavelength.max in RECEIVER_FREQUENCIES["rad2"]: + receivers.append("rad2") + if wavelength.min in RECEIVER_FREQUENCIES["rad1"] or wavelength.max in RECEIVER_FREQUENCIES["rad1"]: + receivers.append("rad1") # min in lfr and max in hfr # min and max of combined lft and hfr contained in give wavelength range - if a.Wavelength(RECEIVER_FREQUENCIES['rad1'].min, - RECEIVER_FREQUENCIES['rad2'].max) in wavelength: - receivers = ['rad1', 'rad2'] + if a.Wavelength(RECEIVER_FREQUENCIES["rad1"].min, RECEIVER_FREQUENCIES["rad2"].max) in wavelength: + receivers = ["rad1", "rad2"] # If we get here the is no overlap so set to empty list return receivers @@ -101,19 +98,18 @@ def search(self, *args, **kwargs): A `QueryResponse` instance containing the query result. """ matchdict = self._get_match_dict(*args, **kwargs) - req_wave = matchdict.get('Wavelength', None) + req_wave = matchdict.get("Wavelength", None) receivers = RECEIVER_FREQUENCIES.keys() if req_wave is not None: receivers = self._check_wavelengths(req_wave) metalist = [] - start_year = matchdict['Start Time'].datetime.year - end_year = matchdict['End Time'].datetime.year - tr = TimeRange(matchdict['Start Time'], matchdict['End Time']) + start_year = matchdict["Start Time"].datetime.year + end_year = matchdict["End Time"].datetime.year + tr = TimeRange(matchdict["Start Time"], matchdict["End Time"]) for receiver in receivers: - for year in range(start_year, end_year+1): - urlpattern = self.baseurl.format(Wavelength=receiver, year=year, - ext=RECEIVER_EXT[receiver]) + for year in range(start_year, end_year + 1): + urlpattern = self.baseurl.format(Wavelength=receiver, year=year, ext=RECEIVER_EXT[receiver]) scraper = Scraper(urlpattern, regex=True) filesmeta = scraper._extract_files_meta(tr, extractor=self.pattern) for i in filesmeta: @@ -124,25 +120,26 @@ def search(self, *args, **kwargs): def post_search_hook(self, exdict, matchdict): """ - This method converts 'rad1' and 'rad1' in the url's metadata to the frequency ranges of - for low and high frequency receivers and removes the ext. + This method converts 'rad1' and 'rad1' in the url's metadata to the + frequency ranges of for low and high frequency receivers and removes + the ext. """ rowdict = super().post_search_hook(exdict, matchdict) - rowdict.pop('ext', None) - if rowdict['Wavelength'] == 'rad1': - fr = RECEIVER_FREQUENCIES['rad1'] - rowdict['Wavelength'] = u.Quantity([float(fr.min.value), float(fr.max.value)], - unit=fr.unit) - elif rowdict['Wavelength'] == 'rad2': - fr = RECEIVER_FREQUENCIES['rad2'] - rowdict['Wavelength'] = u.Quantity([float(fr.min.value), float(fr.max.value)], - unit=fr.unit) + rowdict.pop("ext", None) + if rowdict["Wavelength"] == "rad1": + fr = RECEIVER_FREQUENCIES["rad1"] + rowdict["Wavelength"] = u.Quantity([float(fr.min.value), float(fr.max.value)], unit=fr.unit) + elif rowdict["Wavelength"] == "rad2": + fr = RECEIVER_FREQUENCIES["rad2"] + rowdict["Wavelength"] = u.Quantity([float(fr.min.value), float(fr.max.value)], unit=fr.unit) return rowdict @classmethod def register_values(cls): - adict = {a.Instrument: [('WAVES', 'WIND - Waves')], - a.Source: [('WIND', 'WIND')], - a.Provider: [('NASA', 'NASA Goddard Space Flight Center')], - a.Wavelength: [('*')]} + adict = { + a.Instrument: [("WAVES", "WIND - Waves")], + a.Source: [("WIND", "WIND")], + a.Provider: [("NASA", "NASA Goddard Space Flight Center")], + a.Wavelength: [("*")], + } return adict diff --git a/radiospectra/sources/__init__.py b/radiospectra/sources/__init__.py index f5e5267..7aa2425 100644 --- a/radiospectra/sources/__init__.py +++ b/radiospectra/sources/__init__.py @@ -4,7 +4,7 @@ This is where datasource specific logic is implemented. Each mission should have its own file with one or more classes defined. """ -__all__ = ['CallistoSpectrogram', 'SWavesSpectrogram'] +__all__ = ["CallistoSpectrogram", "SWavesSpectrogram"] from .callisto import CallistoSpectrogram from .swaves import SWavesSpectrogram diff --git a/radiospectra/sources/callisto.py b/radiospectra/sources/callisto.py index a9ddaa0..472ba98 100644 --- a/radiospectra/sources/callisto.py +++ b/radiospectra/sources/callisto.py @@ -16,21 +16,21 @@ from radiospectra.spectrogram import REFERENCE, LinearTimeSpectrogram from radiospectra.util import ConditionalDispatch, minimal_pairs, run_cls -__all__ = ['CallistoSpectrogram'] +__all__ = ["CallistoSpectrogram"] -SUNPY_LT_1 = LooseVersion(__version__) < LooseVersion('1.0') +SUNPY_LT_1 = LooseVersion(__version__) < LooseVersion("1.0") TIME_STR = "%Y%m%d%H%M%S" -DEFAULT_URL = 'http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/' +DEFAULT_URL = "http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/" _DAY = datetime.timedelta(days=1) DATA_SIZE = datetime.timedelta(seconds=15 * 60) def parse_filename(href): - name = href.split('.')[0] + name = href.split(".")[0] try: - inst, date, time, no = name.rsplit('_') + inst, date, time, no = name.rsplit("_") dstart = datetime.datetime.strptime(date + time, TIME_STR) except ValueError: # If the split fails, the file name does not match out @@ -61,10 +61,10 @@ def query(start, end, instruments=None, url=DEFAULT_URL): """ day = datetime.datetime(start.year, start.month, start.day) while day <= end: - directory = url + day.strftime('%Y/%m/%d/') + directory = url + day.strftime("%Y/%m/%d/") opn = urllib.request.urlopen(directory) try: - soup = BeautifulSoup(opn, 'lxml') + soup = BeautifulSoup(opn, "lxml") for link in soup.find_all("a"): href = link.get("href") for prefix, parser in PARSERS: @@ -76,9 +76,7 @@ def query(start, end, instruments=None, url=DEFAULT_URL): continue inst, no, dstart = result - if (instruments is not None and - inst not in instruments and - (inst, int(no)) not in instruments): + if instruments is not None and inst not in instruments and (inst, int(no)) not in instruments: continue dend = dstart + DATA_SIZE @@ -108,7 +106,7 @@ def _parse_header_time(date, time): Returns `~datetime.datetime` object from date and time fields of header. """ if time is not None: - date = date + 'T' + time + date = date + "T" + time if SUNPY_LT_1: time = parse_time(date) @@ -132,6 +130,7 @@ class CallistoSpectrogram(LinearTimeSpectrogram): flag that specifies whether originally in the file the x-axis was frequency """ + # XXX: Determine those from the data. SIGMA_SUM = 75 SIGMA_DELTA_SUM = 20 @@ -143,17 +142,32 @@ class CallistoSpectrogram(LinearTimeSpectrogram): # This needs to list all attributes that need to be # copied to maintain the object and how to handle them. COPY_PROPERTIES = LinearTimeSpectrogram.COPY_PROPERTIES + [ - ('header', REFERENCE), - ('swapped', REFERENCE), - ('axes_header', REFERENCE) + ("header", REFERENCE), + ("swapped", REFERENCE), + ("axes_header", REFERENCE), ] # List of instruments retrieved in July 2012 from # http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/ INSTRUMENTS = { - 'ALASKA', 'ALMATY', 'BIR', 'DARO', 'HB9SCT', 'HUMAIN', - 'HURBANOVO', 'KASI', 'KENYA', 'KRIM', 'MALAYSIA', 'MRT1', - 'MRT2', 'OOTY', 'OSRA', 'SWMC', 'TRIEST', 'UNAM' + "ALASKA", + "ALMATY", + "BIR", + "DARO", + "HB9SCT", + "HUMAIN", + "HURBANOVO", + "KASI", + "KENYA", + "KRIM", + "MALAYSIA", + "MRT1", + "MRT2", + "OOTY", + "OSRA", + "SWMC", + "TRIEST", + "UNAM", } def save(self, filepath): @@ -169,12 +183,8 @@ def save(self, filepath): data = fits.PrimaryHDU(self, header=main_header) # XXX: Update axes header. - freq_col = fits.Column( - name="frequency", format="D8.3", array=self.freq_axis - ) - time_col = fits.Column( - name="time", format="D8.3", array=self.time_axis - ) + freq_col = fits.Column(name="frequency", format="D8.3", array=self.freq_axis) + time_col = fits.Column(name="time", format="D8.3", array=self.time_axis) cols = fits.ColDefs([freq_col, time_col]) table = fits.new_table(cols, header=self.axes_header) @@ -188,11 +198,11 @@ def get_header(self): header = self.header.copy() if self.swapped: - header['NAXIS2'] = self.shape[1] # pylint: disable=E1101 - header['NAXIS1'] = self.shape[0] # pylint: disable=E1101 + header["NAXIS2"] = self.shape[1] # pylint: disable=E1101 + header["NAXIS1"] = self.shape[0] # pylint: disable=E1101 else: - header['NAXIS1'] = self.shape[1] # pylint: disable=E1101 - header['NAXIS2'] = self.shape[0] # pylint: disable=E1101 + header["NAXIS1"] = self.shape[1] # pylint: disable=E1101 + header["NAXIS2"] = self.shape[0] # pylint: disable=E1101 return header @classmethod @@ -211,12 +221,8 @@ def read(cls, filename, **kwargs): axes = fl[1] header = fl[0].header - start = _parse_header_time( - header['DATE-OBS'], header.get('TIME-OBS', header.get('TIME$_OBS')) - ) - end = _parse_header_time( - header['DATE-END'], header.get('TIME-END', header.get('TIME$_END')) - ) + start = _parse_header_time(header["DATE-OBS"], header.get("TIME-OBS", header.get("TIME$_OBS"))) + end = _parse_header_time(header["DATE-END"], header.get("TIME-END", header.get("TIME$_END"))) swapped = "time" not in header["CTYPE1"].lower() @@ -244,11 +250,11 @@ def read(cls, filename, **kwargs): if axes is not None: try: # It's not my fault. Neither supports __contains__ nor .get - tm = axes.data['time'] + tm = axes.data["time"] except KeyError: tm = None try: - fq = axes.data['frequency'] + fq = axes.data["frequency"] except KeyError: fq = None @@ -257,37 +263,57 @@ def read(cls, filename, **kwargs): time_axis = np.squeeze(tm) else: # Otherwise, assume it's linear. - time_axis = \ - np.linspace(0, data.shape[1] - 1) * t_delt + t_init # pylint: disable=E1101 + time_axis = np.linspace(0, data.shape[1] - 1) * t_delt + t_init # pylint: disable=E1101 if fq is not None: freq_axis = np.squeeze(fq) else: - freq_axis = \ - np.linspace(0, data.shape[0] - 1) * f_delt + f_init # pylint: disable=E1101 + freq_axis = np.linspace(0, data.shape[0] - 1) * f_delt + f_init # pylint: disable=E1101 content = header["CONTENT"] instruments = {header["INSTRUME"]} fl.close() return cls( - data, time_axis, freq_axis, start, end, t_init, t_delt, - t_label, f_label, content, instruments, - header, axes.header, swapped + data, + time_axis, + freq_axis, + start, + end, + t_init, + t_delt, + t_label, + f_label, + content, + instruments, + header, + axes.header, + swapped, ) - def __init__(self, data, time_axis, freq_axis, start, end, - t_init=None, t_delt=None, t_label="Time", f_label="Frequency", - content="", instruments=None, header=None, axes_header=None, - swapped=False): + def __init__( + self, + data, + time_axis, + freq_axis, + start, + end, + t_init=None, + t_delt=None, + t_label="Time", + f_label="Frequency", + content="", + instruments=None, + header=None, + axes_header=None, + swapped=False, + ): # Because of how object creation works, there is no avoiding # unused arguments in this case. # pylint: disable=W0613 super(CallistoSpectrogram, self).__init__( - data, time_axis, freq_axis, start, end, - t_init, t_delt, t_label, f_label, - content, instruments + data, time_axis, freq_axis, start, end, t_init, t_delt, t_label, f_label, content, instruments ) self.header = header @@ -304,7 +330,7 @@ def is_datasource_for(cls, header): header : `~astropy.io.fits.Header` main header of the FITS file """ - return header.get('instrume', '').strip() in cls.INSTRUMENTS + return header.get("instrume", "").strip() in cls.INSTRUMENTS def remove_border(self): """ @@ -316,7 +342,7 @@ def remove_border(self): right = self.shape[0] - 1 while self.freq_axis[right] == self.freq_axis[-1]: right -= 1 - return self[left-1:right+2, :] + return self[left - 1 : right + 2, :] @classmethod def read_many(cls, filenames, sort_by=None): @@ -352,8 +378,8 @@ def from_range(cls, instrument, start, end, **kwargs): end of the measurement """ kw = { - 'maxgap': None, - 'fill': cls.JOIN_REPEAT, + "maxgap": None, + "fill": cls.JOIN_REPEAT, } kw.update(kwargs) @@ -369,9 +395,7 @@ def from_range(cls, instrument, start, end, **kwargs): for elem in data: freq_buckets[tuple(elem.freq_axis)].append(elem) try: - return cls.combine_frequencies( - [cls.join_many(elem, **kw) for elem in freq_buckets.values()] - ) + return cls.combine_frequencies([cls.join_many(elem, **kw) for elem in freq_buckets.values()]) except ValueError: raise ValueError("No data found.") @@ -388,10 +412,12 @@ def _to_minimize(a, b): """ Function to be minimized for matching to frequency channels. """ + def _fun(p): if p[0] <= 0.2 or abs(p[1]) >= a.max(): return float("inf") return a - (p[0] * b + p[1]) + return _fun def _homogenize_params(self, other, maxdiff=1): @@ -407,28 +433,17 @@ def _homogenize_params(self, other, maxdiff=1): Threshold for which frequencies are considered equal. """ - pairs_indices = [ - (x, y) for x, y, d in minimal_pairs(self.freq_axis, other.freq_axis) - if d <= maxdiff - ] + pairs_indices = [(x, y) for x, y, d in minimal_pairs(self.freq_axis, other.freq_axis) if d <= maxdiff] - pairs_data = [ - (self[n_one, :], other[n_two, :]) for n_one, n_two in pairs_indices - ] + pairs_data = [(self[n_one, :], other[n_two, :]) for n_one, n_two in pairs_indices] # XXX: Maybe unnecessary. - pairs_data_gaussian = [ - (gaussian_filter1d(a, 15), gaussian_filter1d(b, 15)) - for a, b in pairs_data - ] + pairs_data_gaussian = [(gaussian_filter1d(a, 15), gaussian_filter1d(b, 15)) for a, b in pairs_data] # If we used integer arithmetic, we would accept more invalid # values. pairs_data_gaussian64 = np.float64(pairs_data_gaussian) - least = [ - leastsq(self._to_minimize(a, b), [1, 0])[0] - for a, b in pairs_data_gaussian64 - ] + least = [leastsq(self._to_minimize(a, b), [1, 0])[0] for a, b in pairs_data_gaussian64] factors = [x for x, y in least] constants = [y for x, y in least] @@ -451,9 +466,7 @@ def homogenize(self, other, maxdiff=1): Threshold for which frequencies are considered equal. """ one, two = self._overlap(other) - pairs_indices, factors, constants = one._homogenize_params( - two, maxdiff - ) + pairs_indices, factors, constants = one._homogenize_params(two, maxdiff) # XXX: Maybe (xd.freq_axis[x] + yd.freq_axis[y]) / 2. pairs_freqs = [one.freq_axis[x] for x, y in pairs_indices] @@ -462,9 +475,7 @@ def homogenize(self, other, maxdiff=1): f1 = np.polyfit(pairs_freqs, factors, 3) f2 = np.polyfit(pairs_freqs, constants, 3) - return (one, - two * np.polyval(f1, two.freq_axis)[:, np.newaxis] + - np.polyval(f2, two.freq_axis)[:, np.newaxis]) + return (one, two * np.polyval(f1, two.freq_axis)[:, np.newaxis] + np.polyval(f2, two.freq_axis)[:, np.newaxis]) def extend(self, minutes=15, **kwargs): """ @@ -477,14 +488,10 @@ def extend(self, minutes=15, **kwargs): instrument = next(iter(self.instruments)) if minutes > 0: - data = CallistoSpectrogram.from_range( - instrument, - self.end, self.end + datetime.timedelta(minutes=minutes) - ) + data = CallistoSpectrogram.from_range(instrument, self.end, self.end + datetime.timedelta(minutes=minutes)) else: data = CallistoSpectrogram.from_range( - instrument, - self.start - datetime.timedelta(minutes=-minutes), self.start + instrument, self.start - datetime.timedelta(minutes=-minutes), self.start ) data = data.clip_freq(self.freq_axis[-1], self.freq_axis[0]) @@ -507,11 +514,7 @@ def from_url(cls, url): return cls.read(url) -CallistoSpectrogram._create.add( - run_cls('from_range'), - lambda cls, instrument, start, end: True, - check=False -) +CallistoSpectrogram._create.add(run_cls("from_range"), lambda cls, instrument, start, end: True, check=False) try: CallistoSpectrogram.create.__func__.__doc__ = ( @@ -520,7 +523,9 @@ def from_url(cls, url): Possible signatures: - """ + CallistoSpectrogram._create.generate_docs()) + """ + + CallistoSpectrogram._create.generate_docs() + ) except AttributeError: CallistoSpectrogram.create.__func__.__doc__ = ( """ Create CallistoSpectrogram from given input dispatching to the @@ -528,4 +533,6 @@ def from_url(cls, url): Possible signatures: - """ + CallistoSpectrogram._create.generate_docs()) + """ + + CallistoSpectrogram._create.generate_docs() + ) diff --git a/radiospectra/sources/swaves.py b/radiospectra/sources/swaves.py index b02e823..4cb6721 100644 --- a/radiospectra/sources/swaves.py +++ b/radiospectra/sources/swaves.py @@ -6,23 +6,19 @@ from radiospectra.spectrogram import REFERENCE, LinearTimeSpectrogram from radiospectra.util import ConditionalDispatch, get_day -__all__ = ['SWavesSpectrogram'] +__all__ = ["SWavesSpectrogram"] class SWavesSpectrogram(LinearTimeSpectrogram): _create = ConditionalDispatch.from_existing(LinearTimeSpectrogram._create) create = classmethod(_create.wrapper()) - COPY_PROPERTIES = LinearTimeSpectrogram.COPY_PROPERTIES + [ - ('bg', REFERENCE) - ] + COPY_PROPERTIES = LinearTimeSpectrogram.COPY_PROPERTIES + [("bg", REFERENCE)] @staticmethod def swavesfile_to_date(filename): _, name = os.path.split(filename) - date = name.split('_')[2] - return datetime.datetime( - int(date[0:4]), int(date[4:6]), int(date[6:]) - ) + date = name.split("_")[2] + return datetime.datetime(int(date[0:4]), int(date[4:6]), int(date[6:])) @classmethod def read(cls, filename, **kwargs): @@ -30,35 +26,31 @@ def read(cls, filename, **kwargs): Read in FITS file and return a new SWavesSpectrogram. """ data = np.genfromtxt(filename, skip_header=2) - time_axis = data[:, 0] * 60. + time_axis = data[:, 0] * 60.0 data = data[:, 1:].transpose() header = np.genfromtxt(filename, skip_footer=time_axis.size) freq_axis = header[0, :] bg = header[1, :] start = cls.swavesfile_to_date(filename) end = start + datetime.timedelta(seconds=time_axis[-1]) - t_delt = 60. + t_delt = 60.0 t_init = (start - get_day(start)).seconds - content = '' - t_label = 'Time [UT]' - f_label = 'Frequency [KHz]' + content = "" + t_label = "Time [UT]" + f_label = "Frequency [KHz]" freq_axis = freq_axis[::-1] data = data[::-1, :] - return cls(data, time_axis, freq_axis, start, end, t_init, t_delt, - t_label, f_label, content, bg) + return cls(data, time_axis, freq_axis, start, end, t_init, t_delt, t_label, f_label, content, bg) - def __init__(self, data, time_axis, freq_axis, start, end, - t_init, t_delt, t_label, f_label, content, bg): + def __init__(self, data, time_axis, freq_axis, start, end, t_init, t_delt, t_label, f_label, content, bg): # Because of how object creation works, there is no avoiding # unused arguments in this case. # pylint: disable=W0613 super(SWavesSpectrogram, self).__init__( - data, time_axis, freq_axis, start, end, - t_init, t_delt, t_label, f_label, - content, {"SWAVES"} + data, time_axis, freq_axis, start, end, t_init, t_delt, t_label, f_label, content, {"SWAVES"} ) self.bg = bg @@ -70,7 +62,9 @@ def __init__(self, data, time_axis, freq_axis, start, end, Possible signatures: - """ + SWavesSpectrogram._create.generate_docs()) + """ + + SWavesSpectrogram._create.generate_docs() + ) except AttributeError: SWavesSpectrogram.create.__func__.__doc__ = ( """ Create SWavesSpectrogram from given input dispatching to the @@ -78,4 +72,6 @@ def __init__(self, data, time_axis, freq_axis, start, end, Possible signatures: - """ + SWavesSpectrogram._create.generate_docs()) + """ + + SWavesSpectrogram._create.generate_docs() + ) diff --git a/radiospectra/spectrogram.py b/radiospectra/spectrogram.py index ec65ea2..881b9ee 100644 --- a/radiospectra/spectrogram.py +++ b/radiospectra/spectrogram.py @@ -22,9 +22,9 @@ from radiospectra.spectrum import Spectrum from radiospectra.util import ConditionalDispatch, Parent, common_base, get_day, merge, to_signed -__all__ = ['Spectrogram', 'LinearTimeSpectrogram'] +__all__ = ["Spectrogram", "LinearTimeSpectrogram"] -SUNPY_LT_1 = LooseVersion(__version__) < LooseVersion('1.0') +SUNPY_LT_1 = LooseVersion(__version__) < LooseVersion("1.0") # 1080 because that usually is the maximum vertical pixel count on modern # screens nowadays (2012). @@ -49,14 +49,14 @@ def figure(*args, **kwargs): Compare pyplot.figure. """ kw = { - 'FigureClass': SpectroFigure, + "FigureClass": SpectroFigure, } kw.update(kwargs) return plt.figure(*args, **kw) def _min_delt(arr): - deltas = (arr[:-1] - arr[1:]) + deltas = arr[:-1] - arr[1:] # Multiple values at the same frequency are just thrown away # in the process of linearizaion return deltas[deltas != 0].min() @@ -67,6 +67,7 @@ def _list_formatter(lst, fun=None): Returns a function that takes x, pos and returns fun(lst[x]) if fun is not None, else lst[x] or "" if x is out of range. """ + def _fun(x, pos): x = int(x) if x >= len(lst) or x < 0: @@ -76,6 +77,7 @@ def _fun(x, pos): if fun is None: return elem return fun(elem) + return _fun @@ -106,7 +108,7 @@ def __init__(self, arr, delt=None): self.arr = arr if delt is None: # Nyquist–Shannon sampling theorem - delt = _min_delt(arr.freq_axis) / 2. + delt = _min_delt(arr.freq_axis) / 2.0 self.delt = delt @@ -115,16 +117,13 @@ def __init__(self, arr, delt=None): self.max_mp_delt = np.min(self.midpoints[1:] - self.midpoints[:-1]) - self.freq_axis = np.arange( - self.arr.freq_axis[0], self.arr.freq_axis[-1], -self.delt - ) + self.freq_axis = np.arange(self.arr.freq_axis[0], self.arr.freq_axis[-1], -self.delt) self.time_axis = self.arr.time_axis self.shape = (len(self), arr.data.shape[1]) def __len__(self): - return int(1 + (self.arr.freq_axis[0] - self.arr.freq_axis[-1]) / - self.delt) + return int(1 + (self.arr.freq_axis[0] - self.arr.freq_axis[-1]) / self.delt) def _find(self, arr, item): if item < 0: @@ -164,10 +163,7 @@ def _init(self, data, freqs): self.freqs = freqs def ginput_to_time(self, inp): - return [ - self.data.start + datetime.timedelta(seconds=secs) - for secs in self.ginput_to_time_secs(inp) - ] + return [self.data.start + datetime.timedelta(seconds=secs) for secs in self.ginput_to_time_secs(inp)] def ginput_to_time_secs(self, inp): return np.array([float(self.data.time_axis[x]) for x, y in inp]) @@ -183,9 +179,7 @@ def time_freq(self, points=0): inp = self.ginput(points) min_ = self.ginput_to_time_secs(inp).min() start = self.data.start + datetime.timedelta(seconds=min_) - return TimeFreq( - start, self.ginput_to_time_offset(inp), self.ginput_to_freq(inp) - ) + return TimeFreq(start, self.ginput_to_time_offset(inp), self.ginput_to_freq(inp)) class TimeFreq(object): @@ -230,11 +224,7 @@ def plot(self, time_fmt="%H:%M:%S", **kwargs): axes.plot(self.time, self.freq, **kwargs) xa = axes.get_xaxis() xa.set_major_formatter( - FuncFormatter( - lambda x, pos: ( - self.start + datetime.timedelta(seconds=x) - ).strftime(time_fmt) - ) + FuncFormatter(lambda x, pos: (self.start + datetime.timedelta(seconds=x)).strftime(time_fmt)) ) axes.set_xlabel("Time [UT]") @@ -306,21 +296,22 @@ class Spectrogram(Parent): instruments that recorded the data, may be more than one if it was constructed using combine_frequencies or join_many. """ + # Contrary to what pylint may think, this is not an old-style class. # pylint: disable=E1002,W0142,R0902 # This needs to list all attributes that need to be # copied to maintain the object and how to handle them. COPY_PROPERTIES = [ - ('time_axis', COPY), - ('freq_axis', COPY), - ('instruments', COPY), - ('start', REFERENCE), - ('end', REFERENCE), - ('t_label', REFERENCE), - ('f_label', REFERENCE), - ('content', REFERENCE), - ('t_init', REFERENCE), + ("time_axis", COPY), + ("freq_axis", COPY), + ("instruments", COPY), + ("start", REFERENCE), + ("end", REFERENCE), + ("t_label", REFERENCE), + ("f_label", REFERENCE), + ("content", REFERENCE), + ("t_init", REFERENCE), ] _create = ConditionalDispatch.from_existing(Parent._create) @@ -336,9 +327,7 @@ def _get_params(self): """ Implementation detail. """ - return { - name: getattr(self, name) for name, _ in self.COPY_PROPERTIES - } + return {name: getattr(self, name) for name, _ in self.COPY_PROPERTIES} def _slice(self, y_range, x_range): """ @@ -355,18 +344,15 @@ def _slice(self, y_range, x_range): eoffset -= 1 eoffset = int(eoffset) - params.update({ - 'time_axis': self.time_axis[ - x_range.start:x_range.stop:x_range.step - ] - self.time_axis[soffset], - 'freq_axis': self.freq_axis[ - y_range.start:y_range.stop:y_range.step], - 'start': self.start + datetime.timedelta( - seconds=self.time_axis[soffset]), - 'end': self.start + datetime.timedelta( - seconds=self.time_axis[eoffset]), - 't_init': self.t_init + self.time_axis[soffset], - }) + params.update( + { + "time_axis": self.time_axis[x_range.start : x_range.stop : x_range.step] - self.time_axis[soffset], + "freq_axis": self.freq_axis[y_range.start : y_range.stop : y_range.step], + "start": self.start + datetime.timedelta(seconds=self.time_axis[soffset]), + "end": self.start + datetime.timedelta(seconds=self.time_axis[eoffset]), + "t_init": self.t_init + self.time_axis[soffset], + } + ) return self.__class__(data, **params) def _with_data(self, data): @@ -374,9 +360,19 @@ def _with_data(self, data): new.data = data return new - def __init__(self, data, time_axis, freq_axis, start, end, t_init=None, - t_label="Time", f_label="Frequency", content="", - instruments=None): + def __init__( + self, + data, + time_axis, + freq_axis, + start, + end, + t_init=None, + t_label="Time", + f_label="Frequency", + content="", + instruments=None, + ): # Because of how object creation works, there is no avoiding # unused arguments in this case. self.data = data @@ -411,11 +407,7 @@ def time_formatter(self, x, pos): x = int(x) if x >= len(self.time_axis) or x < 0: return "" - return self.format_time( - self.start + datetime.timedelta( - seconds=float(self.time_axis[x]) - ) - ) + return self.format_time(self.start + datetime.timedelta(seconds=float(self.time_axis[x]))) @staticmethod def format_time(time): @@ -453,9 +445,19 @@ def peek(self, *args, **kwargs): plt.show() return ret - def plot(self, figure=None, overlays=[], colorbar=True, vmin=None, - vmax=None, linear=True, showz=True, yres=DEFAULT_YRES, - max_dist=None, **matplotlib_args): + def plot( + self, + figure=None, + overlays=[], + colorbar=True, + vmin=None, + vmax=None, + linear=True, + showz=True, + yres=DEFAULT_YRES, + max_dist=None, + **matplotlib_args + ): """ Plot spectrogram onto figure. @@ -493,16 +495,11 @@ def plot(self, figure=None, overlays=[], colorbar=True, vmin=None, if linear: delt = yres if delt is not None: - delt = max( - (self.freq_axis[0] - self.freq_axis[-1]) / (yres - 1), - _min_delt(self.freq_axis) / 2. - ) + delt = max((self.freq_axis[0] - self.freq_axis[-1]) / (yres - 1), _min_delt(self.freq_axis) / 2.0) delt = float(delt) data = _LinearView(self.clip_values(vmin, vmax), delt) - freqs = np.arange( - self.freq_axis[0], self.freq_axis[-1], -data.delt - ) + freqs = np.arange(self.freq_axis[0], self.freq_axis[-1], -data.delt) else: data = np.array(self.clip_values(vmin, vmax)) freqs = self.freq_axis @@ -515,8 +512,8 @@ def plot(self, figure=None, overlays=[], colorbar=True, vmin=None, axes = figure.add_subplot(111) params = { - 'origin': 'lower', - 'aspect': 'auto', + "origin": "lower", + "aspect": "auto", } params.update(matplotlib_args) if linear and max_dist is not None: @@ -528,14 +525,12 @@ def plot(self, figure=None, overlays=[], colorbar=True, vmin=None, xa = axes.get_xaxis() ya = axes.get_yaxis() - xa.set_major_formatter( - FuncFormatter(self.time_formatter) - ) + xa.set_major_formatter(FuncFormatter(self.time_formatter)) if linear: # Start with a number that is divisible by 5. init = (self.freq_axis[0] % 5) / data.delt - nticks = 15. + nticks = 15.0 # Calculate MHz difference between major ticks. dist = (self.freq_axis[0] - self.freq_axis[-1]) / nticks # Round to next multiple of 10, at least ten. @@ -544,40 +539,33 @@ def plot(self, figure=None, overlays=[], colorbar=True, vmin=None, # our distance between the major ticks into image space by dividing # it by data.delt. - ya.set_major_locator( - IndexLocator( - dist / data.delt, init - ) - ) - ya.set_minor_locator( - IndexLocator( - dist / data.delt / 10, init - ) - ) + ya.set_major_locator(IndexLocator(dist / data.delt, init)) + ya.set_minor_locator(IndexLocator(dist / data.delt / 10, init)) def freq_fmt(x, pos): # This is necessary because matplotlib somehow tries to get # the mid-point of the row, which we do not need here. x = x + 0.5 return self.format_freq(self.freq_axis[0] - x * data.delt) + else: freq_fmt = _list_formatter(freqs, self.format_freq) ya.set_major_locator(MaxNLocator(integer=True, steps=[1, 5, 10])) - ya.set_major_formatter( - FuncFormatter(freq_fmt) - ) + ya.set_major_formatter(FuncFormatter(freq_fmt)) axes.set_xlabel(self.t_label) axes.set_ylabel(self.f_label) # figure.suptitle(self.content) figure.suptitle( - ' '.join([ - get_day(self.start).strftime("%d %b %Y"), - 'Radio flux density', - '(' + ', '.join(self.instruments) + ')', - ]) + " ".join( + [ + get_day(self.start).strftime("%d %b %Y"), + "Radio flux density", + "(" + ", ".join(self.instruments) + ")", + ] + ) ) for tl in xa.get_ticklabels(): @@ -588,8 +576,7 @@ def freq_fmt(x, pos): figure.subplots_adjust(left=0.2) if showz: - axes.format_coord = self._mk_format_coord( - data, figure.gca().format_coord) + axes.format_coord = self._mk_format_coord(data, figure.gca().format_coord) if colorbar: if len(figure.axes) > 1: @@ -620,16 +607,15 @@ def __getitem__(self, key): # ) return np.array(self.data[key]) elif isinstance(key[0], slice): - return Spectrum( - self.data[key], - self.freq_axis[key[0].start:key[0].stop:key[0].step] - ) + return Spectrum(self.data[key], self.freq_axis[key[0].start : key[0].stop : key[0].step]) return self.data[int(key)] def clip_freq(self, vmin=None, vmax=None): """ - Return a new spectrogram only consisting of frequencies in the interval + Return a new spectrogram only consisting of frequencies in the + interval. + [vmin, vmax]. Parameters @@ -650,7 +636,7 @@ def clip_freq(self, vmin=None, vmax=None): while self.freq_axis[right] < vmin: right -= 1 - return self[left:right + 1, :] + return self[left : right + 1, :] def auto_find_background(self, amount=0.05): """ @@ -667,7 +653,7 @@ def auto_find_background(self, amount=0.05): # pylint: disable=E1101,E1103 data = self.data.astype(to_signed(self.dtype)) # Subtract average value from every frequency channel. - tmp = (data - np.average(self.data, 1).reshape(self.shape[0], 1)) + tmp = data - np.average(self.data, 1).reshape(self.shape[0], 1) # Get standard deviation at every point of time. # Need to convert because otherwise this class's __getitem__ # is used which assumes two-dimensionality. @@ -676,7 +662,7 @@ def auto_find_background(self, amount=0.05): # Get indices of values with lowest standard deviation. cand = sorted(list(range(self.shape[1])), key=lambda y: sdevs[y]) # Only consider the best 5 %. - return cand[:max(1, int(amount * len(cand)))] + return cand[: max(1, int(amount * len(cand)))] def auto_const_bg(self): """ @@ -708,7 +694,7 @@ def randomized_auto_const_bg(self, amount): # pylint: disable=E1101,E1103 data = self.data.astype(to_signed(self.dtype)) # Subtract average value from every frequency channel. - tmp = (data - np.average(self.data, 1).reshape(self.shape[0], 1)) + tmp = data - np.average(self.data, 1).reshape(self.shape[0], 1) # Get standard deviation at every point of time. # Need to convert because otherwise this class's __getitem__ # is used which assumes two-dimensionality. @@ -718,7 +704,7 @@ def randomized_auto_const_bg(self, amount): # Get indices of values with lowest standard deviation. cand = sorted(list(range(amount)), key=lambda y: sdevs[y]) # Only consider the best 5 %. - realcand = cand[:max(1, int(0.05 * len(cand)))] + realcand = cand[: max(1, int(0.05 * len(cand)))] # Average the best 5 % bg = np.average(self[:, [cols[r] for r in realcand]], 1) @@ -762,7 +748,7 @@ def clip_values(self, vmin=None, vmax=None, out=None): return self._with_data(self.data.clip(vmin, vmax, out)) - def rescale(self, vmin=0, vmax=1, dtype=np.dtype('float32')): + def rescale(self, vmin=0, vmax=1, dtype=np.dtype("float32")): """ Rescale intensities to [vmin, vmax]. Note that vmin ≠ vmax and spectrogram.min() ≠ spectrogram.max(). @@ -782,8 +768,10 @@ def rescale(self, vmin=0, vmax=1, dtype=np.dtype('float32')): raise ValueError("Spectrogram needs to contain distinct values.") data = self.data.astype(dtype) # pylint: disable=E1101 return self._with_data( - vmin + (vmax - vmin) * (data - self.data.min()) / # pylint: disable=E1101 - (self.data.max() - self.data.min()) # pylint: disable=E1101 + vmin + + (vmax - vmin) + * (data - self.data.min()) + / (self.data.max() - self.data.min()) # pylint: disable=E1101 # pylint: disable=E1101 ) def interpolate(self, frequency): @@ -823,34 +811,25 @@ def linearize_freqs(self, delta_freq=None): """ if delta_freq is None: # Nyquist–Shannon sampling theorem - delta_freq = _min_delt(self.freq_axis) / 2. - nsize = int((self.freq_axis.max() - self.freq_axis.min()) / - delta_freq + 1) + delta_freq = _min_delt(self.freq_axis) / 2.0 + nsize = int((self.freq_axis.max() - self.freq_axis.min()) / delta_freq + 1) new = np.zeros((int(nsize), self.shape[1]), dtype=self.data.dtype) freqs = self.freq_axis - self.freq_axis.max() freqs = freqs / delta_freq midpoints = np.round((freqs[:-1] + freqs[1:]) / 2) - fillto = np.concatenate( - [midpoints - 1, np.round([freqs[-1]]) - 1] - ) - fillfrom = np.concatenate( - [np.round([freqs[0]]), midpoints - 1] - ) + fillto = np.concatenate([midpoints - 1, np.round([freqs[-1]]) - 1]) + fillfrom = np.concatenate([np.round([freqs[0]]), midpoints - 1]) fillto = np.abs(fillto) fillfrom = np.abs(fillfrom) for row, from_, to_ in zip(self, fillfrom, fillto): - new[int(from_): int(to_)] = row + new[int(from_) : int(to_)] = row vrs = self._get_params() - vrs.update({ - 'freq_axis': np.linspace( - self.freq_axis.max(), self.freq_axis.min(), nsize - ) - }) + vrs.update({"freq_axis": np.linspace(self.freq_axis.max(), self.freq_axis.min(), nsize)}) return self.__class__(new, **vrs) @@ -904,7 +883,7 @@ def format_coord(x, y): else: pixel = "" - return '{!s} z={!s}'.format(fmt_coord(x, y), pixel) + return "{!s} z={!s}".format(fmt_coord(x, y), pixel) return format_coord @@ -918,25 +897,36 @@ class LinearTimeSpectrogram(Spectrogram): t_delt : float difference between the items on the time axis """ + # pylint: disable=E1002 COPY_PROPERTIES = Spectrogram.COPY_PROPERTIES + [ - ('t_delt', REFERENCE), + ("t_delt", REFERENCE), ] - def __init__(self, data, time_axis, freq_axis, start, end, - t_init=None, t_delt=None, t_label="Time", f_label="Frequency", - content="", instruments=None): + def __init__( + self, + data, + time_axis, + freq_axis, + start, + end, + t_init=None, + t_delt=None, + t_label="Time", + f_label="Frequency", + content="", + instruments=None, + ): if t_delt is None: t_delt = _min_delt(freq_axis) super(LinearTimeSpectrogram, self).__init__( - data, time_axis, freq_axis, start, end, t_init, t_label, f_label, - content, instruments + data, time_axis, freq_axis, start, end, t_init, t_label, f_label, content, instruments ) self.t_delt = t_delt @staticmethod - def make_array(shape, dtype=np.dtype('float32')): + def make_array(shape, dtype=np.dtype("float32")): """ Function to create an array with shape and dtype. @@ -960,11 +950,7 @@ def memmap(filename): filename : str File to store the memory mapped array in. """ - return ( - lambda shape, dtype=np.dtype('float32'): np.memmap( - filename, mode="write", shape=shape, dtype=dtype - ) - ) + return lambda shape, dtype=np.dtype("float32"): np.memmap(filename, mode="write", shape=shape, dtype=dtype) def resample_time(self, new_delt): """ @@ -985,21 +971,20 @@ def resample_time(self, new_delt): data = ndimage.zoom(self.data, (1, new_size / self.shape[1])) # pylint: disable=E1101 params = self._get_params() - params.update({ - 'time_axis': np.linspace( - self.time_axis[0], - self.time_axis[int((new_size - 1) * new_delt / self.t_delt)], - new_size - ), - 't_delt': new_delt, - }) + params.update( + { + "time_axis": np.linspace( + self.time_axis[0], self.time_axis[int((new_size - 1) * new_delt / self.t_delt)], new_size + ), + "t_delt": new_delt, + } + ) return self.__class__(data, **params) JOIN_REPEAT = object() @classmethod - def join_many(cls, specs, mk_arr=None, nonlinear=False, - maxgap=0, fill=JOIN_REPEAT): + def join_many(cls, specs, mk_arr=None, nonlinear=False, maxgap=0, fill=JOIN_REPEAT): """ Produce new Spectrogram that contains spectrograms joined together in time. @@ -1049,11 +1034,7 @@ def join_many(cls, specs, mk_arr=None, nonlinear=False, xs = [] last = data for elem in specs[1:]: - e_init = ( - SECONDS_PER_DAY * ( - get_day(elem.start) - get_day(start_day) - ).days + elem.t_init - ) + e_init = SECONDS_PER_DAY * (get_day(elem.start) - get_day(start_day)).days + elem.t_init x = int((e_init - last.t_init) / min_delt) xs.append(x) diff = last.shape[1] - x @@ -1100,41 +1081,36 @@ def join_many(cls, specs, mk_arr=None, nonlinear=False, else: filler[:] = fill minimum = e_time_axis[-1] - e_time_axis = np.concatenate([ - e_time_axis, - np.linspace( - minimum + min_delt, - minimum + diff * min_delt, - diff - ) - ]) + e_time_axis = np.concatenate( + [e_time_axis, np.linspace(minimum + min_delt, minimum + diff * min_delt, diff)] + ) elem = np.concatenate([elem, filler], 1) - arr[:, sx:sx + x] = elem[:, :x] + arr[:, sx : sx + x] = elem[:, :x] if diff > 0: if mask is None: mask = np.zeros((data.shape[0], size), dtype=np.uint8) - mask[:, sx + x - diff:sx + x] = 1 - time_axis[sx:sx + x] = e_time_axis[:x] + data.t_delt * (sx + sd) + mask[:, sx + x - diff : sx + x] = 1 + time_axis[sx : sx + x] = e_time_axis[:x] + data.t_delt * (sx + sd) if nonlinear: sd += max(0, diff) sx += x params = { - 'time_axis': time_axis, - 'freq_axis': data.freq_axis, - 'start': data.start, - 'end': specs[-1].end, - 't_delt': data.t_delt, - 't_init': data.t_init, - 't_label': data.t_label, - 'f_label': data.f_label, - 'content': data.content, - 'instruments': _union(spec.instruments for spec in specs), + "time_axis": time_axis, + "freq_axis": data.freq_axis, + "start": data.start, + "end": specs[-1].end, + "t_delt": data.t_delt, + "t_init": data.t_init, + "t_label": data.t_label, + "f_label": data.f_label, + "content": data.content, + "instruments": _union(spec.instruments for spec in specs), } if mask is not None: arr = ma.array(arr, mask=mask) if nonlinear: - del params['t_delt'] + del params["t_delt"] return Spectrogram(arr, **params) return common_base(specs)(arr, **params) @@ -1177,7 +1153,7 @@ def intersect_time(specs): # XXX: Could do without resampling by using # sp.t_init below, not sure if good idea. specs = [sp.resample_time(delt) for sp in specs] - cut = [sp[:, int((start - sp.t_init) / delt):] for sp in specs] + cut = [sp[:, int((start - sp.t_init) / delt) :] for sp in specs] length = min(sp.shape[1] for sp in cut) return [sp[:, :length] for sp in cut] @@ -1207,25 +1183,22 @@ def combine_frequencies(cls, specs): freq_axis = np.zeros((fsize,)) - for n, (data, row) in enumerate(merge( - [ - [(sp, n) for n in range(sp.shape[0])] for sp in specs - ], - key=lambda x: x[0].freq_axis[x[1]] - )): + for n, (data, row) in enumerate( + merge([[(sp, n) for n in range(sp.shape[0])] for sp in specs], key=lambda x: x[0].freq_axis[x[1]]) + ): new[n, :] = data[row, :] freq_axis[n] = data.freq_axis[row] params = { - 'time_axis': one.time_axis, # Should be equal - 'freq_axis': freq_axis, - 'start': one.start, - 'end': one.end, - 't_delt': one.t_delt, - 't_init': one.t_init, - 't_label': one.t_label, - 'f_label': one.f_label, - 'content': one.content, - 'instruments': _union(spec.instruments for spec in specs) + "time_axis": one.time_axis, # Should be equal + "freq_axis": freq_axis, + "start": one.start, + "end": one.end, + "t_delt": one.t_delt, + "t_init": one.t_init, + "t_label": one.t_label, + "f_label": one.f_label, + "content": one.content, + "instruments": _union(spec.instruments for spec in specs), } return common_base(specs)(new, **params) @@ -1279,12 +1252,9 @@ def in_interval(self, start=None, end=None): except ValueError: # XXX: We could do better than that. if get_day(self.start) != get_day(self.end): - raise TypeError( - "Time ambiguous because data spans over more than one day" - ) + raise TypeError("Time ambiguous because data spans over more than one day") start = datetime.datetime( - self.start.year, self.start.month, self.start.day, - *list(map(int, start.split(":"))) + self.start.year, self.start.month, self.start.day, *list(map(int, start.split(":"))) ) start = self.time_to_x(start) if end is not None: @@ -1295,12 +1265,9 @@ def in_interval(self, start=None, end=None): end = parse_time(end).datetime except ValueError: if get_day(self.start) != get_day(self.end): - raise TypeError( - "Time ambiguous because data spans over more than one day" - ) + raise TypeError("Time ambiguous because data spans over more than one day") end = datetime.datetime( - self.start.year, self.start.month, self.start.day, - *list(map(int, end.split(":"))) + self.start.year, self.start.month, self.start.day, *list(map(int, end.split(":"))) ) end = self.time_to_x(end) if start: diff --git a/radiospectra/spectrogram2/__init__.py b/radiospectra/spectrogram2/__init__.py index 95bc49c..b458781 100644 --- a/radiospectra/spectrogram2/__init__.py +++ b/radiospectra/spectrogram2/__init__.py @@ -1,6 +1,7 @@ """ -The spectrogram2 module aims to provide a more sunpy-like interface to radiospectra data similar to -that of `~sunpy.map.Map` and `~sunpy.timeseries.TimeSeries`. +The spectrogram2 module aims to provide a more sunpy-like interface to +radiospectra data similar to that of `~sunpy.map.Map` and +`~sunpy.timeseries.TimeSeries`. """ from radiospectra.spectrogram2.sources import ( diff --git a/radiospectra/spectrogram2/sources.py b/radiospectra/spectrogram2/sources.py index 0d65a7d..730922d 100644 --- a/radiospectra/spectrogram2/sources.py +++ b/radiospectra/spectrogram2/sources.py @@ -1,16 +1,14 @@ - import astropy.units as u from astropy.coordinates.earth import EarthLocation from radiospectra.spectrogram2.spectrogram import GenericSpectrogram -__all__ = ['SWAVESSpectrogram', 'RFSSpectrogram', 'CALISTOSpectrogram', 'EOVSASpectrogram', - 'RSTNSpectrogram'] +__all__ = ["SWAVESSpectrogram", "RFSSpectrogram", "CALISTOSpectrogram", "EOVSASpectrogram", "RSTNSpectrogram"] class SWAVESSpectrogram(GenericSpectrogram): """ - STEREO Waves or S/WAVES, SWAVES Spectrogram + STEREO Waves or S/WAVES, SWAVES Spectrogram. Examples -------- @@ -26,24 +24,25 @@ class SWAVESSpectrogram(GenericSpectrogram): >>> spec.plot() #doctest: +REMOTE_DATA """ + def __init__(self, data, meta, **kwargs): super().__init__(meta=meta, data=data, **kwargs) @property def receiver(self): """ - The name of the receiver + The name of the receiver. """ - return self.meta['receiver'] + return self.meta["receiver"] @classmethod def is_datasource_for(cls, data, meta, **kwargs): - return meta['instrument'] == 'swaves' + return meta["instrument"] == "swaves" class WAVESSpectrogram(GenericSpectrogram): """ - Wind Waves Spectrogram + Wind Waves Spectrogram. Examples -------- @@ -59,31 +58,32 @@ class WAVESSpectrogram(GenericSpectrogram): >>> spec.plot() #doctest: +REMOTE_DATA """ + def __init__(self, data, meta, **kwargs): super().__init__(meta=meta, data=data, **kwargs) @property def receiver(self): """ - The name of the receiver + The name of the receiver. """ - return self.meta['receiver'] + return self.meta["receiver"] @property def background(self): """ - The background subtracted from the data + The background subtracted from the data. """ return self.meta.bg @classmethod def is_datasource_for(cls, data, meta, **kwargs): - return meta.get('instrument', None) == 'WAVES' + return meta.get("instrument", None) == "WAVES" class RFSSpectrogram(GenericSpectrogram): """ - Parker Solar Probe FIELDS/Radio Frequency Spectrometer (RFS) Spectrogram + Parker Solar Probe FIELDS/Radio Frequency Spectrometer (RFS) Spectrogram. >>> import radiospectra.net >>> from sunpy.net import Fido, attrs as a @@ -97,26 +97,28 @@ class RFSSpectrogram(GenericSpectrogram): >>> spec.plot() #doctest: +REMOTE_DATA """ + def __init__(self, data, meta, **kwargs): super().__init__(meta=meta, data=data, **kwargs) @property def level(self): - return self.meta['cdf_meta']['Data_type'].split('>')[0] + return self.meta["cdf_meta"]["Data_type"].split(">")[0] @property def version(self): - return int(self.meta['cdf_meta']['Data_version']) + return int(self.meta["cdf_meta"]["Data_version"]) @classmethod def is_datasource_for(cls, data, meta, **kwargs): - return (meta['observatory'] == 'PSP' and meta['instrument'] == 'FIELDS/RFS' - and meta['detector'] in ('lfr', 'hfr')) + return ( + meta["observatory"] == "PSP" and meta["instrument"] == "FIELDS/RFS" and meta["detector"] in ("lfr", "hfr") + ) class CALISTOSpectrogram(GenericSpectrogram): """ - CALISTO Spectrogram from the e-CALISTO network + CALISTO Spectrogram from the e-CALISTO network. Examples -------- @@ -132,26 +134,25 @@ class CALISTOSpectrogram(GenericSpectrogram): >>> spec.plot() #doctest: +REMOTE_DATA """ + def __init__(self, data, meta, **kwargs): super().__init__(meta=meta, data=data, **kwargs) @property def observatory_location(self): - lat = self.meta['fits_meta']['OBS_LAT'] * u.deg * 1.0 if \ - self.meta['fits_meta']['OBS_LAC'] == 'N' else -1.0 - lon = self.meta['fits_meta']['OBS_LON'] * u.deg * 1.0 if \ - self.meta['fits_meta']['OBS_LOC'] == 'E' else -1.0 - height = self.meta['fits_meta']['OBS_ALT'] * u.m + lat = self.meta["fits_meta"]["OBS_LAT"] * u.deg * 1.0 if self.meta["fits_meta"]["OBS_LAC"] == "N" else -1.0 + lon = self.meta["fits_meta"]["OBS_LON"] * u.deg * 1.0 if self.meta["fits_meta"]["OBS_LOC"] == "E" else -1.0 + height = self.meta["fits_meta"]["OBS_ALT"] * u.m return EarthLocation(lat=lat, lon=lon, height=height) @classmethod def is_datasource_for(cls, data, meta, **kwargs): - return meta['instrument'] == 'e-CALLISTO' or meta['detector'] == 'e-CALLISTO' + return meta["instrument"] == "e-CALLISTO" or meta["detector"] == "e-CALLISTO" class EOVSASpectrogram(GenericSpectrogram): """ - Extend Owen Valley Array (EOVSA) Spectrogram + Extend Owen Valley Array (EOVSA) Spectrogram. Examples -------- @@ -165,16 +166,17 @@ class EOVSASpectrogram(GenericSpectrogram): >>> spec.plot() #doctest: +REMOTE_DATA """ + def __init__(self, data, meta, **kwargs): super().__init__(meta=meta, data=data, **kwargs) @property def polarisation(self): - return self.meta['fits_meta']['POLARIZA'] + return self.meta["fits_meta"]["POLARIZA"] @classmethod def is_datasource_for(cls, data, meta, **kwargs): - return meta['instrument'] == 'EOVSA' or meta['detector'] == 'EOVSA' + return meta["instrument"] == "EOVSA" or meta["detector"] == "EOVSA" # TODO fix time gaps for plots need to render them as gaps # can prob do when generateing proper pcolormesh gird but then prob doesn't belong here @@ -182,7 +184,7 @@ def is_datasource_for(cls, data, meta, **kwargs): class RSTNSpectrogram(GenericSpectrogram): """ - Radio Solar Telescope Network + Radio Solar Telescope Network. Examples -------- @@ -199,4 +201,4 @@ class RSTNSpectrogram(GenericSpectrogram): @classmethod def is_datasource_for(cls, data, meta, **kwargs): - return meta['instrument'] == 'RSTN' + return meta["instrument"] == "RSTN" diff --git a/radiospectra/spectrogram2/spectrogram.py b/radiospectra/spectrogram2/spectrogram.py index 1ad504b..a3032b9 100644 --- a/radiospectra/spectrogram2/spectrogram.py +++ b/radiospectra/spectrogram2/spectrogram.py @@ -38,13 +38,14 @@ SUPPORTED_ARRAY_TYPES = (np.ndarray,) try: import dask.array + SUPPORTED_ARRAY_TYPES += (dask.array.Array,) except ImportError: pass quantity_support() -__all__ = ['SpectrogramFactory', 'Spectrogram', 'GenericSpectrogram'] +__all__ = ["SpectrogramFactory", "Spectrogram", "GenericSpectrogram"] class NoSpectrogramInFileError(Exception): @@ -85,6 +86,7 @@ def is_dir(path): def possibly_a_path(obj): """ Check if ``obj`` can be coerced into a pathlib.Path object. + Does *not* check if the path exists. """ try: @@ -112,13 +114,13 @@ def parse_path(path, f, **kwargs): List of files read in by ``f``. """ if not isinstance(path, os.PathLike): - raise ValueError('path must be a pathlib.Path object') + raise ValueError("path must be a pathlib.Path object") path = path.expanduser() if is_file(path): return [f(path, **kwargs)] elif is_dir(path): read_files = [] - for afile in sorted(path.glob('*')): + for afile in sorted(path.glob("*")): read_files += f(afile, **kwargs) return read_files elif glob.glob(str(path)): @@ -127,13 +129,14 @@ def parse_path(path, f, **kwargs): read_files += f(afile, **kwargs) return read_files else: - raise ValueError(f'Did not find any files at {path}') + raise ValueError(f"Did not find any files at {path}") class PcolormeshPlotMixin: """ Class provides plotting functions using `~pcolormesh`. """ + def plot(self, axes=None, **kwargs): """ Plot the spectrogram. @@ -153,20 +156,18 @@ def plot(self, axes=None, **kwargs): else: fig = axes.get_figure() - if hasattr(self.data, 'value'): + if hasattr(self.data, "value"): data = self.data.value else: data = self.data - title = f'{self.observatory}, {self.instrument}' + title = f"{self.observatory}, {self.instrument}" if self.instrument != self.detector: - title = f'{title}, {self.detector}' + title = f"{title}, {self.detector}" axes.set_title(title) - axes.plot(self.times.datetime[[0, -1]], self.frequencies[[0, -1]], - linestyle='None', marker='None') - axes.pcolormesh(self.times.datetime, self.frequencies.value, data[:-1, :-1], - shading='auto', **kwargs) + axes.plot(self.times.datetime[[0, -1]], self.frequencies[[0, -1]], linestyle="None", marker="None") + axes.pcolormesh(self.times.datetime, self.frequencies.value, data[:-1, :-1], shading="auto", **kwargs) axes.set_xlim(self.times.datetime[0], self.times.datetime[-1]) locator = mdates.AutoDateLocator(minticks=4, maxticks=8) formatter = mdates.ConciseDateFormatter(locator) @@ -179,11 +180,12 @@ class NonUniformImagePlotMixin: """ Class provides plotting functions using `NonUniformImage` """ + def plotim(self, fig=None, axes=None, **kwargs): if axes is None: fig, axes = plt.subplots() - im = NonUniformImage(axes, interpolation='none', **kwargs) + im = NonUniformImage(axes, interpolation="none", **kwargs) im.set_data(mdates.date2num(self.times.datetime), self.frequencies.value, self.data) axes.images.append(im) @@ -199,11 +201,12 @@ class GenericSpectrogram(PcolormeshPlotMixin, NonUniformImagePlotMixin): data : `numpy.ndarray` The spectrogram data itself a 2D array. """ + _registry = {} def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) - if hasattr(cls, 'is_datasource_for'): + if hasattr(cls, "is_datasource_for"): cls._registry[cls] = cls.is_datasource_for def __init__(self, data, meta, **kwargs): @@ -217,79 +220,81 @@ def observatory(self): """ The name of the observatory which recorded the spectrogram. """ - return self.meta['observatory'].upper() + return self.meta["observatory"].upper() @property def instrument(self): """ The name of the instrument which recorded the spectrogram. """ - return self.meta['instrument'].upper() + return self.meta["instrument"].upper() @property def detector(self): """ The detector which recorded the spectrogram. """ - return self.meta['detector'].upper() + return self.meta["detector"].upper() @property def start_time(self): """ The start time of the spectrogram. """ - return self.meta['start_time'] + return self.meta["start_time"] @property def end_time(self): """ The end time of the spectrogram. """ - return self.meta['end_time'] + return self.meta["end_time"] @property def wavelength(self): """ The wavelength range of the spectrogram. """ - return self.meta['wavelength'] + return self.meta["wavelength"] @property def times(self): """ The times of the spectrogram. """ - return self.meta['times'] + return self.meta["times"] @property def frequencies(self): """ The frequencies of the spectrogram. """ - return self.meta['freqs'] + return self.meta["freqs"] def _validate_meta(self): """ Validates the meta-information associated with a Spectrogram. This method includes very basic validation checks which apply to - all of the kinds of files that radiospectra can read. Datasource-specific - validation should be handled in the relevant file in the - radiospectra.spectrogram2.sources file. + all of the kinds of files that radiospectra can read. + Datasource-specific validation should be handled in the relevant + file in the radiospectra.spectrogram2.sources file. """ - msg = 'Spectrogram coordinate units for {} axis not present in metadata.' + msg = "Spectrogram coordinate units for {} axis not present in metadata." err_message = [] - for i, ax in enumerate(['times', 'freqs']): + for i, ax in enumerate(["times", "freqs"]): if self.meta.get(ax) is None: err_message.append(msg.format(ax)) if err_message: - raise SpectraMetaValidationError('\n'.join(err_message)) + raise SpectraMetaValidationError("\n".join(err_message)) def __repr__(self): - return (f'<{self.__class__.__name__} {self.observatory}, {self.instrument}, {self.detector}' - f' {self.wavelength.min} - {self.wavelength.max},' - f' {self.start_time.isot} to {self.end_time.isot}>') + return ( + f"<{self.__class__.__name__} {self.observatory}, {self.instrument}, {self.detector}" + f" {self.wavelength.min} - {self.wavelength.max}," + f" {self.start_time.isot} to {self.end_time.isot}>" + ) class SpectrogramFactory(BasicRegistrationFactory): @@ -306,6 +311,7 @@ class SpectrogramFactory(BasicRegistrationFactory): `radiospectra.spectrogram2.Spectrogram` The spectrogram for the give file """ + def _validate_meta(self, meta): """ Validate a meta argument. @@ -319,8 +325,9 @@ def _validate_meta(self, meta): def _parse_args(self, *args, silence_errors=False, **kwargs): """ - Parses an args list into data-header pairs. - args can contain any mixture of the following entries: + Parses an args list into data-header pairs. args can contain any + mixture of the following entries: + * tuples of data,header * data, header not in a tuple * data, wcs object in a tuple @@ -373,8 +380,7 @@ def _parse_args(self, *args, silence_errors=False, **kwargs): except NoSpectrogramInFileError as e: if not silence_errors: raise - warnings.warn(f"One of the arguments failed to parse with error: {e}", - SunpyUserWarning) + warnings.warn(f"One of the arguments failed to parse with error: {e}", SunpyUserWarning) return data_header_pairs @@ -383,6 +389,7 @@ def _parse_args(self, *args, silence_errors=False, **kwargs): def _parse_arg(self, arg, **kwargs): """ Take a factory input and parse into (data, header) pairs. + Must return a list, even if only one pair is returned. """ raise ValueError(f"Invalid input: {arg}") @@ -413,12 +420,12 @@ def _parse_path(self, arg, **kwargs): def __call__(self, *args, silence_errors=False, **kwargs): """ - Method for running the factory. Takes arbitrary arguments and - keyword arguments and passes them to a sequence of pre-registered types - to determine which is the correct spectrogram-type to build. - Arguments args and kwargs are passed through to the validation - function and to the constructor for the final type. For spectrogram types, - validation function must take a data-header pair as an argument. + Method for running the factory. Takes arbitrary arguments and keyword + arguments and passes them to a sequence of pre-registered types to + determine which is the correct spectrogram-type to build. Arguments + args and kwargs are passed through to the validation function and to + the constructor for the final type. For spectrogram types, validation + function must take a data-header pair as an argument. Parameters ---------- @@ -446,15 +453,13 @@ def __call__(self, *args, silence_errors=False, **kwargs): try: new_map = self._check_registered_widgets(data, meta, **kwargs) new_maps.append(new_map) - except (NoMatchError, MultipleMatchError, - ValidationFunctionError, SpectraMetaValidationError) as e: + except (NoMatchError, MultipleMatchError, ValidationFunctionError, SpectraMetaValidationError) as e: if not silence_errors: raise - warnings.warn(f'One of the data, header pairs failed to validate with: {e}', - SunpyUserWarning) + warnings.warn(f"One of the data, header pairs failed to validate with: {e}", SunpyUserWarning) if not len(new_maps): - raise RuntimeError('No maps loaded') + raise RuntimeError("No maps loaded") if len(new_maps) == 1: return new_maps[0] @@ -479,10 +484,12 @@ def _check_registered_widgets(self, data, meta, **kwargs): else: candidate_widget_types = [self.default_widget_type] elif n_matches > 1: - raise MultipleMatchError("Too many candidate types identified " - f"({candidate_widget_types}). " - "Specify enough keywords to guarantee unique type " - "identification.") + raise MultipleMatchError( + "Too many candidate types identified " + f"({candidate_widget_types}). " + "Specify enough keywords to guarantee unique type " + "identification." + ) # Only one is found WidgetType = candidate_widget_types[0] @@ -493,23 +500,23 @@ def _read_file(self, file, **kwargs): file = Path(file) extensions = file.suffixes first_extension = extensions[0].lower() - if first_extension == '.dat': + if first_extension == ".dat": return self._read_dat(file) - elif first_extension in ('.r1', '.r2'): - return self._read_idl_sav(file, instrument='waves') - elif first_extension == '.cdf': + elif first_extension in (".r1", ".r2"): + return self._read_idl_sav(file, instrument="waves") + elif first_extension == ".cdf": return self._read_cdf(file) - elif first_extension == '.srs': + elif first_extension == ".srs": return self._read_srs(file) - elif first_extension in ('.fits', '.fit', '.fts', 'fit.gz'): + elif first_extension in (".fits", ".fit", ".fts", "fit.gz"): return self._read_fits(file) else: - raise ValueError(f'Extension {extensions[0]} not supported.') + raise ValueError(f"Extension {extensions[0]} not supported.") @staticmethod def _read_dat(file): - if 'swaves' in file.name: - name, prod, date, spacecraft, receiver = file.stem.split('_') + if "swaves" in file.name: + name, prod, date, spacecraft, receiver = file.stem.split("_") # frequency range freqs = np.genfromtxt(file, max_rows=1) * u.kHz # bg which is already subtracted from data @@ -519,21 +526,27 @@ def _read_dat(file): times = data[:, 0] * u.min data = data[:, 1:].T - meta = {'instrument': name, 'observatory': f'STEREO {spacecraft.upper()}', - 'product': prod, 'start_time': Time.strptime(date, '%Y%m%d'), - 'wavelength': a.Wavelength(freqs[0], freqs[-1]), 'detector': receiver, - 'freqs': freqs, 'background': bg} + meta = { + "instrument": name, + "observatory": f"STEREO {spacecraft.upper()}", + "product": prod, + "start_time": Time.strptime(date, "%Y%m%d"), + "wavelength": a.Wavelength(freqs[0], freqs[-1]), + "detector": receiver, + "freqs": freqs, + "background": bg, + } - meta['times'] = meta['start_time'] + times - meta['end_time'] = meta['start_time'] + times[-1] + meta["times"] = meta["start_time"] + times + meta["end_time"] = meta["start_time"] + times[-1] return data, meta @staticmethod def _read_srs(file): - with file.open('rb') as buff: + with file.open("rb") as buff: data = buff.read() - if file.suffixes[-1] == '.gz': + if file.suffixes[-1] == ".gz": data = gzip.decompress(data) # Data is store as a series of records made of different numbers of bytes @@ -560,25 +573,41 @@ def _read_srs(file): # Spectrum Analyser data # 25-425 401 data bytes for band 1 (A-band) # 426-826 401 data bytes for band 2 (B-band) - record_struc = struct.Struct('B'*8 + 'H'*3 + 'B'*2 - + 'H'*3 + 'B'*2 + 'B' * 401 + 'B' * 401) + record_struc = struct.Struct("B" * 8 + "H" * 3 + "B" * 2 + "H" * 3 + "B" * 2 + "B" * 401 + "B" * 401) records = record_struc.iter_unpack(data) # Map of numeric records to locations - site_map = {1: 'Palehua', 2: 'Holloman', 3: 'Learmonth', 4: 'San Vito'} - - df = pd.DataFrame([(*r[:18], np.array(r[18:419]), np.array(r[419:820])) - for r in records]) - df.columns = ['year', 'month', 'day', 'hour', 'minute', 'second', 'site', ' num_bands', - 'start_freq1', 'end_freq1', 'num_bytes1', 'analyser_ref1', - 'analyser_atten1', 'start_freq2', 'end_freq2', 'num_bytes2', - 'analyser_ref2', 'analyser_atten2', 'spec1', 'spec2'] + site_map = {1: "Palehua", 2: "Holloman", 3: "Learmonth", 4: "San Vito"} + + df = pd.DataFrame([(*r[:18], np.array(r[18:419]), np.array(r[419:820])) for r in records]) + df.columns = [ + "year", + "month", + "day", + "hour", + "minute", + "second", + "site", + " num_bands", + "start_freq1", + "end_freq1", + "num_bytes1", + "analyser_ref1", + "analyser_atten1", + "start_freq2", + "end_freq2", + "num_bytes2", + "analyser_ref2", + "analyser_atten2", + "spec1", + "spec2", + ] # Hack to make to_datetime work - earliest dates seem to be 2000 and won't be # around in 3000! - df['year'] = df['year'] + 2000 - df['time'] = pd.to_datetime(df[['year', 'month', 'day', 'hour', 'minute', 'second']]) + df["year"] = df["year"] + 2000 + df["time"] = pd.to_datetime(df[["year", "month", "day", "hour", "minute", "second"]]) # Equations taken from document n = np.arange(1, 402) @@ -586,12 +615,19 @@ def _read_srs(file): freq_b = (75 + 105 * (n - 1) / 400) * u.MHz freqs = np.hstack([freq_a, freq_b]) - data = np.hstack([np.vstack(df[name].to_numpy()) for name in ['spec1', 'spec2']]).T - times = Time(df['time']) + data = np.hstack([np.vstack(df[name].to_numpy()) for name in ["spec1", "spec2"]]).T + times = Time(df["time"]) - meta = {'instrument': 'RSTN', 'observatory': site_map[df['site'][0]], - 'start_time': times[0], 'end_time': times[-1], 'detector': 'RSTN', - 'wavelength': a.Wavelength(freqs[0], freqs[-1]), 'freqs': freqs, 'times': times} + meta = { + "instrument": "RSTN", + "observatory": site_map[df["site"][0]], + "start_time": times[0], + "end_time": times[-1], + "detector": "RSTN", + "wavelength": a.Wavelength(freqs[0], freqs[-1]), + "freqs": freqs, + "times": times, + } return data, meta @@ -599,31 +635,37 @@ def _read_srs(file): def _read_cdf(file): cdf = cdflib.CDF(file) cdf_meta = cdf.globalattsget() - if (cdf_meta.get('Project', '') == 'PSP' - and cdf_meta.get('Source_name') == 'PSP_FLD>Parker Solar Probe FIELDS' - and 'Radio Frequency Spectrometer' in cdf_meta.get('Descriptor')): - short, _long = cdf_meta['Descriptor'].split('>') + if ( + cdf_meta.get("Project", "") == "PSP" + and cdf_meta.get("Source_name") == "PSP_FLD>Parker Solar Probe FIELDS" + and "Radio Frequency Spectrometer" in cdf_meta.get("Descriptor") + ): + short, _long = cdf_meta["Descriptor"].split(">") detector = short[4:].lower() - times, data, freqs = [cdf.varget(name) for name in - [f'epoch_{detector}_auto_averages_ch0_V1V2', - f'psp_fld_l2_rfs_{detector}_auto_averages_ch0_V1V2', - f'frequency_{detector}_auto_averages_ch0_V1V2']] + times, data, freqs = [ + cdf.varget(name) + for name in [ + f"epoch_{detector}_auto_averages_ch0_V1V2", + f"psp_fld_l2_rfs_{detector}_auto_averages_ch0_V1V2", + f"frequency_{detector}_auto_averages_ch0_V1V2", + ] + ] - times = Time(times << u.ns, format='cdf_tt2000') + times = Time(times << u.ns, format="cdf_tt2000") freqs = freqs[0, :] << u.Hz - data = data.T << u.Unit('Volt**2/Hz') + data = data.T << u.Unit("Volt**2/Hz") meta = { - 'cdf_meta': cdf_meta, - 'detector': detector, - 'instrument': 'FIELDS/RFS', - 'observatory': 'PSP', - 'start_time': times[0], - 'end_time': times[-1], - 'wavelength': a.Wavelength(freqs.min(), freqs.max()), - 'times': times, - 'freqs': freqs + "cdf_meta": cdf_meta, + "detector": detector, + "instrument": "FIELDS/RFS", + "observatory": "PSP", + "start_time": times[0], + "end_time": times[-1], + "wavelength": a.Wavelength(freqs.min(), freqs.max()), + "times": times, + "freqs": freqs, } return data, meta @@ -631,75 +673,79 @@ def _read_cdf(file): def _read_fits(file): hd_pairs = fits.read(file) - if 'e-CALLISTO' in hd_pairs[0].header.get('CONTENT', ''): + if "e-CALLISTO" in hd_pairs[0].header.get("CONTENT", ""): data = hd_pairs[0].data - times = hd_pairs[1].data['TIME'].flatten() * u.s - freqs = hd_pairs[1].data['FREQUENCY'].flatten() * u.MHz - start_time = parse_time(hd_pairs[0].header['DATE-OBS'] - + ' ' + hd_pairs[0].header['TIME-OBS']) - end_time = parse_time(hd_pairs[0].header['DATE-END'] - + ' ' + hd_pairs[0].header['TIME-END']) + times = hd_pairs[1].data["TIME"].flatten() * u.s + freqs = hd_pairs[1].data["FREQUENCY"].flatten() * u.MHz + start_time = parse_time(hd_pairs[0].header["DATE-OBS"] + " " + hd_pairs[0].header["TIME-OBS"]) + end_time = parse_time(hd_pairs[0].header["DATE-END"] + " " + hd_pairs[0].header["TIME-END"]) times = start_time + times meta = { - 'fits_meta': hd_pairs[0].header, - 'detector': 'e-CALLISTO', - 'instrument': 'e-CALLISTO', - 'observatory': hd_pairs[0].header['INSTRUME'], - 'start_time': start_time, - 'end_time': end_time, - 'wavelength': a.Wavelength(freqs.min(), freqs.max()), - 'times': times, - 'freqs': freqs + "fits_meta": hd_pairs[0].header, + "detector": "e-CALLISTO", + "instrument": "e-CALLISTO", + "observatory": hd_pairs[0].header["INSTRUME"], + "start_time": start_time, + "end_time": end_time, + "wavelength": a.Wavelength(freqs.min(), freqs.max()), + "times": times, + "freqs": freqs, } return data, meta - elif hd_pairs[0].header.get('TELESCOP', '') == 'EOVSA': - times = Time(hd_pairs[2].data['mjd'] + hd_pairs[2].data['time'] / 1000.0 / 86400., - format='mjd') - freqs = hd_pairs[1].data['sfreq'] * u.GHz + elif hd_pairs[0].header.get("TELESCOP", "") == "EOVSA": + times = Time(hd_pairs[2].data["mjd"] + hd_pairs[2].data["time"] / 1000.0 / 86400.0, format="mjd") + freqs = hd_pairs[1].data["sfreq"] * u.GHz data = hd_pairs[0].data - start_time = parse_time(hd_pairs[0].header['DATE_OBS']) - end_time = parse_time(hd_pairs[0].header['DATE_END']) + start_time = parse_time(hd_pairs[0].header["DATE_OBS"]) + end_time = parse_time(hd_pairs[0].header["DATE_END"]) meta = { - 'fits_meta': hd_pairs[0].header, - 'detector': 'EOVSA', - 'instrument': 'EOVSA', - 'observatory': 'Owens Valley', - 'start_time': start_time, - 'end_time': end_time, - 'wavelength': a.Wavelength(freqs.min(), freqs.max()), - 'times': times, - 'freqs': freqs + "fits_meta": hd_pairs[0].header, + "detector": "EOVSA", + "instrument": "EOVSA", + "observatory": "Owens Valley", + "start_time": start_time, + "end_time": end_time, + "wavelength": a.Wavelength(freqs.min(), freqs.max()), + "times": times, + "freqs": freqs, } return data, meta @staticmethod def _read_idl_sav(file, instrument=None): data = readsav(file) - if instrument == 'waves': + if instrument == "waves": # See https://solar-radio.gsfc.nasa.gov/wind/one_minute_doc.html - data_array = data['arrayb'] + data_array = data["arrayb"] # frequency range - if file.suffix == '.R1': + if file.suffix == ".R1": freqs = np.linspace(20, 1040, 256) * u.kHz - receiver = 'RAD1' - elif file.suffix == '.R2': + receiver = "RAD1" + elif file.suffix == ".R2": freqs = np.linspace(1.075, 13.825, 256) * u.MHz - receiver = 'RAD2' + receiver = "RAD2" # bg which is already subtracted from data ? bg = data_array[:, -1] data = data_array[:, :-1] - start_time = Time.strptime(file.stem, '%Y%m%d') - end_time = start_time + 86399*u.s - times = start_time + (np.arange(1440) * 60 + 30)*u.s + start_time = Time.strptime(file.stem, "%Y%m%d") + end_time = start_time + 86399 * u.s + times = start_time + (np.arange(1440) * 60 + 30) * u.s - meta = {'instrument': 'WAVES', 'observatory': 'WIND', 'start_time': start_time, - 'end_time': end_time, 'wavelength': a.Wavelength(freqs[0], freqs[-1]), - 'detector': receiver, 'freqs': freqs, 'times': times, 'background': bg} + meta = { + "instrument": "WAVES", + "observatory": "WIND", + "start_time": start_time, + "end_time": end_time, + "wavelength": a.Wavelength(freqs[0], freqs[-1]), + "detector": receiver, + "freqs": freqs, + "times": times, + "background": bg, + } return data, meta -Spectrogram = SpectrogramFactory(registry=GenericSpectrogram._registry, - default_widget_type=GenericSpectrogram) +Spectrogram = SpectrogramFactory(registry=GenericSpectrogram._registry, default_widget_type=GenericSpectrogram) diff --git a/radiospectra/spectrogram2/tests/test_callisto.py b/radiospectra/spectrogram2/tests/test_callisto.py index 27d23ac..0811e45 100644 --- a/radiospectra/spectrogram2/tests/test_callisto.py +++ b/radiospectra/spectrogram2/tests/test_callisto.py @@ -12,71 +12,238 @@ from radiospectra.spectrogram2.sources import CALISTOSpectrogram -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_callisto(parse_path_moc): - start_time = Time('2011-06-07 06:24:00.213') + start_time = Time("2011-06-07 06:24:00.213") meta = { - 'fits_meta': { - 'OBS_LAC': 'N', - 'OBS_LAT': 53.0941390991211, - 'OBS_LOC': 'E', - 'OBS_LON': 7.92012977600098, - 'OBS_ALT': 416.5 + "fits_meta": { + "OBS_LAC": "N", + "OBS_LAT": 53.0941390991211, + "OBS_LOC": "E", + "OBS_LON": 7.92012977600098, + "OBS_ALT": 416.5, }, - 'detector': 'e-CALLISTO', - 'instrument': 'e-CALLISTO', - 'observatory': 'BIR', - 'start_time': Time('2011-06-07 06:24:00.213'), - 'end_time': Time('2011-06-07 06:39:00.000'), - 'wavelength': a.Wavelength(20000.0*u.kHz, 91813.00*u.kHz), - 'times': start_time + np.arange(3600) * 0.25 * u.s, - 'freqs': [91.81300354003906, 91.25, 91.06300354003906, 90.625, 90.43800354003906, 89.75, - 89.68800354003906, 89.0, 88.625, 88.25, 88.06300354003906, 87.56300354003906, - 87.43800354003906, 87.06300354003906, 86.5, 86.06300354003906, 85.875, - 85.56300354003906, 84.875, 84.68800354003906, 84.31300354003906, 83.875, - 83.68800354003906, 83.0, 82.75, 82.43800354003906, 81.875, 81.75, - 81.18800354003906, 80.75, 80.625, 80.25, 79.68800354003906, 79.25, 79.125, - 78.68800354003906, 78.43800354003906, 78.06300354003906, 77.43800354003906, 77.0, - 76.625, 76.56300354003906, 76.0, 75.56300354003906, 75.125, 75.0, - 74.68800354003906, 74.31300354003906, 73.68800354003906, 73.31300354003906, - 72.875, 72.625, 72.125, 71.75, 71.56300354003906, 71.0, 70.93800354003906, 70.25, - 70.18800354003906, 69.68800354003906, 69.43800354003906, 69.06300354003906, - 68.43800354003906, 68.06300354003906, 67.93800354003906, 67.31300354003906, - 66.93800354003906, 66.81300354003906, 66.125, 66.06300354003906, - 65.43800354003906, 65.0, 64.875, 64.25, 64.06300354003906, 63.8129997253418, - 63.3129997253418, 62.75, 62.5, 62.0, 61.9379997253418, 61.5629997253418, 60.875, - 60.75, 60.3129997253418, 59.9379997253418, 59.6879997253418, 59.0, 58.625, 58.25, - 58.1879997253418, 57.5, 57.125, 56.9379997253418, 56.5, 56.3129997253418, - 55.9379997253418, 55.4379997253418, 54.9379997253418, 54.8129997253418, - 54.4379997253418, 53.9379997253418, 53.4379997253418, 53.125, 52.9379997253418, - 52.5629997253418, 51.875, 51.5629997253418, 51.1879997253418, 50.8129997253418, - 50.5629997253418, 50.0629997253418, 49.6879997253418, 49.3129997253418, - 48.9379997253418, 48.8129997253418, 48.125, 48.0629997253418, 47.4379997253418, - 47.25, 46.9379997253418, 46.25, 45.875, 45.8129997253418, 45.3129997253418, - 45.0629997253418, 44.375, 44.1879997253418, 43.8129997253418, 43.3129997253418, - 43.1879997253418, 42.5, 42.125, 42.0629997253418, 41.5629997253418, - 41.1879997253418, 40.6879997253418, 40.4379997253418, 39.875, 39.8129997253418, - 39.4379997253418, 38.75, 38.375, 38.0629997253418, 37.6879997253418, - 37.5629997253418, 36.875, 36.8129997253418, 36.25, 36.0629997253418, - 35.6879997253418, 35.0629997253418, 34.875, 34.5, 34.125, 33.8129997253418, - 33.125, 33.0, 32.5629997253418, 32.0629997253418, 31.937999725341797, 31.25, - 30.875, 30.562999725341797, 30.125, 30.062999725341797, 29.375, - 29.312999725341797, 28.875, 28.25, 28.187999725341797, 27.562999725341797, 27.125, - 26.75, 26.687999725341797, 26.125, 25.75, 25.375, 25.0, 24.812999725341797, - 24.125, 23.812999725341797, 23.437999725341797, 23.125, 22.812999725341797, - 22.437999725341797, 21.875, 21.812999725341797, 21.125, 20.75, 20.375, 20.0, 20.0, - 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0] * u.MHz + "detector": "e-CALLISTO", + "instrument": "e-CALLISTO", + "observatory": "BIR", + "start_time": Time("2011-06-07 06:24:00.213"), + "end_time": Time("2011-06-07 06:39:00.000"), + "wavelength": a.Wavelength(20000.0 * u.kHz, 91813.00 * u.kHz), + "times": start_time + np.arange(3600) * 0.25 * u.s, + "freqs": [ + 91.81300354003906, + 91.25, + 91.06300354003906, + 90.625, + 90.43800354003906, + 89.75, + 89.68800354003906, + 89.0, + 88.625, + 88.25, + 88.06300354003906, + 87.56300354003906, + 87.43800354003906, + 87.06300354003906, + 86.5, + 86.06300354003906, + 85.875, + 85.56300354003906, + 84.875, + 84.68800354003906, + 84.31300354003906, + 83.875, + 83.68800354003906, + 83.0, + 82.75, + 82.43800354003906, + 81.875, + 81.75, + 81.18800354003906, + 80.75, + 80.625, + 80.25, + 79.68800354003906, + 79.25, + 79.125, + 78.68800354003906, + 78.43800354003906, + 78.06300354003906, + 77.43800354003906, + 77.0, + 76.625, + 76.56300354003906, + 76.0, + 75.56300354003906, + 75.125, + 75.0, + 74.68800354003906, + 74.31300354003906, + 73.68800354003906, + 73.31300354003906, + 72.875, + 72.625, + 72.125, + 71.75, + 71.56300354003906, + 71.0, + 70.93800354003906, + 70.25, + 70.18800354003906, + 69.68800354003906, + 69.43800354003906, + 69.06300354003906, + 68.43800354003906, + 68.06300354003906, + 67.93800354003906, + 67.31300354003906, + 66.93800354003906, + 66.81300354003906, + 66.125, + 66.06300354003906, + 65.43800354003906, + 65.0, + 64.875, + 64.25, + 64.06300354003906, + 63.8129997253418, + 63.3129997253418, + 62.75, + 62.5, + 62.0, + 61.9379997253418, + 61.5629997253418, + 60.875, + 60.75, + 60.3129997253418, + 59.9379997253418, + 59.6879997253418, + 59.0, + 58.625, + 58.25, + 58.1879997253418, + 57.5, + 57.125, + 56.9379997253418, + 56.5, + 56.3129997253418, + 55.9379997253418, + 55.4379997253418, + 54.9379997253418, + 54.8129997253418, + 54.4379997253418, + 53.9379997253418, + 53.4379997253418, + 53.125, + 52.9379997253418, + 52.5629997253418, + 51.875, + 51.5629997253418, + 51.1879997253418, + 50.8129997253418, + 50.5629997253418, + 50.0629997253418, + 49.6879997253418, + 49.3129997253418, + 48.9379997253418, + 48.8129997253418, + 48.125, + 48.0629997253418, + 47.4379997253418, + 47.25, + 46.9379997253418, + 46.25, + 45.875, + 45.8129997253418, + 45.3129997253418, + 45.0629997253418, + 44.375, + 44.1879997253418, + 43.8129997253418, + 43.3129997253418, + 43.1879997253418, + 42.5, + 42.125, + 42.0629997253418, + 41.5629997253418, + 41.1879997253418, + 40.6879997253418, + 40.4379997253418, + 39.875, + 39.8129997253418, + 39.4379997253418, + 38.75, + 38.375, + 38.0629997253418, + 37.6879997253418, + 37.5629997253418, + 36.875, + 36.8129997253418, + 36.25, + 36.0629997253418, + 35.6879997253418, + 35.0629997253418, + 34.875, + 34.5, + 34.125, + 33.8129997253418, + 33.125, + 33.0, + 32.5629997253418, + 32.0629997253418, + 31.937999725341797, + 31.25, + 30.875, + 30.562999725341797, + 30.125, + 30.062999725341797, + 29.375, + 29.312999725341797, + 28.875, + 28.25, + 28.187999725341797, + 27.562999725341797, + 27.125, + 26.75, + 26.687999725341797, + 26.125, + 25.75, + 25.375, + 25.0, + 24.812999725341797, + 24.125, + 23.812999725341797, + 23.437999725341797, + 23.125, + 22.812999725341797, + 22.437999725341797, + 21.875, + 21.812999725341797, + 21.125, + 20.75, + 20.375, + 20.0, + 20.0, + 20.0, + 20.0, + 20.0, + 20.0, + 20.0, + 20.0, + 20.0, + ] + * u.MHz, } array = np.zeros((200, 3600)) parse_path_moc.return_value = [(array, meta)] - file = Path('fake.fit.gz') + file = Path("fake.fit.gz") spec = Spectrogram(file) assert isinstance(spec, CALISTOSpectrogram) - assert spec.observatory == 'BIR' - assert spec.instrument == 'E-CALLISTO' - assert spec.detector == 'E-CALLISTO' + assert spec.observatory == "BIR" + assert spec.instrument == "E-CALLISTO" + assert spec.detector == "E-CALLISTO" assert spec.start_time.datetime == datetime(2011, 6, 7, 6, 24, 0, 213000) assert spec.end_time.datetime == datetime(2011, 6, 7, 6, 39) assert spec.wavelength.min.to(u.MHz) == 20 * u.MHz assert spec.wavelength.max.to(u.MHz).round(1) == 91.8 * u.MHz - assert str(spec.observatory_location) == '(3801942.21260148, 528924.60367802, 5077174.56861812) m' + assert str(spec.observatory_location) == "(3801942.21260148, 528924.60367802, 5077174.56861812) m" diff --git a/radiospectra/spectrogram2/tests/test_eovsa.py b/radiospectra/spectrogram2/tests/test_eovsa.py index 498f347..f9f02fb 100644 --- a/radiospectra/spectrogram2/tests/test_eovsa.py +++ b/radiospectra/spectrogram2/tests/test_eovsa.py @@ -15,143 +15,506 @@ @pytest.fixture def eovsa_data(): - start_time = Time('2021-02-13 15:41:20.999') - end_time = Time('2021-02-13 20:43:18.999') + start_time = Time("2021-02-13 15:41:20.999") + end_time = Time("2021-02-13 20:43:18.999") meta = { - 'fits_meta': {'POLARIZA': 'I'}, - 'detector': 'EOVSA', - 'instrument': 'EOVSA', - 'observatory': 'Owens Valley', - 'start_time': start_time, - 'end_time': end_time, - 'wavelength': a.Wavelength(1105371.117591858 * u.kHz, 17979686.737060547 * u.kHz), - 'times': np.linspace(0, (end_time - start_time).to_value('s'), 15463), - 'freqs': [1.1053711, 1.1161133, 1.1268555, 1.1375977, 1.1483399, - 1.159082, 1.1698242, 1.1805664, 1.1913086, 1.2020508, - 1.212793, 1.2235352, 1.2342774, 1.2450196, 1.2557617, - 1.2665039, 1.2772461, 1.2879883, 1.2987305, 1.3094727, - 1.3202149, 1.330957, 1.3416992, 1.3524414, 1.3631836, - 1.3739258, 1.384668, 1.3954102, 1.4061524, 1.4168946, - 1.432373, 1.4471191, 1.4618652, 1.4766114, 1.4913574, - 1.5061035, 1.5208496, 1.5355957, 1.5503418, 1.5650879, - 1.579834, 1.59458, 1.6093261, 1.6240723, 1.6388184, - 1.6535645, 1.6683105, 1.6830566, 1.6978028, 1.7125489, - 1.7272949, 1.742041, 2.4125, 2.4375, 2.4625, - 2.4875, 2.5125, 2.5375, 2.5625, 2.5875, - 2.6125, 2.6375, 2.6625, 2.6875, 2.7125, - 2.7385254, 2.7655761, 2.7926269, 2.8196778, 2.8467286, - 2.8737793, 2.90083, 2.9278808, 2.9549317, 2.9819825, - 3.0090332, 3.036084, 3.0647461, 3.0942383, 3.1237304, - 3.1532226, 3.182715, 3.212207, 3.2416992, 3.2711914, - 3.3006835, 3.3301759, 3.359668, 3.391211, 3.4236329, - 3.4560547, 3.4884765, 3.5208983, 3.5533204, 3.5857422, - 3.618164, 3.650586, 3.6830077, 3.7180176, 3.7540526, - 3.790088, 3.826123, 3.8621583, 3.8981934, 3.9342284, - 3.9702637, 4.006299, 4.0453124, 4.0859375, 4.1265626, - 4.1671877, 4.2078123, 4.2484374, 4.2890625, 4.3296876, - 4.3703127, 4.4109373, 4.4515624, 4.4921875, 4.5328126, - 4.5734377, 4.6140623, 4.6546874, 4.6953125, 4.7359376, - 4.7765627, 4.8171873, 4.8578124, 4.8984375, 4.9390626, - 4.9796877, 5.0203123, 5.0609374, 5.1015625, 5.1421876, - 5.1828127, 5.2234373, 5.2640624, 5.3046875, 5.3453126, - 5.3859377, 5.4265623, 5.4671874, 5.5078125, 5.5484376, - 5.5890627, 5.6296873, 5.6703124, 5.7109375, 5.7515626, - 5.7921877, 5.8328123, 5.8734374, 5.9140625, 5.9546876, - 5.9953127, 6.0359373, 6.0765624, 6.1171875, 6.1578126, - 6.1984377, 6.2390623, 6.2796874, 6.3203125, 6.3609376, - 6.4015627, 6.4421873, 6.4828124, 6.5234375, 6.5640626, - 6.6046877, 6.6453123, 6.6859374, 6.7265625, 6.7671876, - 6.8078127, 6.8484373, 6.8890624, 6.9296875, 6.9703126, - 7.0109377, 7.0515623, 7.0921874, 7.1328125, 7.1734376, - 7.2140627, 7.2546873, 7.2953124, 7.3359375, 7.3765626, - 7.4171877, 7.4578123, 7.4984374, 7.5390625, 7.5796876, - 7.6203127, 7.6609373, 7.7015624, 7.7421875, 7.7828126, - 7.8234377, 7.8640623, 7.9046874, 7.9453125, 7.9859376, - 8.026563, 8.067187, 8.107813, 8.1484375, 8.189062, - 8.229688, 8.270312, 8.310938, 8.3515625, 8.392187, - 8.432813, 8.473437, 8.514063, 8.5546875, 8.595312, - 8.635938, 8.676562, 8.717188, 8.7578125, 8.798437, - 8.839063, 8.879687, 8.920313, 8.9609375, 9.001562, - 9.042188, 9.082812, 9.123438, 9.1640625, 9.204687, - 9.245313, 9.285937, 9.326563, 9.3671875, 9.407812, - 9.448438, 9.489062, 9.529688, 9.5703125, 9.610937, - 9.651563, 9.692187, 9.732813, 9.7734375, 9.814062, - 9.854688, 9.895312, 9.935938, 9.9765625, 10.017187, - 10.057813, 10.098437, 10.139063, 10.1796875, 10.220312, - 10.260938, 10.301562, 10.342188, 10.3828125, 10.423437, - 10.464063, 10.504687, 10.545313, 10.5859375, 10.626562, - 10.667188, 10.707812, 10.748438, 10.7890625, 10.829687, - 10.870313, 10.910937, 10.951563, 10.9921875, 11.032812, - 11.073438, 11.114062, 11.154688, 11.1953125, 11.235937, - 11.276563, 11.317187, 11.357813, 11.3984375, 11.439062, - 11.479688, 11.520312, 11.560938, 11.6015625, 11.642187, - 11.682813, 11.723437, 11.764063, 11.8046875, 11.845312, - 11.885938, 11.926562, 11.967188, 12.0078125, 12.048437, - 12.089063, 12.129687, 12.170313, 12.2109375, 12.251562, - 12.292188, 12.332812, 12.373438, 12.4140625, 12.454687, - 12.495313, 12.535937, 12.576563, 12.6171875, 12.657812, - 12.698438, 12.739062, 12.779688, 12.8203125, 12.860937, - 12.901563, 12.942187, 12.982813, 13.0234375, 13.064062, - 13.104688, 13.145312, 13.185938, 13.2265625, 13.267187, - 13.307813, 13.348437, 13.389063, 13.4296875, 13.470312, - 13.510938, 13.551562, 13.592188, 13.6328125, 13.673437, - 13.714063, 13.754687, 13.795313, 13.8359375, 13.876562, - 13.917188, 13.957812, 13.998438, 14.0390625, 14.079687, - 14.120313, 14.160937, 14.201563, 14.2421875, 14.282812, - 14.323438, 14.364062, 14.404688, 14.4453125, 14.485937, - 14.526563, 14.567187, 14.607813, 14.6484375, 14.689062, - 14.729688, 14.770312, 14.810938, 14.8515625, 14.892187, - 14.932813, 14.973437, 15.014063, 15.0546875, 15.095312, - 15.135938, 15.176562, 15.217188, 15.2578125, 15.298437, - 15.339063, 15.379687, 15.420313, 15.4609375, 15.501562, - 15.542188, 15.582812, 15.623438, 15.6640625, 15.704687, - 15.745313, 15.785937, 15.826563, 15.8671875, 15.907812, - 15.948438, 15.989062, 16.029688, 16.070312, 16.110937, - 16.151562, 16.192188, 16.232813, 16.273438, 16.314062, - 16.354687, 16.395313, 16.435938, 16.476562, 16.517187, - 16.557812, 16.598438, 16.639063, 16.679688, 16.720312, - 16.760937, 16.801563, 16.842188, 16.882812, 16.923437, - 16.964062, 17.004688, 17.045313, 17.085938, 17.126562, - 17.167187, 17.207813, 17.248438, 17.289062, 17.329687, - 17.370312, 17.410938, 17.451563, 17.492188, 17.532812, - 17.573437, 17.614063, 17.654688, 17.695312, 17.735937, - 17.776562, 17.817188, 17.857813, 17.898438, 17.939062, - 17.979687] * u.GHz + "fits_meta": {"POLARIZA": "I"}, + "detector": "EOVSA", + "instrument": "EOVSA", + "observatory": "Owens Valley", + "start_time": start_time, + "end_time": end_time, + "wavelength": a.Wavelength(1105371.117591858 * u.kHz, 17979686.737060547 * u.kHz), + "times": np.linspace(0, (end_time - start_time).to_value("s"), 15463), + "freqs": [ + 1.1053711, + 1.1161133, + 1.1268555, + 1.1375977, + 1.1483399, + 1.159082, + 1.1698242, + 1.1805664, + 1.1913086, + 1.2020508, + 1.212793, + 1.2235352, + 1.2342774, + 1.2450196, + 1.2557617, + 1.2665039, + 1.2772461, + 1.2879883, + 1.2987305, + 1.3094727, + 1.3202149, + 1.330957, + 1.3416992, + 1.3524414, + 1.3631836, + 1.3739258, + 1.384668, + 1.3954102, + 1.4061524, + 1.4168946, + 1.432373, + 1.4471191, + 1.4618652, + 1.4766114, + 1.4913574, + 1.5061035, + 1.5208496, + 1.5355957, + 1.5503418, + 1.5650879, + 1.579834, + 1.59458, + 1.6093261, + 1.6240723, + 1.6388184, + 1.6535645, + 1.6683105, + 1.6830566, + 1.6978028, + 1.7125489, + 1.7272949, + 1.742041, + 2.4125, + 2.4375, + 2.4625, + 2.4875, + 2.5125, + 2.5375, + 2.5625, + 2.5875, + 2.6125, + 2.6375, + 2.6625, + 2.6875, + 2.7125, + 2.7385254, + 2.7655761, + 2.7926269, + 2.8196778, + 2.8467286, + 2.8737793, + 2.90083, + 2.9278808, + 2.9549317, + 2.9819825, + 3.0090332, + 3.036084, + 3.0647461, + 3.0942383, + 3.1237304, + 3.1532226, + 3.182715, + 3.212207, + 3.2416992, + 3.2711914, + 3.3006835, + 3.3301759, + 3.359668, + 3.391211, + 3.4236329, + 3.4560547, + 3.4884765, + 3.5208983, + 3.5533204, + 3.5857422, + 3.618164, + 3.650586, + 3.6830077, + 3.7180176, + 3.7540526, + 3.790088, + 3.826123, + 3.8621583, + 3.8981934, + 3.9342284, + 3.9702637, + 4.006299, + 4.0453124, + 4.0859375, + 4.1265626, + 4.1671877, + 4.2078123, + 4.2484374, + 4.2890625, + 4.3296876, + 4.3703127, + 4.4109373, + 4.4515624, + 4.4921875, + 4.5328126, + 4.5734377, + 4.6140623, + 4.6546874, + 4.6953125, + 4.7359376, + 4.7765627, + 4.8171873, + 4.8578124, + 4.8984375, + 4.9390626, + 4.9796877, + 5.0203123, + 5.0609374, + 5.1015625, + 5.1421876, + 5.1828127, + 5.2234373, + 5.2640624, + 5.3046875, + 5.3453126, + 5.3859377, + 5.4265623, + 5.4671874, + 5.5078125, + 5.5484376, + 5.5890627, + 5.6296873, + 5.6703124, + 5.7109375, + 5.7515626, + 5.7921877, + 5.8328123, + 5.8734374, + 5.9140625, + 5.9546876, + 5.9953127, + 6.0359373, + 6.0765624, + 6.1171875, + 6.1578126, + 6.1984377, + 6.2390623, + 6.2796874, + 6.3203125, + 6.3609376, + 6.4015627, + 6.4421873, + 6.4828124, + 6.5234375, + 6.5640626, + 6.6046877, + 6.6453123, + 6.6859374, + 6.7265625, + 6.7671876, + 6.8078127, + 6.8484373, + 6.8890624, + 6.9296875, + 6.9703126, + 7.0109377, + 7.0515623, + 7.0921874, + 7.1328125, + 7.1734376, + 7.2140627, + 7.2546873, + 7.2953124, + 7.3359375, + 7.3765626, + 7.4171877, + 7.4578123, + 7.4984374, + 7.5390625, + 7.5796876, + 7.6203127, + 7.6609373, + 7.7015624, + 7.7421875, + 7.7828126, + 7.8234377, + 7.8640623, + 7.9046874, + 7.9453125, + 7.9859376, + 8.026563, + 8.067187, + 8.107813, + 8.1484375, + 8.189062, + 8.229688, + 8.270312, + 8.310938, + 8.3515625, + 8.392187, + 8.432813, + 8.473437, + 8.514063, + 8.5546875, + 8.595312, + 8.635938, + 8.676562, + 8.717188, + 8.7578125, + 8.798437, + 8.839063, + 8.879687, + 8.920313, + 8.9609375, + 9.001562, + 9.042188, + 9.082812, + 9.123438, + 9.1640625, + 9.204687, + 9.245313, + 9.285937, + 9.326563, + 9.3671875, + 9.407812, + 9.448438, + 9.489062, + 9.529688, + 9.5703125, + 9.610937, + 9.651563, + 9.692187, + 9.732813, + 9.7734375, + 9.814062, + 9.854688, + 9.895312, + 9.935938, + 9.9765625, + 10.017187, + 10.057813, + 10.098437, + 10.139063, + 10.1796875, + 10.220312, + 10.260938, + 10.301562, + 10.342188, + 10.3828125, + 10.423437, + 10.464063, + 10.504687, + 10.545313, + 10.5859375, + 10.626562, + 10.667188, + 10.707812, + 10.748438, + 10.7890625, + 10.829687, + 10.870313, + 10.910937, + 10.951563, + 10.9921875, + 11.032812, + 11.073438, + 11.114062, + 11.154688, + 11.1953125, + 11.235937, + 11.276563, + 11.317187, + 11.357813, + 11.3984375, + 11.439062, + 11.479688, + 11.520312, + 11.560938, + 11.6015625, + 11.642187, + 11.682813, + 11.723437, + 11.764063, + 11.8046875, + 11.845312, + 11.885938, + 11.926562, + 11.967188, + 12.0078125, + 12.048437, + 12.089063, + 12.129687, + 12.170313, + 12.2109375, + 12.251562, + 12.292188, + 12.332812, + 12.373438, + 12.4140625, + 12.454687, + 12.495313, + 12.535937, + 12.576563, + 12.6171875, + 12.657812, + 12.698438, + 12.739062, + 12.779688, + 12.8203125, + 12.860937, + 12.901563, + 12.942187, + 12.982813, + 13.0234375, + 13.064062, + 13.104688, + 13.145312, + 13.185938, + 13.2265625, + 13.267187, + 13.307813, + 13.348437, + 13.389063, + 13.4296875, + 13.470312, + 13.510938, + 13.551562, + 13.592188, + 13.6328125, + 13.673437, + 13.714063, + 13.754687, + 13.795313, + 13.8359375, + 13.876562, + 13.917188, + 13.957812, + 13.998438, + 14.0390625, + 14.079687, + 14.120313, + 14.160937, + 14.201563, + 14.2421875, + 14.282812, + 14.323438, + 14.364062, + 14.404688, + 14.4453125, + 14.485937, + 14.526563, + 14.567187, + 14.607813, + 14.6484375, + 14.689062, + 14.729688, + 14.770312, + 14.810938, + 14.8515625, + 14.892187, + 14.932813, + 14.973437, + 15.014063, + 15.0546875, + 15.095312, + 15.135938, + 15.176562, + 15.217188, + 15.2578125, + 15.298437, + 15.339063, + 15.379687, + 15.420313, + 15.4609375, + 15.501562, + 15.542188, + 15.582812, + 15.623438, + 15.6640625, + 15.704687, + 15.745313, + 15.785937, + 15.826563, + 15.8671875, + 15.907812, + 15.948438, + 15.989062, + 16.029688, + 16.070312, + 16.110937, + 16.151562, + 16.192188, + 16.232813, + 16.273438, + 16.314062, + 16.354687, + 16.395313, + 16.435938, + 16.476562, + 16.517187, + 16.557812, + 16.598438, + 16.639063, + 16.679688, + 16.720312, + 16.760937, + 16.801563, + 16.842188, + 16.882812, + 16.923437, + 16.964062, + 17.004688, + 17.045313, + 17.085938, + 17.126562, + 17.167187, + 17.207813, + 17.248438, + 17.289062, + 17.329687, + 17.370312, + 17.410938, + 17.451563, + 17.492188, + 17.532812, + 17.573437, + 17.614063, + 17.654688, + 17.695312, + 17.735937, + 17.776562, + 17.817188, + 17.857813, + 17.898438, + 17.939062, + 17.979687, + ] + * u.GHz, } array = np.zeros((451, 15463)) return meta, array -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_eovsa_xpall(parse_path_moc, eovsa_data): meta, array = eovsa_data parse_path_moc.return_value = [(array, meta)] - file = Path('fake.fts') + file = Path("fake.fts") spec = Spectrogram(file) assert isinstance(spec, EOVSASpectrogram) - assert spec.observatory == 'OWENS VALLEY' - assert spec.instrument == 'EOVSA' - assert spec.detector == 'EOVSA' + assert spec.observatory == "OWENS VALLEY" + assert spec.instrument == "EOVSA" + assert spec.detector == "EOVSA" assert spec.start_time.datetime == datetime(2021, 2, 13, 15, 41, 20, 999000) assert spec.end_time.datetime == datetime(2021, 2, 13, 20, 43, 18, 999000) assert spec.wavelength.min.to(u.GHz) == 1.105371117591858 * u.GHz assert spec.wavelength.max.to(u.GHz) == 17.979686737060547 * u.GHz - assert spec.polarisation == 'I' + assert spec.polarisation == "I" -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_eovsa_tpall(parse_path_moc, eovsa_data): meta, array = eovsa_data - meta['fits_meta']['POLARIZA'] = 'I' + meta["fits_meta"]["POLARIZA"] = "I" parse_path_moc.return_value = [(array, meta)] - file = Path('fake.fts') + file = Path("fake.fts") spec = Spectrogram(file) assert isinstance(spec, EOVSASpectrogram) - assert spec.observatory == 'OWENS VALLEY' - assert spec.instrument == 'EOVSA' - assert spec.detector == 'EOVSA' + assert spec.observatory == "OWENS VALLEY" + assert spec.instrument == "EOVSA" + assert spec.detector == "EOVSA" assert spec.start_time.datetime == datetime(2021, 2, 13, 15, 41, 20, 999000) assert spec.end_time.datetime == datetime(2021, 2, 13, 20, 43, 18, 999000) assert spec.wavelength.min.to(u.GHz) == 1.105371117591858 * u.GHz assert spec.wavelength.max.to(u.GHz) == 17.979686737060547 * u.GHz - assert spec.polarisation == 'I' + assert spec.polarisation == "I" diff --git a/radiospectra/spectrogram2/tests/test_psp_rfs.py b/radiospectra/spectrogram2/tests/test_psp_rfs.py index 9911379..0d4082f 100644 --- a/radiospectra/spectrogram2/tests/test_psp_rfs.py +++ b/radiospectra/spectrogram2/tests/test_psp_rfs.py @@ -12,99 +12,217 @@ from radiospectra.spectrogram2.sources import RFSSpectrogram -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_psp_rfs_lfr(parse_path_moc): - start_time = Time('2019-04-09 00:01:16.197889') - end_time = Time('2019-04-10 00:01:04.997573') + start_time = Time("2019-04-09 00:01:16.197889") + end_time = Time("2019-04-10 00:01:04.997573") meta = { - 'cdf_meta': { - 'TITLE': 'PSP FIELDS RFS LFR data', - 'Project': 'PSP', - 'Source_name': 'PSP_FLD>Parker Solar Probe FIELDS', - 'Descriptor': 'RFS_LFR>Radio Frequency Spectrometer LFR', - 'Data_type': 'L2>Level 2 Data', - 'Data_version': '01', - 'MODS': 'Revision 1', - 'Logical_file_id': 'psp_fld_l2_rfs_lfr_20190409_v01', - 'Mission_group': 'PSP'}, - 'detector': 'lfr', - 'instrument': 'FIELDS/RFS', - 'observatory': 'PSP', - 'start_time': start_time, - 'end_time': end_time, - 'wavelength': a.Wavelength(10.546879882812501 * u.kHz, 1687.5 * u.kHz), - 'times': start_time + np.linspace(0, (end_time - start_time).to_value('s'), 12359) * u.s, - 'freqs': [10546.88, 18750., 28125., 37500., 46875., 56250., 65625., 75000., 84375., 89062.5, - 94921.88, 100781.25, 106640.62, 112500., 118359.38, 125390.62, 132421.88, 140625., - 146484.38, 157031.25, 166406.25, 175781.25, 186328.12, 196875., 208593.75, - 220312.5, 233203.12, 247265.62, 261328.12, 276562.5, 292968.75, 309375., 328125., - 346875., 366796.88, 387890.62, 411328.12, 434765.62, 459375., 486328.12, - 514453.12, 544921.9, 576562.5, 609375., 645703.1, 682031.25, 721875., 764062.5, - 808593.75, 855468.75, 904687.5, 957421.9, 1013671.9, 1072265.6, 1134375., - 1196484.4, 1265625., 1312500., 1368750., 1425000., 1481250., 1565625., 1621875., - 1687500.] * u.Hz + "cdf_meta": { + "TITLE": "PSP FIELDS RFS LFR data", + "Project": "PSP", + "Source_name": "PSP_FLD>Parker Solar Probe FIELDS", + "Descriptor": "RFS_LFR>Radio Frequency Spectrometer LFR", + "Data_type": "L2>Level 2 Data", + "Data_version": "01", + "MODS": "Revision 1", + "Logical_file_id": "psp_fld_l2_rfs_lfr_20190409_v01", + "Mission_group": "PSP", + }, + "detector": "lfr", + "instrument": "FIELDS/RFS", + "observatory": "PSP", + "start_time": start_time, + "end_time": end_time, + "wavelength": a.Wavelength(10.546879882812501 * u.kHz, 1687.5 * u.kHz), + "times": start_time + np.linspace(0, (end_time - start_time).to_value("s"), 12359) * u.s, + "freqs": [ + 10546.88, + 18750.0, + 28125.0, + 37500.0, + 46875.0, + 56250.0, + 65625.0, + 75000.0, + 84375.0, + 89062.5, + 94921.88, + 100781.25, + 106640.62, + 112500.0, + 118359.38, + 125390.62, + 132421.88, + 140625.0, + 146484.38, + 157031.25, + 166406.25, + 175781.25, + 186328.12, + 196875.0, + 208593.75, + 220312.5, + 233203.12, + 247265.62, + 261328.12, + 276562.5, + 292968.75, + 309375.0, + 328125.0, + 346875.0, + 366796.88, + 387890.62, + 411328.12, + 434765.62, + 459375.0, + 486328.12, + 514453.12, + 544921.9, + 576562.5, + 609375.0, + 645703.1, + 682031.25, + 721875.0, + 764062.5, + 808593.75, + 855468.75, + 904687.5, + 957421.9, + 1013671.9, + 1072265.6, + 1134375.0, + 1196484.4, + 1265625.0, + 1312500.0, + 1368750.0, + 1425000.0, + 1481250.0, + 1565625.0, + 1621875.0, + 1687500.0, + ] + * u.Hz, } array = np.zeros((64, 12359)) parse_path_moc.return_value = [(array, meta)] - file = Path('fake.cdf') + file = Path("fake.cdf") spec = Spectrogram(file) assert isinstance(spec, RFSSpectrogram) - assert spec.observatory == 'PSP' - assert spec.instrument == 'FIELDS/RFS' - assert spec.detector == 'LFR' + assert spec.observatory == "PSP" + assert spec.instrument == "FIELDS/RFS" + assert spec.detector == "LFR" # TODO check why not exact prob base on spacecrast ET so won't match utc exacly assert spec.start_time.datetime == datetime(2019, 4, 9, 0, 1, 16, 197889) assert spec.end_time.datetime == datetime(2019, 4, 10, 0, 1, 4, 997573) assert spec.wavelength.min.round(1) == 10.5 * u.kHz assert spec.wavelength.max == 1687.5 * u.kHz - assert spec.level == 'L2' + assert spec.level == "L2" assert spec.version == 1 -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_psp_rfs_hfr(parse_path_moc): - start_time = Time('2019-04-09 00:01:13.904188') - end_time = Time('2019-04-10 00:01:02.758315') + start_time = Time("2019-04-09 00:01:13.904188") + end_time = Time("2019-04-10 00:01:02.758315") meta = { - 'cdf_meta': { - 'TITLE': 'PSP FIELDS RFS HFR data', - 'Project': 'PSP', - 'Source_name': 'PSP_FLD>Parker Solar Probe FIELDS', - 'Descriptor': 'RFS_HFR>Radio Frequency Spectrometer HFR', - 'Data_type': 'L2>Level 2 Data', - 'Data_version': '01', - 'MODS': 'Revision 1', - 'Logical_file_id': 'psp_fld_l2_rfs_lfr_20190409_v01', - 'Mission_group': 'PSP'}, - 'detector': 'hfr', - 'instrument': 'FIELDS/RFS', - 'observatory': 'PSP', - 'start_time': start_time, - 'end_time': end_time, - 'wavelength': a.Wavelength(1275.0*u.kHz, 19171.876*u.kHz), - 'times': start_time + np.linspace(0, (end_time - start_time).to_value('s'), 12359) * u.s, - 'freqs': [1275000., 1321875., 1378125., 1425000., 1471875., 1575000., 1621875., 1678125., - 1771875., 1828125., 1921875., 2025000., 2128125., 2221875., 2278125., 2371875., - 2521875., 2625000., 2728125., 2878125., 2971875., 3121875., 3271875., 3375000., - 3525000., 3721875., 3871875., 4021875., 4228125., 4425000., 4575000., 4771875., - 5025000., 5221875., 5475000., 5728125., 5971875., 6225000., 6478125., 6778125., - 7078125., 7425000., 7725000., 8071875., 8428125., 8821875., 9178125., 9571875., - 10021875., 10471875., 10921875., 11428125., 11925000., 12421875., 13021875., - 13575000., 14175000., 14821875., 15478125., 16125000., 16875000., 17625000., - 18375000., 19171876.] * u.Hz + "cdf_meta": { + "TITLE": "PSP FIELDS RFS HFR data", + "Project": "PSP", + "Source_name": "PSP_FLD>Parker Solar Probe FIELDS", + "Descriptor": "RFS_HFR>Radio Frequency Spectrometer HFR", + "Data_type": "L2>Level 2 Data", + "Data_version": "01", + "MODS": "Revision 1", + "Logical_file_id": "psp_fld_l2_rfs_lfr_20190409_v01", + "Mission_group": "PSP", + }, + "detector": "hfr", + "instrument": "FIELDS/RFS", + "observatory": "PSP", + "start_time": start_time, + "end_time": end_time, + "wavelength": a.Wavelength(1275.0 * u.kHz, 19171.876 * u.kHz), + "times": start_time + np.linspace(0, (end_time - start_time).to_value("s"), 12359) * u.s, + "freqs": [ + 1275000.0, + 1321875.0, + 1378125.0, + 1425000.0, + 1471875.0, + 1575000.0, + 1621875.0, + 1678125.0, + 1771875.0, + 1828125.0, + 1921875.0, + 2025000.0, + 2128125.0, + 2221875.0, + 2278125.0, + 2371875.0, + 2521875.0, + 2625000.0, + 2728125.0, + 2878125.0, + 2971875.0, + 3121875.0, + 3271875.0, + 3375000.0, + 3525000.0, + 3721875.0, + 3871875.0, + 4021875.0, + 4228125.0, + 4425000.0, + 4575000.0, + 4771875.0, + 5025000.0, + 5221875.0, + 5475000.0, + 5728125.0, + 5971875.0, + 6225000.0, + 6478125.0, + 6778125.0, + 7078125.0, + 7425000.0, + 7725000.0, + 8071875.0, + 8428125.0, + 8821875.0, + 9178125.0, + 9571875.0, + 10021875.0, + 10471875.0, + 10921875.0, + 11428125.0, + 11925000.0, + 12421875.0, + 13021875.0, + 13575000.0, + 14175000.0, + 14821875.0, + 15478125.0, + 16125000.0, + 16875000.0, + 17625000.0, + 18375000.0, + 19171876.0, + ] + * u.Hz, } array = np.zeros((64, 12359)) parse_path_moc.return_value = [(array, meta)] - file = Path('fake.cdf') + file = Path("fake.cdf") spec = Spectrogram(file) assert isinstance(spec, RFSSpectrogram) - assert spec.observatory == 'PSP' - assert spec.instrument == 'FIELDS/RFS' - assert spec.detector == 'HFR' + assert spec.observatory == "PSP" + assert spec.instrument == "FIELDS/RFS" + assert spec.detector == "HFR" # TODO check why not exact prob base on spacecrast ET so won't match utc exacly assert spec.start_time.datetime == datetime(2019, 4, 9, 0, 1, 13, 904188) assert spec.end_time.datetime == datetime(2019, 4, 10, 0, 1, 2, 758315) assert spec.wavelength.min == 1275.0 * u.kHz assert spec.wavelength.max == 19171.876 * u.kHz - assert spec.level == 'L2' + assert spec.level == "L2" assert spec.version == 1 diff --git a/radiospectra/spectrogram2/tests/test_rstn.py b/radiospectra/spectrogram2/tests/test_rstn.py index 098d4a7..c2c650e 100644 --- a/radiospectra/spectrogram2/tests/test_rstn.py +++ b/radiospectra/spectrogram2/tests/test_rstn.py @@ -12,28 +12,28 @@ from radiospectra.spectrogram2.sources import RSTNSpectrogram -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_rstn(parse_path_moc): - start_time = Time('2020-01-01T06:17:38.000') - end_time = Time('2020-01-01T15:27:43.000') + start_time = Time("2020-01-01T06:17:38.000") + end_time = Time("2020-01-01T15:27:43.000") meta = { - 'instrument': 'RSTN', - 'observatory': 'San Vito', - 'start_time': start_time, - 'end_time': end_time, - 'detector': 'RSTN', - 'wavelength': a.Wavelength(25000.0 * u.kHz, 180000.0 * u.kHz), - 'freqs': np.concatenate([np.linspace(25, 75, 401), np.linspace(75, 180, 401)])*u.MHz, - 'times': start_time + np.linspace(0, (end_time-start_time).to_value('s'), 11003)*u.s + "instrument": "RSTN", + "observatory": "San Vito", + "start_time": start_time, + "end_time": end_time, + "detector": "RSTN", + "wavelength": a.Wavelength(25000.0 * u.kHz, 180000.0 * u.kHz), + "freqs": np.concatenate([np.linspace(25, 75, 401), np.linspace(75, 180, 401)]) * u.MHz, + "times": start_time + np.linspace(0, (end_time - start_time).to_value("s"), 11003) * u.s, } array = np.zeros((802, 11003)) parse_path_moc.return_value = [(array, meta)] - file = Path('fakes.srs') + file = Path("fakes.srs") spec = Spectrogram(file) assert isinstance(spec, RSTNSpectrogram) - assert spec.observatory == 'SAN VITO' - assert spec.instrument == 'RSTN' - assert spec.detector == 'RSTN' + assert spec.observatory == "SAN VITO" + assert spec.instrument == "RSTN" + assert spec.detector == "RSTN" assert spec.start_time.datetime == datetime(2020, 1, 1, 6, 17, 38) assert spec.end_time.datetime == datetime(2020, 1, 1, 15, 27, 43) assert spec.wavelength.min == 25000 * u.kHz diff --git a/radiospectra/spectrogram2/tests/test_swaves.py b/radiospectra/spectrogram2/tests/test_swaves.py index 05f6c9a..4037a3d 100644 --- a/radiospectra/spectrogram2/tests/test_swaves.py +++ b/radiospectra/spectrogram2/tests/test_swaves.py @@ -12,57 +12,104 @@ from radiospectra.spectrogram2.sources import SWAVESSpectrogram -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_swaves_lfr(parse_path_moc): meta = { - 'instrument': 'swaves', - 'observatory': 'STEREO A', - 'product': 'average', - 'start_time': Time('2020-11-28 00:00:00'), - 'end_time': Time('2020-11-28 23:59:00'), - 'wavelength': a.Wavelength(2.6 * u.kHz, 153.4 * u.kHz), - 'detector': 'lfr', - 'freqs': [2.6, 2.8, 3.1, 3.4, 3.7, 4., 4.4, 4.8, 5.2, 5.7, 6.2, 6.8, 7.4, 8.1, 8.8, 9.6, - 10.4, 11.4, 12.4, 13.6, 14.8, 16.1, 17.6, 19.2, 20.9, 22.8, 24.9, 27.1, 29.6, - 32.2, 35.2, 38.3, 41.8, 45.6, 49.7, 54.2, 59.1, 64.5, 70.3, 76.7, 83.6, 91.2, - 99.4, 108.4, 118.3, 129., 140.6, 153.4] * u.kHz, - 'times': np.arange(1440) * u.min + "instrument": "swaves", + "observatory": "STEREO A", + "product": "average", + "start_time": Time("2020-11-28 00:00:00"), + "end_time": Time("2020-11-28 23:59:00"), + "wavelength": a.Wavelength(2.6 * u.kHz, 153.4 * u.kHz), + "detector": "lfr", + "freqs": [ + 2.6, + 2.8, + 3.1, + 3.4, + 3.7, + 4.0, + 4.4, + 4.8, + 5.2, + 5.7, + 6.2, + 6.8, + 7.4, + 8.1, + 8.8, + 9.6, + 10.4, + 11.4, + 12.4, + 13.6, + 14.8, + 16.1, + 17.6, + 19.2, + 20.9, + 22.8, + 24.9, + 27.1, + 29.6, + 32.2, + 35.2, + 38.3, + 41.8, + 45.6, + 49.7, + 54.2, + 59.1, + 64.5, + 70.3, + 76.7, + 83.6, + 91.2, + 99.4, + 108.4, + 118.3, + 129.0, + 140.6, + 153.4, + ] + * u.kHz, + "times": np.arange(1440) * u.min, } array = np.zeros((48, 1440)) parse_path_moc.return_value = [(array, meta)] - file = Path('fake.dat') + file = Path("fake.dat") spec = Spectrogram(file) assert isinstance(spec, SWAVESSpectrogram) - assert spec.observatory == 'STEREO A' - assert spec.instrument == 'SWAVES' - assert spec.detector == 'LFR' + assert spec.observatory == "STEREO A" + assert spec.instrument == "SWAVES" + assert spec.detector == "LFR" assert spec.start_time.datetime == datetime(2020, 11, 28, 0, 0) assert spec.end_time.datetime == datetime(2020, 11, 28, 23, 59) assert spec.wavelength.min == 2.6 * u.kHz assert spec.wavelength.max == 153.4 * u.kHz -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_swaves_hfr(parse_path_moc): meta = { - 'instrument': 'swaves', - 'observatory': 'STEREO A', - 'product': 'average', - 'start_time': Time('2020-11-28 00:00:00'), - 'end_time': Time('2020-11-28 23:59:00'), - 'wavelength': a.Wavelength(125.0 * u.kHz, 16025.0 * u.kHz), - 'detector': 'hfr', - 'freqs': np.linspace(125, 16025, 319) * u.kHz, - 'times': np.arange(1440) * u.min, + "instrument": "swaves", + "observatory": "STEREO A", + "product": "average", + "start_time": Time("2020-11-28 00:00:00"), + "end_time": Time("2020-11-28 23:59:00"), + "wavelength": a.Wavelength(125.0 * u.kHz, 16025.0 * u.kHz), + "detector": "hfr", + "freqs": np.linspace(125, 16025, 319) * u.kHz, + "times": np.arange(1440) * u.min, } array = np.zeros((319, 1440)) parse_path_moc.return_value = [(array, meta)] - file = Path('fake.dat') + file = Path("fake.dat") spec = Spectrogram(file) assert isinstance(spec, SWAVESSpectrogram) - assert spec.observatory == 'STEREO A' - assert spec.instrument == 'SWAVES' - assert spec.detector == 'HFR' + assert spec.observatory == "STEREO A" + assert spec.instrument == "SWAVES" + assert spec.detector == "HFR" assert spec.start_time.datetime == datetime(2020, 11, 28, 0, 0) assert spec.end_time.datetime == datetime(2020, 11, 28, 23, 59) assert spec.wavelength.min == 125 * u.kHz diff --git a/radiospectra/spectrogram2/tests/test_waves.py b/radiospectra/spectrogram2/tests/test_waves.py index 09431fd..5c85b5f 100644 --- a/radiospectra/spectrogram2/tests/test_waves.py +++ b/radiospectra/spectrogram2/tests/test_waves.py @@ -12,52 +12,52 @@ from radiospectra.spectrogram2.sources import WAVESSpectrogram -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_waves_rad1(parse_path_moc): meta = { - 'instrument': 'WAVES', - 'observatory': 'wind', - 'start_time': Time('2020-11-28 00:00:00'), - 'end_time': Time('2020-11-28 23:59:00'), - 'wavelength': a.Wavelength(20*u.kHz, 1040*u.kHz), - 'detector': 'rad1', - 'freqs': np.linspace(20, 1040, 256) * u.kHz, - 'times': np.arange(1440) * u.min + "instrument": "WAVES", + "observatory": "wind", + "start_time": Time("2020-11-28 00:00:00"), + "end_time": Time("2020-11-28 23:59:00"), + "wavelength": a.Wavelength(20 * u.kHz, 1040 * u.kHz), + "detector": "rad1", + "freqs": np.linspace(20, 1040, 256) * u.kHz, + "times": np.arange(1440) * u.min, } array = np.zeros((256, 1440)) parse_path_moc.return_value = [(array, meta)] - file = Path('fake.r1') + file = Path("fake.r1") spec = Spectrogram(file) assert isinstance(spec, WAVESSpectrogram) - assert spec.observatory == 'WIND' - assert spec.instrument == 'WAVES' - assert spec.detector == 'RAD1' + assert spec.observatory == "WIND" + assert spec.instrument == "WAVES" + assert spec.detector == "RAD1" assert spec.start_time.datetime == datetime(2020, 11, 28, 0, 0) assert spec.end_time.datetime == datetime(2020, 11, 28, 23, 59) assert spec.wavelength.min == 20.0 * u.kHz assert spec.wavelength.max == 1040.0 * u.kHz -@mock.patch('radiospectra.spectrogram2.spectrogram.parse_path') +@mock.patch("radiospectra.spectrogram2.spectrogram.parse_path") def test_waves_rad2(parse_path_moc): meta = { - 'instrument': 'WAVES', - 'observatory': 'WIND', - 'start_time': Time('2020-11-28 00:00:00'), - 'end_time': Time('2020-11-28 23:59:00'), - 'wavelength': a.Wavelength(1.075*u.MHz, 13.825*u.MHz), - 'detector': 'RAD2', - 'freqs': np.linspace(1.075, 13.825, 256) * u.MHz, - 'times': np.arange(1440) * u.min, + "instrument": "WAVES", + "observatory": "WIND", + "start_time": Time("2020-11-28 00:00:00"), + "end_time": Time("2020-11-28 23:59:00"), + "wavelength": a.Wavelength(1.075 * u.MHz, 13.825 * u.MHz), + "detector": "RAD2", + "freqs": np.linspace(1.075, 13.825, 256) * u.MHz, + "times": np.arange(1440) * u.min, } array = np.zeros((319, 1440)) parse_path_moc.return_value = [(array, meta)] - file = Path('fake.dat') + file = Path("fake.dat") spec = Spectrogram(file) assert isinstance(spec, WAVESSpectrogram) - assert spec.observatory == 'WIND' - assert spec.instrument == 'WAVES' - assert spec.detector == 'RAD2' + assert spec.observatory == "WIND" + assert spec.instrument == "WAVES" + assert spec.detector == "RAD2" assert spec.start_time.datetime == datetime(2020, 11, 28, 0, 0) assert spec.end_time.datetime == datetime(2020, 11, 28, 23, 59) assert spec.wavelength.min == 1.075 * u.MHz diff --git a/radiospectra/spectrum.py b/radiospectra/spectrum.py index 66425c4..f8e2c27 100644 --- a/radiospectra/spectrum.py +++ b/radiospectra/spectrum.py @@ -1,7 +1,7 @@ import numpy as np from matplotlib import pyplot as plt -__all__ = ['Spectrum'] +__all__ = ["Spectrum"] class Spectrum(np.ndarray): @@ -27,12 +27,13 @@ class Spectrum(np.ndarray): >>> spec = Spectrum(data, freq_axis) >>> spec.peek() # doctest: +SKIP """ + def __new__(cls, data, *args, **kwargs): return np.asarray(data).view(cls) def __init__(self, data, freq_axis): if np.shape(data)[0] != np.shape(freq_axis)[0]: - raise ValueError('Dimensions of data and frequency axis do not match') + raise ValueError("Dimensions of data and frequency axis do not match") self.freq_axis = freq_axis def plot(self, axes=None, **matplot_args): diff --git a/radiospectra/tests/setup_package.py b/radiospectra/tests/setup_package.py index f2fd9ed..17b092d 100644 --- a/radiospectra/tests/setup_package.py +++ b/radiospectra/tests/setup_package.py @@ -1,3 +1,2 @@ def get_package_data(): - return { - _ASTROPY_PACKAGE_NAME_ + '.tests': ['coveragerc']} + return {_ASTROPY_PACKAGE_NAME_ + ".tests": ["coveragerc"]} diff --git a/radiospectra/tests/test_callisto.py b/radiospectra/tests/test_callisto.py index c0a8425..b1ef384 100644 --- a/radiospectra/tests/test_callisto.py +++ b/radiospectra/tests/test_callisto.py @@ -15,13 +15,13 @@ @pytest.fixture def CALLISTO_IMAGE(): - path = Path(__file__).parent / 'data' / 'BIR_20110607_062400_10.fit' + path = Path(__file__).parent / "data" / "BIR_20110607_062400_10.fit" return str(path) @pytest.fixture def CALLISTO_IMAGE_GLOB_KEY(): - return 'BIR_*' + return "BIR_*" @pytest.fixture @@ -37,19 +37,15 @@ def test_read(CALLISTO_IMAGE): assert ca.shape == (200, 3600) assert ca.t_delt == 0.25 # Test linearity of time axis. - assert np.array_equal( - ca.time_axis, np.linspace(0, 0.25 * (ca.shape[1] - 1), ca.shape[1]) - ) + assert np.array_equal(ca.time_axis, np.linspace(0, 0.25 * (ca.shape[1] - 1), ca.shape[1])) assert ca.dtype == np.uint8 @pytest.mark.remote_data def test_query(): - URL = 'http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/2011/09/22/' + URL = "http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/2011/09/22/" - result = list(query( - datetime(2011, 9, 22, 5), datetime(2011, 9, 22, 6), {"BIR"} - )) + result = list(query(datetime(2011, 9, 22, 5), datetime(2011, 9, 22, 6), {"BIR"})) RESULTS = [ "BIR_20110922_050000_01.fit.gz", "BIR_20110922_051500_01.fit.gz", @@ -70,9 +66,7 @@ def test_query(): @pytest.mark.xfail def test_query_number(): - result = list(query( - datetime(2011, 9, 22, 5), datetime(2011, 9, 22, 6), {("BIR", 1)} - )) + result = list(query(datetime(2011, 9, 22, 5), datetime(2011, 9, 22, 6), {("BIR", 1)})) RESULTS = [ "BIR_20110922_050000_01.fit.gz", "BIR_20110922_051500_01.fit.gz", @@ -91,9 +85,7 @@ def test_query_number(): def test_download(): directory = mkdtemp() try: - result = query( - datetime(2011, 9, 22, 5), datetime(2011, 9, 22, 6), {("BIR", 1)} - ) + result = query(datetime(2011, 9, 22, 5), datetime(2011, 9, 22, 6), {("BIR", 1)}) RESULTS = [ "BIR_20110922_050000_01.fit.gz", "BIR_20110922_051500_01.fit.gz", @@ -118,20 +110,14 @@ def test_create_file_kw(CALLISTO_IMAGE): @pytest.mark.remote_data def test_create_url(): - URL = ( - "http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/2011/09/22/" - "BIR_20110922_050000_01.fit.gz" - ) + URL = "http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/2011/09/22/" "BIR_20110922_050000_01.fit.gz" ca = CallistoSpectrogram.create(URL) assert np.array_equal(ca.data, CallistoSpectrogram.read(URL).data) @pytest.mark.remote_data def test_create_url_kw(): - URL = ( - "http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/2011/09/22/" - "BIR_20110922_050000_01.fit.gz" - ) + URL = "http://soleil.i4ds.ch/solarradio/data/2002-20yy_Callisto/2011/09/22/" "BIR_20110922_050000_01.fit.gz" ca = CallistoSpectrogram.create(url=URL) assert np.array_equal(ca.data, CallistoSpectrogram.read(URL).data) @@ -148,20 +134,15 @@ def test_create_single_glob(CALLISTO_IMAGE, CALLISTO_IMAGE_GLOB_INDEX, CALLISTO_ # ca = CallistoSpectrogram.create(singlepattern=PATTERN) # assert np.array_equal(ca[0].data, CallistoSpectrogram.read(CALLISTO_IMAGE).data) + def test_create_glob_kw(CALLISTO_IMAGE, CALLISTO_IMAGE_GLOB_INDEX, CALLISTO_IMAGE_GLOB_KEY): - PATTERN = os.path.join( - os.path.dirname(CALLISTO_IMAGE), - CALLISTO_IMAGE_GLOB_KEY - ) + PATTERN = os.path.join(os.path.dirname(CALLISTO_IMAGE), CALLISTO_IMAGE_GLOB_KEY) ca = CallistoSpectrogram.create(pattern=PATTERN)[CALLISTO_IMAGE_GLOB_INDEX] assert_allclose(ca.data, CallistoSpectrogram.read(CALLISTO_IMAGE).data) def test_create_glob(CALLISTO_IMAGE_GLOB_KEY, CALLISTO_IMAGE): - PATTERN = os.path.join( - str(Path(CALLISTO_IMAGE).parent), - CALLISTO_IMAGE_GLOB_KEY - ) + PATTERN = os.path.join(str(Path(CALLISTO_IMAGE).parent), CALLISTO_IMAGE_GLOB_KEY) ca = CallistoSpectrogram.create(PATTERN) assert len([ca]) == 1 @@ -174,31 +155,19 @@ def test_minimum_pairs_commotative(): def test_minimum_pairs_end(): - assert ( - list(minimal_pairs([0, 1, 2, 4], [1, 2, 3, 4])) == - [(1, 0, 0), (2, 1, 0), (3, 3, 0)] - ) + assert list(minimal_pairs([0, 1, 2, 4], [1, 2, 3, 4])) == [(1, 0, 0), (2, 1, 0), (3, 3, 0)] def test_minimum_pairs_end_more(): - assert ( - list(minimal_pairs([0, 1, 2, 4, 8], [1, 2, 3, 4])) == - [(1, 0, 0), (2, 1, 0), (3, 3, 0)] - ) + assert list(minimal_pairs([0, 1, 2, 4, 8], [1, 2, 3, 4])) == [(1, 0, 0), (2, 1, 0), (3, 3, 0)] def test_minimum_pairs_end_diff(): - assert ( - list(minimal_pairs([0, 1, 2, 8], [1, 2, 3, 4])) == - [(1, 0, 0), (2, 1, 0), (3, 3, 4)] - ) + assert list(minimal_pairs([0, 1, 2, 8], [1, 2, 3, 4])) == [(1, 0, 0), (2, 1, 0), (3, 3, 4)] def test_closest(): - assert ( - list(minimal_pairs([50, 60], [0, 10, 20, 30, 40, 51, 52])) == - [(0, 5, 1), (1, 6, 8)] - ) + assert list(minimal_pairs([50, 60], [0, 10, 20, 30, 40, 51, 52])) == [(0, 5, 1), (1, 6, 8)] def test_homogenize_factor(): @@ -212,13 +181,13 @@ def test_homogenize_factor(): datetime(2011, 1, 1, 1), 0, 1, - 'Time', - 'Frequency', - 'Test', + "Time", + "Frequency", + "Test", None, None, None, - False + False, ) b = 2 * a c2 = CallistoSpectrogram( @@ -229,18 +198,16 @@ def test_homogenize_factor(): datetime(2011, 1, 1, 1), 0, 1, - 'Time', - 'Frequency', - 'Test', + "Time", + "Frequency", + "Test", None, None, None, - False + False, ) - pairs_indices, factors, constants = c1._homogenize_params( - c2, 0 - ) + pairs_indices, factors, constants = c1._homogenize_params(c2, 0) assert pairs_indices == [(0, 0)] assert_array_almost_equal(factors, [0.5], 2) @@ -259,13 +226,13 @@ def test_homogenize_constant(): datetime(2011, 1, 1, 1), 0, 1, - 'Time', - 'Frequency', - 'Test', + "Time", + "Frequency", + "Test", None, None, None, - False + False, ) b = a + 10 c2 = CallistoSpectrogram( @@ -276,18 +243,16 @@ def test_homogenize_constant(): datetime(2011, 1, 1, 1), 0, 1, - 'Time', - 'Frequency', - 'Test', + "Time", + "Frequency", + "Test", None, None, None, - False + False, ) - pairs_indices, factors, constants = c1._homogenize_params( - c2, 0 - ) + pairs_indices, factors, constants = c1._homogenize_params(c2, 0) assert pairs_indices == [(0, 0)] assert_array_almost_equal(factors, [1], 2) @@ -306,13 +271,13 @@ def test_homogenize_both(): datetime(2011, 1, 1, 1), 0, 1, - 'Time', - 'Frequency', - 'Test', + "Time", + "Frequency", + "Test", None, None, None, - False + False, ) b = 2 * a + 1 c2 = CallistoSpectrogram( @@ -323,18 +288,16 @@ def test_homogenize_both(): datetime(2011, 1, 1, 1), 0, 1, - 'Time', - 'Frequency', - 'Test', + "Time", + "Frequency", + "Test", None, None, None, - False + False, ) - pairs_indices, factors, constants = c1._homogenize_params( - c2, 0 - ) + pairs_indices, factors, constants = c1._homogenize_params(c2, 0) assert pairs_indices == [(0, 0)] assert_array_almost_equal(factors, [0.5], 2) @@ -353,37 +316,32 @@ def test_homogenize_rightfq(): datetime(2011, 1, 1, 1), 0, 1, - 'Time', - 'Frequency', - 'Test', + "Time", + "Frequency", + "Test", None, None, None, - False + False, ) b = 2 * a + 1 c2 = CallistoSpectrogram( - np.concatenate([ - np.arange(3600)[np.newaxis, :], b, - np.arange(3600)[np.newaxis, :] - ], 0), + np.concatenate([np.arange(3600)[np.newaxis, :], b, np.arange(3600)[np.newaxis, :]], 0), np.arange(3600), np.array([0, 1, 2]), datetime(2011, 1, 1), datetime(2011, 1, 1, 1), 0, 1, - 'Time', - 'Frequency', - 'Test', + "Time", + "Frequency", + "Test", None, None, None, - False - ) - pairs_indices, factors, constants = c1._homogenize_params( - c2, 0 + False, ) + pairs_indices, factors, constants = c1._homogenize_params(c2, 0) assert pairs_indices == [(0, 1)] assert_array_almost_equal(factors, [0.5], 2) assert_array_almost_equal(constants, [-0.5], 2) diff --git a/radiospectra/tests/test_spectrogram.py b/radiospectra/tests/test_spectrogram.py index 743fe2c..e949f30 100644 --- a/radiospectra/tests/test_spectrogram.py +++ b/radiospectra/tests/test_spectrogram.py @@ -27,9 +27,12 @@ def dict_eq(one, other): def mk_spec(image): return Spectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 10), datetime(2010, 10, 10, 1), 0 + datetime(2010, 10, 10), + datetime(2010, 10, 10, 1), + 0, ) @@ -48,9 +51,7 @@ def test_subtract_bg(): spectrogram = mk_spec(image) sbg = spectrogram.subtract_bg() - assert np.array_equal( - spectrogram.subtract_bg()[:, 1800:].data, signal - ) + assert np.array_equal(spectrogram.subtract_bg()[:, 1800:].data, signal) assert dict_eq(spectrogram._get_params(), sbg._get_params()) @@ -99,8 +100,7 @@ def test_slice_time_axis(): new = spectrogram[:, 59:3599] assert new.shape == (200, 3600 - 59 - 1) assert new.t_init == 59 - assert np.array_equal(new.time_axis, - np.linspace(0, 3600 - 60 - 1, 3600 - 59 - 1)) + assert np.array_equal(new.time_axis, np.linspace(0, 3600 - 60 - 1, 3600 - 59 - 1)) assert new.start == datetime(2010, 10, 10, 0, 0, 59) assert np.array_equal(new.data, rnd[:, 59:3599]) @@ -129,9 +129,13 @@ def test_slice_both_axis(): def test_time_to_x(): image = np.zeros((200, 3600)) spectrogram = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 10), datetime(2010, 10, 10, 1), 0, 1 + datetime(2010, 10, 10), + datetime(2010, 10, 10, 1), + 0, + 1, ) ret = spectrogram.time_to_x(datetime(2010, 10, 10, 0, 0, 59)) assert isinstance(ret, int) @@ -141,9 +145,11 @@ def test_time_to_x(): def test_time_to_x_nonlinear(): image = np.zeros((200, 3600)) spectrogram = Spectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 10), datetime(2010, 10, 10, 1) + datetime(2010, 10, 10), + datetime(2010, 10, 10, 1), ) ret = spectrogram.time_to_x(datetime(2010, 10, 10, 0, 0, 59)) assert isinstance(ret, int) @@ -153,22 +159,27 @@ def test_time_to_x_nonlinear(): def test_join(): image = np.random.rand(200, 3600) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 10), datetime(2010, 10, 10, 0, 30), 0, 0.5, + datetime(2010, 10, 10), + datetime(2010, 10, 10, 0, 30), + 0, + 0.5, ) image = np.random.rand(200, 3600) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2010, 10, 10, 0, 29), - datetime(2010, 10, 10, 1, 29), 1799, 1, + datetime(2010, 10, 10, 1, 29), + 1799, + 1, ) - z = LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=0 - ) + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=0) # The - 1 is because resampling other produces an image of size # 2 * 3600 - 1 # The - 2 is because there is one second overlap. @@ -185,66 +196,81 @@ def test_join(): def test_join_dtype(): image = np.random.rand(200, 3600).astype(np.uint8) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 10), datetime(2010, 10, 10, 0, 30), 0, 0.5, + datetime(2010, 10, 10), + datetime(2010, 10, 10, 0, 30), + 0, + 0.5, ) image = np.random.rand(200, 3600).astype(np.uint8) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2010, 10, 10, 0, 29), - datetime(2010, 10, 10, 1, 29), 1799, 1, + datetime(2010, 10, 10, 1, 29), + 1799, + 1, ) - z = LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=0 - ) - assert z.dtype == np.dtype('uint8') + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=0) + assert z.dtype == np.dtype("uint8") def test_join_different_dtype(): image = np.random.rand(200, 3600).astype(np.uint16) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 10), datetime(2010, 10, 10, 0, 30), 0, 0.5, + datetime(2010, 10, 10), + datetime(2010, 10, 10, 0, 30), + 0, + 0.5, ) image = np.random.rand(200, 3600).astype(np.uint8) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2010, 10, 10, 0, 29), - datetime(2010, 10, 10, 1, 29), 1799, 1, + datetime(2010, 10, 10, 1, 29), + 1799, + 1, ) - z = LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=0 - ) - assert z.dtype == np.dtype('uint16') + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=0) + assert z.dtype == np.dtype("uint16") def test_join_midnight(): image = np.random.rand(200, 3600) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2010, 10, 10, 23, 30), - datetime(2010, 10, 10, 23, 59, 59), 84600, 0.5, + datetime(2010, 10, 10, 23, 59, 59), + 84600, + 0.5, ) image = np.random.rand(200, 3600) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 11, 0, 0), datetime(2010, 10, 11, 1), 0, 1, + datetime(2010, 10, 11, 0, 0), + datetime(2010, 10, 11, 1), + 0, + 1, ) - z = LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=0 - ) + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=0) # The - 1 is because resampling other produces an image of size # 2 * 3600 - 1 assert z.shape == (200, 3 * 3600 - 1) @@ -257,22 +283,27 @@ def test_join_midnight(): def test_join_month(): image = np.random.rand(200, 3600) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2012, 7, 31, 23, 30), - datetime(2012, 7, 31, 23, 59, 59), 84600, 0.5, + datetime(2012, 7, 31, 23, 59, 59), + 84600, + 0.5, ) image = np.random.rand(200, 3600) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2012, 8, 1), datetime(2012, 8, 1, 1), 0, 1, + datetime(2012, 8, 1), + datetime(2012, 8, 1, 1), + 0, + 1, ) - z = LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=0 - ) + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=0) # The - 1 is because resampling other produces an image of size # 2 * 3600 - 1 assert z.shape == (200, 3 * 3600 - 1) @@ -285,22 +316,27 @@ def test_join_month(): def test_join_year(): image = np.random.rand(200, 3600) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2012, 12, 31, 23, 30), - datetime(2013, 1, 1, 0, 0, 0), 84600, 0.5, + datetime(2013, 1, 1, 0, 0, 0), + 84600, + 0.5, ) image = np.random.rand(200, 3600) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2013, 1, 1), datetime(2013, 1, 1, 1), 0, 1, + datetime(2013, 1, 1), + datetime(2013, 1, 1, 1), + 0, + 1, ) - z = LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=0 - ) + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=0) # The - 1 is because resampling other produces an image of size # 2 * 3600 - 1 assert z.shape == (200, 3 * 3600 - 1) @@ -313,21 +349,32 @@ def test_join_year(): def test_join_over_midnight(): image = np.random.rand(200, 3600) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2010, 10, 10, 23, 45), - datetime(2010, 10, 11, 0, 15,), 85500, 0.5, + datetime( + 2010, + 10, + 11, + 0, + 15, + ), + 85500, + 0.5, ) image = np.random.rand(200, 3600) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 11, 0, 15), datetime(2010, 10, 11, 1, 15), 900, 1, + datetime(2010, 10, 11, 0, 15), + datetime(2010, 10, 11, 1, 15), + 900, + 1, ) - z = LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=0 - ) + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=0) # The - 1 is because resampling other produces an image of size # 2 * 3600 - 1 @@ -342,45 +389,66 @@ def test_join_over_midnight(): def test_join_gap(): image = np.random.rand(200, 3600) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2010, 10, 10, 23, 45), - datetime(2010, 10, 11, 0, 15,), 85500, 0.5, + datetime( + 2010, + 10, + 11, + 0, + 15, + ), + 85500, + 0.5, ) image = np.random.rand(200, 3600) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2010, 10, 11, 0, 15, 1), - datetime(2010, 10, 11, 1, 15), 901, 1, + datetime(2010, 10, 11, 1, 15), + 901, + 1, ) with pytest.raises(ValueError) as excinfo: - LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=0 - ) + LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=0) assert excinfo.value.message == "Too large gap." def test_join_with_gap(): image = np.random.rand(200, 3600) one = LinearTimeSpectrogram( - image, np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), datetime(2010, 10, 10, 23, 45), - datetime(2010, 10, 11, 0, 15,), 85500, 0.5, + datetime( + 2010, + 10, + 11, + 0, + 15, + ), + 85500, + 0.5, ) image = np.random.rand(200, 3600) other = LinearTimeSpectrogram( - image, np.linspace(0, image.shape[1] - 1, image.shape[1]), + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 11, 0, 15), datetime(2010, 10, 11, 1, 15), 901, 1, + datetime(2010, 10, 11, 0, 15), + datetime(2010, 10, 11, 1, 15), + 901, + 1, ) - z = LinearTimeSpectrogram.join_many( - [one, other], nonlinear=False, maxgap=1, fill=0 - ) + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=1, fill=0) # The - 1 is because resampling other produces an image of size # 2 * 3600 - 1 @@ -396,24 +464,34 @@ def test_join_with_gap(): def test_join_with_gap_fill(): image = np.random.rand(200, 3600) - one = LinearTimeSpectrogram(image, - np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), - np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 10, 23, 45), - datetime(2010, 10, 11, 0, 15,), 85500, 0.5, - ) + one = LinearTimeSpectrogram( + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + np.linspace(0, image.shape[0] - 1, image.shape[0]), + datetime(2010, 10, 10, 23, 45), + datetime( + 2010, + 10, + 11, + 0, + 15, + ), + 85500, + 0.5, + ) image = np.random.rand(200, 3600) - other = LinearTimeSpectrogram(image, - np.linspace(0, image.shape[1] - 1, image.shape[1]), - np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 11, 0, 15), - datetime(2010, 10, 11, 1, 15), 901, 1, - ) - - z = LinearTimeSpectrogram.join_many([one, other], - nonlinear=False, maxgap=2, fill=np.NaN - ) + other = LinearTimeSpectrogram( + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), + np.linspace(0, image.shape[0] - 1, image.shape[0]), + datetime(2010, 10, 11, 0, 15), + datetime(2010, 10, 11, 1, 15), + 901, + 1, + ) + + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=False, maxgap=2, fill=np.NaN) # The - 1 is because resampling other produces an image of size # 2 * 3600 - 1 # The + 2 is because there is one second without data inserted. @@ -431,28 +509,36 @@ def test_join_with_gap_fill(): def test_join_nonlinear(): image = np.random.rand(200, 3600) - one = LinearTimeSpectrogram(image, - np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), - np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 10, 23, 45), - datetime(2010, 10, 11, 0, 15,), - 85500, 0.5, - ) + one = LinearTimeSpectrogram( + image, + np.linspace(0, 0.5 * (image.shape[1] - 1), image.shape[1]), + np.linspace(0, image.shape[0] - 1, image.shape[0]), + datetime(2010, 10, 10, 23, 45), + datetime( + 2010, + 10, + 11, + 0, + 15, + ), + 85500, + 0.5, + ) image = np.random.rand(200, 3600) - other = LinearTimeSpectrogram(image, - np.linspace(0, image.shape[1] - 1, image.shape[1]), - np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 10, 11, 0, 15), - datetime(2010, 10, 11, 1, 15), - 901, 1, - ) + other = LinearTimeSpectrogram( + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), + np.linspace(0, image.shape[0] - 1, image.shape[0]), + datetime(2010, 10, 11, 0, 15), + datetime(2010, 10, 11, 1, 15), + 901, + 1, + ) oz = other.resample_time(0.5) - z = LinearTimeSpectrogram.join_many([one, other], - nonlinear=True, maxgap=2 - ) + z = LinearTimeSpectrogram.join_many([one, other], nonlinear=True, maxgap=2) # The - 1 is because resampling other produces an image of size # 2 * 3600 - 1 @@ -466,22 +552,27 @@ def test_join_nonlinear(): def test_auto_t_init(): image = np.random.rand(200, 3600) - assert Spectrogram(image, - np.linspace(0, image.shape[1] - 1, image.shape[1]), - np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30) - ).t_init == 900 + assert ( + Spectrogram( + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), + np.linspace(0, image.shape[0] - 1, image.shape[0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + ).t_init + == 900 + ) def test_rescale(): image = np.random.rand(200, 3600) * 43 - spec = Spectrogram(image, - np.linspace(0, image.shape[1] - 1, image.shape[1]), - np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30) - ) + spec = Spectrogram( + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), + np.linspace(0, image.shape[0] - 1, image.shape[0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + ) nspec = spec.rescale() @@ -492,43 +583,39 @@ def test_rescale(): def test_rescale_error(): image = np.zeros((200, 3600)) - spec = Spectrogram(image, - np.linspace(0, image.shape[1] - 1, image.shape[1]), - np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30) - ) + spec = Spectrogram( + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), + np.linspace(0, image.shape[0] - 1, image.shape[0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + ) with pytest.raises(ValueError) as excinfo: spec.rescale(0, 1) - assert ( - excinfo.value.message == - "Spectrogram needs to contain distinct values.") + assert excinfo.value.message == "Spectrogram needs to contain distinct values." def test_rescale_error2(): image = np.random.rand(200, 3600) * 43 - spec = Spectrogram(image, - np.linspace(0, image.shape[1] - 1, image.shape[1]), - np.linspace(0, image.shape[0] - 1, image.shape[0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30) - ) + spec = Spectrogram( + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), + np.linspace(0, image.shape[0] - 1, image.shape[0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + ) with pytest.raises(ValueError) as excinfo: spec.rescale(1, 1) - assert (excinfo.value.message == - "Maximum and minimum must be different.") + assert excinfo.value.message == "Maximum and minimum must be different." def test_resample(): image = np.array([[0, 1, 2], [0, 1, 2]]) - spec = LinearTimeSpectrogram(image, - np.array([0, 1, 2]), np.array([0]), - datetime(2012, 1, 1), - datetime(2012, 1, 1, 0, 0, 3), - 0, 1 - ) + spec = LinearTimeSpectrogram( + image, np.array([0, 1, 2]), np.array([0]), datetime(2012, 1, 1), datetime(2012, 1, 1, 0, 0, 3), 0, 1 + ) r = spec.resample_time(0.5) assert r.shape[1] == 5 assert np.array_equal(r.time_axis, np.linspace(0, 2, 5)) @@ -536,65 +623,64 @@ def test_resample(): def test_upsample(): image = np.array([[0, 1, 2, 3], [0, 1, 2, 3]]) - spec = LinearTimeSpectrogram(image, - np.array([0, 1, 2]), np.array([0]), - datetime(2012, 1, 1), - datetime(2012, 1, 1, 0, 0, 3), - 0, 1 - ) + spec = LinearTimeSpectrogram( + image, np.array([0, 1, 2]), np.array([0]), datetime(2012, 1, 1), datetime(2012, 1, 1, 0, 0, 3), 0, 1 + ) r = spec.resample_time(2) assert r.shape[1] == 2 def test_combine_freqs(): image = np.random.rand(5, 3600) - spec = LinearTimeSpectrogram(image, - np.linspace(0, image.shape[1] - 1, image.shape[1]), - np.array([8, 6, 4, 2, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 0.25 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), + np.array([8, 6, 4, 2, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 0.25, + ) image = np.random.rand(5, 3600) - spec2 = LinearTimeSpectrogram(image, - np.linspace(0, image.shape[1] - 1, image.shape[1]), - np.array([9, 7, 5, 3, 1]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 0.25 - ) + spec2 = LinearTimeSpectrogram( + image, + np.linspace(0, image.shape[1] - 1, image.shape[1]), + np.array([9, 7, 5, 3, 1]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 0.25, + ) comb = LinearTimeSpectrogram.combine_frequencies([spec, spec2]) stuff = [spec, spec2] # print comb for freq in range(10): - assert np.array_equal( - comb[9 - freq, :], stuff[freq % 2][4 - freq // 2, :] - ) + assert np.array_equal(comb[9 - freq, :], stuff[freq % 2][4 - freq // 2, :]) def test_join_diff_freq(): image = np.random.rand(5, 3600) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), - np.array([8, 6, 4, 2, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 0.25 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), + np.array([8, 6, 4, 2, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 0.25, + ) image = np.random.rand(5, 3600) - spec2 = LinearTimeSpectrogram(image, - np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), - np.array([9, 7, 5, 3, 1]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 1800, - 0.25 - ) + spec2 = LinearTimeSpectrogram( + image, + np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), + np.array([9, 7, 5, 3, 1]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 1800, + 0.25, + ) with pytest.raises(ValueError) as excinfo: LinearTimeSpectrogram.join_many([spec, spec2]) @@ -603,23 +689,25 @@ def test_join_diff_freq(): def test_intersect_time(): image = np.random.rand(5, 3600) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), - np.array([8, 6, 4, 2, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 0.25 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), + np.array([8, 6, 4, 2, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 0.25, + ) image = np.random.rand(5, 3600) - spec2 = LinearTimeSpectrogram(image, - np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), - np.array([9, 7, 5, 3, 1]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 901, - 0.25 - ) + spec2 = LinearTimeSpectrogram( + image, + np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), + np.array([9, 7, 5, 3, 1]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 901, + 0.25, + ) one, other = LinearTimeSpectrogram.intersect_time([spec, spec2]) @@ -636,14 +724,15 @@ def test_intersect_time(): def test_check_linearity(): image = np.random.rand(5, 3600) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), - np.array([8, 6, 4, 2, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 0.25 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), + np.array([8, 6, 4, 2, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 0.25, + ) assert spec.check_linearity() spec.time_axis[1] += 0.1 assert not spec.check_linearity() @@ -657,57 +746,59 @@ def test_check_linearity(): def test_flatten(): flat = np.arange(5 * 3600) image = flat.reshape(5, 3600) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), - np.array([8, 6, 4, 2, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 0.25 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 0.25 * (image.shape[1] - 1), image.shape[1]), + np.array([8, 6, 4, 2, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 0.25, + ) assert np.array_equal(flat, spec.data.flatten()) def test_in_interval(): image = np.random.rand(5, 900) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), - np.array([8, 6, 4, 2, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 1 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), + np.array([8, 6, 4, 2, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 1, + ) assert np.array_equal(spec.in_interval("00:15", "00:30").data, spec.data) def test_in_interval2(): image = np.random.rand(5, 900) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), - np.array([8, 6, 4, 2, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 1 - ) - - assert np.array_equal( - spec.in_interval("2010-01-01T00:15:00", "00:30").data, spec.data + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), + np.array([8, 6, 4, 2, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 1, ) + assert np.array_equal(spec.in_interval("2010-01-01T00:15:00", "00:30").data, spec.data) + def test_linearize(): image = np.random.rand(5, 900) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), - np.array([20, 10, 5, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 1 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), + np.array([20, 10, 5, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 1, + ) # 0 1 2 3 4 5 6 7 8 # -------- ----------- ----- --- # 20 17.5 15 12.5 10 7.5 5 2.5 0 @@ -728,14 +819,15 @@ def test_linearize(): def test_linear_view(): image = np.random.rand(5, 900) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), - np.array([20, 10, 5, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 1 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), + np.array([20, 10, 5, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 1, + ) linear = _LinearView(spec) # assert ((linear.freq_axis[:-1] - linear.freq_axis[1:]) == 2.5).all() @@ -753,14 +845,15 @@ def test_linear_view(): def test_linear_view_indexerror(): image = np.random.rand(5, 900) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), - np.array([20, 10, 5, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 1 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), + np.array([20, 10, 5, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 1, + ) linear = _LinearView(spec) # assert ((linear.freq_axis[:-1] - linear.freq_axis[1:]) == 2.5).all() @@ -770,14 +863,15 @@ def test_linear_view_indexerror(): def test_linear_view_negative(): image = np.random.rand(5, 900) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), - np.array([20, 10, 5, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 1 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), + np.array([20, 10, 5, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 1, + ) linear = _LinearView(spec) # assert ((linear.freq_axis[:-1] - linear.freq_axis[1:]) == 2.5).all() @@ -787,14 +881,15 @@ def test_linear_view_negative(): def test_linear_view_freqs(): image = np.random.rand(5, 900) - spec = LinearTimeSpectrogram(image, - np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), - np.array([20, 10, 5, 0]), - datetime(2010, 1, 1, 0, 15), - datetime(2010, 1, 1, 0, 30), - 900, - 1 - ) + spec = LinearTimeSpectrogram( + image, + np.linspace(0, 1 * (image.shape[1] - 1), image.shape[1]), + np.array([20, 10, 5, 0]), + datetime(2010, 1, 1, 0, 15), + datetime(2010, 1, 1, 0, 30), + 900, + 1, + ) linear = _LinearView(spec) # assert ((linear.freq_axis[:-1] - linear.freq_axis[1:]) == 2.5).all() diff --git a/radiospectra/tests/test_util.py b/radiospectra/tests/test_util.py index e69e89d..abf57e5 100644 --- a/radiospectra/tests/test_util.py +++ b/radiospectra/tests/test_util.py @@ -24,8 +24,7 @@ def test_dispatch(oddeven): def test_wrong_sig(oddeven): with pytest.raises(TypeError) as exc_info: oddeven(y=2) - assert "There are no functions matching your input parameter signature." in str( - exc_info.value) + assert "There are no functions matching your input parameter signature." in str(exc_info.value) def test_nocond(): @@ -34,8 +33,7 @@ def test_nocond(): f.add(lambda x: 2 * x, lambda x: x % 2 == 0) with pytest.raises(TypeError) as exc_info: f(3) - assert "Your input did not fulfill the condition for any function." in str( - exc_info.value) + assert "Your input did not fulfill the condition for any function." in str(exc_info.value) def test_else(): @@ -69,18 +67,16 @@ def test_types(): def test_minimal_pairs(): """ - This should return the pairs of elements from list1 and list2 with - minimal difference between their values. + This should return the pairs of elements from list1 and list2 with minimal + difference between their values. """ list1 = [0, 5, 10, 15, 20, 25] list2 = [3, 12, 19, 21, 26, 29] - assert list(minimal_pairs(list1, list2)) == [(1, 0, 2), (2, 1, 2), - (4, 2, 1), (5, 4, 1)] + assert list(minimal_pairs(list1, list2)) == [(1, 0, 2), (2, 1, 2), (4, 2, 1), (5, 4, 1)] def test_get_day(): - end_of_day = datetime(year=2017, month=1, day=1, hour=23, minute=59, second=59, - microsecond=999) + end_of_day = datetime(year=2017, month=1, day=1, hour=23, minute=59, second=59, microsecond=999) begining_of_day = get_day(end_of_day) assert begining_of_day.year == 2017 @@ -96,14 +92,22 @@ def test_common_base(): """ This should return the base class common to each object in objs. """ + class TestA(object): - """Base test class.""" + """ + Base test class. + """ class TestB(TestA): - """First inherited class.""" + """ + First inherited class. + """ class TestC(TestA): - """Second inherited class.""" + """ + Second inherited class. + """ + inst_b = TestB() inst_c = TestC() objs = [inst_b, inst_c] @@ -112,8 +116,8 @@ class TestC(TestA): def test_merge(): """ - This should return a sorted (from greatest to least) merged list - from list1 and list2. + This should return a sorted (from greatest to least) merged list from list1 + and list2. """ list1 = [13, 11, 9, 7, 5, 3, 1] list2 = [14, 12, 10, 8, 6, 4, 2] @@ -125,11 +129,11 @@ def test_merge(): def test_to_signed(): """ - This should return a signed type that can hold uint32 and ensure that - an exception is raised when attempting to convert an unsigned 64 bit integer - to an integer + This should return a signed type that can hold uint32 and ensure that an + exception is raised when attempting to convert an unsigned 64 bit integer + to an integer. """ - assert to_signed(np.dtype('uint32')) == np.dtype('int64') + assert to_signed(np.dtype("uint32")) == np.dtype("int64") with pytest.raises(ValueError): - to_signed(np.dtype('uint64')) == np.dtype('int64') + to_signed(np.dtype("uint64")) == np.dtype("int64") diff --git a/radiospectra/util.py b/radiospectra/util.py index 7f50caf..429aa28 100644 --- a/radiospectra/util.py +++ b/radiospectra/util.py @@ -82,15 +82,27 @@ from sunpy.util.config import get_and_create_download_dir from sunpy.util.net import download_file -__all__ = ['run_cls', 'matches_types', 'arginize', 'correct_argspec', - 'matches_signature', 'ConditionalDispatch', 'fmt_argspec_types', - 'minimal_pairs', 'get_day', 'to_signed', 'common_base', 'merge', 'Parent'] +__all__ = [ + "run_cls", + "matches_types", + "arginize", + "correct_argspec", + "matches_signature", + "ConditionalDispatch", + "fmt_argspec_types", + "minimal_pairs", + "get_day", + "to_signed", + "common_base", + "merge", + "Parent", +] def merge(items, key=(lambda x: x)): """ - Given sorted lists of iterables, return new iterable that returns - elements of all iterables sorted with respect to key. + Given sorted lists of iterables, return new iterable that returns elements + of all iterables sorted with respect to key. """ state = {} for item in map(iter, items): @@ -104,8 +116,7 @@ def merge(items, key=(lambda x: x)): while state: for item, (value, tk) in list(state.items()): # Value is biggest. - if all(tk >= k for it, (v, k) in list(state.items()) - if it is not item): + if all(tk >= k for it, (v, k) in list(state.items()) if it is not item): yield value break try: @@ -127,8 +138,8 @@ def common_base(objs): def to_signed(dtype): """ - Return dtype that can hold data of passed dtype but is signed. - Raise ValueError if no such dtype exists. + Return dtype that can hold data of passed dtype but is signed. Raise + ValueError if no such dtype exists. Parameters ---------- @@ -147,13 +158,16 @@ def to_signed(dtype): def get_day(dt): - """ Return datetime for the beginning of the day of given datetime. """ + """ + Return datetime for the beginning of the day of given datetime. + """ return datetime(dt.year, dt.month, dt.day) def minimal_pairs(one, other): - """ Find pairs of values in one and other with minimal distance. - Assumes one and other are sorted in the same sort sequence. + """ + Find pairs of values in one and other with minimal distance. Assumes one + and other are sorted in the same sort sequence. Parameters ---------- @@ -208,11 +222,7 @@ def matches_types(fun, types, args, kwargs): types are given in the order they are defined in the function. kwargs are automatically converted into that order. """ - return all( - isinstance(obj, cls) for obj, cls in list(zip( - arginize(fun, args, kwargs), types - )) - ) + return all(isinstance(obj, cls) for obj, cls in list(zip(arginize(fun, args, kwargs), types))) def arginize(fun, a, kw): @@ -223,9 +233,9 @@ def arginize(fun, a, kw): if varargs is not None: raise ValueError - names = args[len(a):] + names = args[len(a) :] if defaults: - defs = dict(list(zip(args[-len(defaults):], defaults))) + defs = dict(list(zip(args[-len(defaults) :], defaults))) else: defs = {} return list(a) + [kw.get(name, defs.get(name, None)) for name in names] @@ -251,13 +261,13 @@ def matches_signature(fun, a, kw): if varargs is None and len(a) > len(args): return False skw = set(kw) - sargs = set(args[len(a):]) + sargs = set(args[len(a) :]) # There mayn't be unexpected parameters unless there is a **kwargs # in fun's signature. if keywords is None and skw - sargs != set(): return False - rest = set(args[len(a):]) - set(kw) + rest = set(args[len(a) :]) - set(kw) # If there are any arguments that weren't passed but do not have # defaults, the signature does not match. @@ -283,6 +293,7 @@ def add_dec(self, condition): def _dec(fun): self.add(fun, condition) return fun + return _dec def add(self, fun, condition=None, types=None, check=True): @@ -303,34 +314,27 @@ def add(self, fun, condition=None, types=None, check=True): if condition is None: self.nones.append((fun, types)) elif check and correct_argspec(fun) != correct_argspec(condition): - raise ValueError( - "Signature of condition must match signature of fun." - ) + raise ValueError("Signature of condition must match signature of fun.") else: self.funcs.append((fun, condition, types)) def __call__(self, *args, **kwargs): matched = False for fun, condition, types in self.funcs: - if (matches_signature(condition, args, kwargs) and - (types is None or matches_types(condition, types, args, kwargs))): + if matches_signature(condition, args, kwargs) and ( + types is None or matches_types(condition, types, args, kwargs) + ): matched = True if condition(*args, **kwargs): return fun(*args, **kwargs) for fun, types in self.nones: - if (matches_signature(fun, args, kwargs) and - (types is None or matches_types(fun, types, args, kwargs))): + if matches_signature(fun, args, kwargs) and (types is None or matches_types(fun, types, args, kwargs)): return fun(*args, **kwargs) if matched: - raise TypeError( - "Your input did not fulfill the condition for any function." - ) + raise TypeError("Your input did not fulfill the condition for any function.") else: - raise TypeError( - "There are no functions matching your input parameter " - "signature." - ) + raise TypeError("There are no functions matching your input parameter " "signature.") def wrapper(self): return lambda *args, **kwargs: self(*args, **kwargs) @@ -346,7 +350,7 @@ def get_signatures(self, prefix="", start=0): """ for fun, condition, types in self.funcs: if start == -1: - st = getattr(fun, 'run_cls', 0) + st = getattr(fun, "run_cls", 0) else: st = start @@ -356,8 +360,8 @@ def get_signatures(self, prefix="", start=0): args, varargs, keywords, defaults = correct_argspec(condition) args = args[st:] sig_str = str(inspect.signature(fun)) - if sig_str == '(cls, *args, **kwargs)': - sig_str = '(cls, \\*args, \\**kwargs)' + if sig_str == "(cls, *args, **kwargs)": + sig_str = "(cls, \\*args, \\**kwargs)" yield prefix + sig_str for fun, types in self.nones: @@ -366,18 +370,19 @@ def get_signatures(self, prefix="", start=0): else: args, varargs, keywords = correct_argspec(condition) args = args[st:] - if sig_str == '(cls, *args, **kwargs)': - sig_str = '(cls, \\*args, \\**kwargs)' + if sig_str == "(cls, *args, **kwargs)": + sig_str = "(cls, \\*args, \\**kwargs)" yield prefix + sig_str def generate_docs(self): fns = (item[0] for item in chain(self.funcs, self.nones)) - return '\n\n '.join("{} -> :meth:`{}`".format(sig, fun.__name__) - for sig, fun in - # The 1 prevents the cls from incorrectly being shown in the - # documentation. - list(zip(self.get_signatures("create", -1), fns)) - ) + return "\n\n ".join( + "{} -> :meth:`{}`".format(sig, fun.__name__) + for sig, fun in + # The 1 prevents the cls from incorrectly being shown in the + # documentation. + list(zip(self.get_signatures("create", -1), fns)) + ) def fmt_argspec_types(fun, types, start=0): @@ -402,10 +407,10 @@ def fmt_argspec_types(fun, types, start=0): else: spec.append("{}: {} = {}".format(key, type_.__name__, value)) if varargs is not None: - spec.append('*{!s}'.format(varargs)) + spec.append("*{!s}".format(varargs)) if keywords is not None: - spec.append('**{!s}'.format(keywords)) - return '(' + ', '.join(spec) + ')' + spec.append("**{!s}".format(keywords)) + return "(" + ", ".join(spec) + ")" class Parent(object): @@ -421,14 +426,18 @@ def read_many(cls, filenames): @classmethod def from_glob(cls, pattern): - """ Read out files using glob (e.g., ~/BIR_2011*) pattern. Returns - list of objects made from all matched files. + """ + Read out files using glob (e.g., ~/BIR_2011*) pattern. + + Returns list of objects made from all matched files. """ return cls.read_many(glob.glob(pattern)) @classmethod def from_single_glob(cls, singlepattern): - """ Read out a single file using glob (e.g., ~/BIR_2011*) pattern. + """ + Read out a single file using glob (e.g., ~/BIR_2011*) pattern. + If more than one file matches the pattern, raise ValueError. """ matches = glob.glob(os.path.expanduser(singlepattern)) @@ -438,28 +447,32 @@ def from_single_glob(cls, singlepattern): @classmethod def from_files(cls, filenames): - """ Return list of object read from given list of - filenames. """ + """ + Return list of object read from given list of filenames. + """ filenames = list(map(os.path.expanduser, filenames)) return cls.read_many(filenames) @classmethod def from_file(cls, filename): - """ Return object from file. """ + """ + Return object from file. + """ filename = os.path.expanduser(filename) return cls.read(filename) @classmethod def from_dir(cls, directory): - """ Return list that contains all files in the directory read in. """ + """ + Return list that contains all files in the directory read in. + """ directory = os.path.expanduser(directory) - return cls.read_many( - os.path.join(directory, elem) for elem in os.listdir(directory) - ) + return cls.read_many(os.path.join(directory, elem) for elem in os.listdir(directory)) @classmethod def from_url(cls, url): - """ Return object read from URL. + """ + Return object read from URL. Parameters ---------- @@ -471,43 +484,32 @@ def from_url(cls, url): Parent._create.add( - run_cls('from_file'), - lambda cls, filename: os.path.isfile(os.path.expanduser(filename)), - [type, str], check=False + run_cls("from_file"), lambda cls, filename: os.path.isfile(os.path.expanduser(filename)), [type, str], check=False ) Parent._create.add( # pylint: disable=W0108 # The lambda is necessary because introspection is performed on the # argspec of the function. - run_cls('from_dir'), + run_cls("from_dir"), lambda cls, directory: os.path.isdir(os.path.expanduser(directory)), - [type, str], check=False + [type, str], + check=False, ) # If it is not a kwarg and only one matches, do not return a list. Parent._create.add( - run_cls('from_single_glob'), - lambda cls, singlepattern: ('*' in singlepattern and - len(glob.glob( - os.path.expanduser(singlepattern))) == 1), - [type, str], check=False + run_cls("from_single_glob"), + lambda cls, singlepattern: ("*" in singlepattern and len(glob.glob(os.path.expanduser(singlepattern))) == 1), + [type, str], + check=False, ) # This case only gets executed under the condition that the previous one wasn't. # This is either because more than one file matched, or because the user # explicitly used pattern=, in both cases we want a list. Parent._create.add( - run_cls('from_glob'), - lambda cls, pattern: '*' in pattern and glob.glob( - os.path.expanduser(pattern) - ), - [type, str], check=False -) -Parent._create.add( - run_cls('from_files'), - lambda cls, filenames: True, - types=[type, list], check=False -) -Parent._create.add( - run_cls('from_url'), - lambda cls, url: True, - types=[type, str], check=False + run_cls("from_glob"), + lambda cls, pattern: "*" in pattern and glob.glob(os.path.expanduser(pattern)), + [type, str], + check=False, ) +Parent._create.add(run_cls("from_files"), lambda cls, filenames: True, types=[type, list], check=False) +Parent._create.add(run_cls("from_url"), lambda cls, url: True, types=[type, str], check=False) diff --git a/radiospectra/version.py b/radiospectra/version.py index 4c6e402..bf0f914 100644 --- a/radiospectra/version.py +++ b/radiospectra/version.py @@ -9,12 +9,10 @@ except Exception: import warnings - warnings.warn( - f'could not determine {__name__.split(".")[0]} package version; this indicates a broken installation' - ) + warnings.warn(f'could not determine {__name__.split(".")[0]} package version; this indicates a broken installation') del warnings - version = '0.0.0' + version = "0.0.0" # We use LooseVersion to define major, minor, micro, but ignore any suffixes. @@ -37,4 +35,4 @@ def split_version(version): del split_version # clean up namespace. -release = 'dev' not in version +release = "dev" not in version diff --git a/setup.py b/setup.py index b8c0922..4d83ca9 100755 --- a/setup.py +++ b/setup.py @@ -8,18 +8,18 @@ ################################################################################ # Programmatically generate some extras combos. ################################################################################ -extras = read_configuration("setup.cfg")['options']['extras_require'] +extras = read_configuration("setup.cfg")["options"]["extras_require"] # Dev is everything -extras['dev'] = list(chain(*extras.values())) +extras["dev"] = list(chain(*extras.values())) # All is everything but tests and docs exclude_keys = ("tests", "docs", "dev") ex_extras = dict(filter(lambda i: i[0] not in exclude_keys, extras.items())) # Concatenate all the values together for 'all' -extras['all'] = list(chain.from_iterable(ex_extras.values())) +extras["all"] = list(chain.from_iterable(ex_extras.values())) setup( extras_require=extras, - use_scm_version={'write_to': os.path.join('radiospectra', '_version.py')}, + use_scm_version={"write_to": os.path.join("radiospectra", "_version.py")}, ) diff --git a/tox.ini b/tox.ini index 9526cab..6190117 100644 --- a/tox.ini +++ b/tox.ini @@ -1,32 +1,20 @@ [tox] envlist = - py{37,38,39}{,-oldestdeps,-devdeps,-online} + py{38,39,310}{,-oldestdeps,-devdeps,-online} build_docs codestyle conda requires = - setuptools >= 30.3.0 + setuptools >=56, !=61.0.0 pip >= 19.3.1 tox-pypi-filter >= 0.12 isolated_build = true [testenv] pypi_filter = https://raw.githubusercontent.com/sunpy/sunpy/main/.test_package_pins.txt -# We use bash in some of our environments so we have to whitelist it. -whitelist_externals= - /bin/bash - /usr/bin/bash # Run the tests in a temporary directory to make sure that we don't import # sunpy from the source tree changedir = .tmp/{envname} -# tox environments are constructed with so-called 'factors' (or terms) -# separated by hyphens, e.g. test-devdeps-cov. Lines below starting with factor: -# will only take effect if that factor is included in the environment name. To -# see a list of example environments that can be run, along with a description, -# run: -# -# tox -l -v -# description = run tests devdeps: with the latest developer version of key dependencies @@ -56,12 +44,8 @@ deps = devdeps: git+https://github.com/sunpy/sunpy devdeps: matplotlib devdeps: scipy - - # Until scikit-image 0.19 is out. - py39: numpy - # Oldest deps we pin against. - oldestdeps: sunpy<2.1 + oldestdeps: sunpy<4.1 # These are specific online extras we use to run the online tests. online: pytest-rerunfailures online: pytest-timeout @@ -76,7 +60,8 @@ commands = [testenv:build_docs] changedir = docs description = Invoke sphinx-build to build the HTML docs -extras = dev +extras = + dev commands = sphinx-build -j auto --color -W --keep-going -b html -d _build/.doctrees . _build/html {posargs} python -c 'import pathlib; print("Documentation available under file://\{0\}".format(pathlib.Path(r"{toxinidir}") / "docs" / "_build" / "index.html"))' @@ -94,7 +79,7 @@ commands = # This env requires tox-conda. [testenv:conda] pypi_filter = -basepython = python3.8 +basepython = python3.9 extras = deps = conda_deps = From 95658eb5e751c380925370cc80e4c8f4d0857c17 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 24 May 2022 14:41:54 -0700 Subject: [PATCH 2/6] more --- radiospectra/net/sources/psp.py | 2 +- radiospectra/net/sources/rstn.py | 2 +- radiospectra/net/sources/stereo.py | 2 +- .../net/sources/tests/test_callisto_client.py | 3 +-- radiospectra/net/sources/tests/test_eovsa_client.py | 2 +- radiospectra/net/sources/tests/test_psp_client.py | 2 +- radiospectra/net/sources/tests/test_rstn_client.py | 2 +- radiospectra/net/sources/tests/test_stereo_client.py | 2 +- radiospectra/net/sources/tests/test_wind_client.py | 2 +- radiospectra/net/sources/wind.py | 2 +- setup.cfg | 11 ++++------- 11 files changed, 14 insertions(+), 18 deletions(-) diff --git a/radiospectra/net/sources/psp.py b/radiospectra/net/sources/psp.py index 050fea1..93b40e5 100644 --- a/radiospectra/net/sources/psp.py +++ b/radiospectra/net/sources/psp.py @@ -2,7 +2,7 @@ from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse from sunpy.time.timerange import TimeRange -from sunpy.util.scraper import Scraper +from sunpy.net.scraper import Scraper __all__ = ["RFSClient"] diff --git a/radiospectra/net/sources/rstn.py b/radiospectra/net/sources/rstn.py index 55332ce..c207297 100644 --- a/radiospectra/net/sources/rstn.py +++ b/radiospectra/net/sources/rstn.py @@ -1,7 +1,7 @@ from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse from sunpy.time.timerange import TimeRange -from sunpy.util.scraper import Scraper +from sunpy.net.scraper import Scraper from radiospectra.net.attrs import Observatory diff --git a/radiospectra/net/sources/stereo.py b/radiospectra/net/sources/stereo.py index ed9fe11..644eb8f 100644 --- a/radiospectra/net/sources/stereo.py +++ b/radiospectra/net/sources/stereo.py @@ -4,7 +4,7 @@ from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse from sunpy.time import TimeRange -from sunpy.util.scraper import Scraper +from sunpy.net.scraper import Scraper from radiospectra.net import attrs as ra diff --git a/radiospectra/net/sources/tests/test_callisto_client.py b/radiospectra/net/sources/tests/test_callisto_client.py index 16909dc..6052029 100644 --- a/radiospectra/net/sources/tests/test_callisto_client.py +++ b/radiospectra/net/sources/tests/test_callisto_client.py @@ -10,8 +10,7 @@ from radiospectra.net.sources.callisto import CALLISTOClient, Observatory -MOCK_PATH = "sunpy.net.scraper.urlopen" if sunpy.__version__ >= "3.1.0" else "sunpy.util.scraper.urlopen" - +MOCK_PATH = "sunpy.net.scraper.urlopen" @pytest.fixture def client(): diff --git a/radiospectra/net/sources/tests/test_eovsa_client.py b/radiospectra/net/sources/tests/test_eovsa_client.py index 2f090ea..4d1c5db 100644 --- a/radiospectra/net/sources/tests/test_eovsa_client.py +++ b/radiospectra/net/sources/tests/test_eovsa_client.py @@ -11,7 +11,7 @@ from radiospectra.net.attrs import PolType from radiospectra.net.sources.eovsa import EOVSAClient -MOCK_PATH = "sunpy.net.scraper.urlopen" if sunpy.__version__ >= "3.1.0" else "sunpy.util.scraper.urlopen" +MOCK_PATH = "sunpy.net.scraper.urlopen" @pytest.fixture diff --git a/radiospectra/net/sources/tests/test_psp_client.py b/radiospectra/net/sources/tests/test_psp_client.py index a83a7d5..71ecf6a 100644 --- a/radiospectra/net/sources/tests/test_psp_client.py +++ b/radiospectra/net/sources/tests/test_psp_client.py @@ -13,7 +13,7 @@ from radiospectra.net.sources.psp import RFSClient -MOCK_PATH = "sunpy.net.scraper.urlopen" if sunpy.__version__ >= "3.1.0" else "sunpy.util.scraper.urlopen" +MOCK_PATH = "sunpy.net.scraper.urlopen" @pytest.fixture diff --git a/radiospectra/net/sources/tests/test_rstn_client.py b/radiospectra/net/sources/tests/test_rstn_client.py index 133286b..54ca24e 100644 --- a/radiospectra/net/sources/tests/test_rstn_client.py +++ b/radiospectra/net/sources/tests/test_rstn_client.py @@ -10,7 +10,7 @@ from radiospectra.net.attrs import Observatory from radiospectra.net.sources.rstn import RSTNClient -MOCK_PATH = "sunpy.net.scraper.urlopen" if sunpy.__version__ >= "3.1.0" else "sunpy.util.scraper.urlopen" +MOCK_PATH = "sunpy.net.scraper.urlopen" @pytest.fixture diff --git a/radiospectra/net/sources/tests/test_stereo_client.py b/radiospectra/net/sources/tests/test_stereo_client.py index 557b184..96211b9 100644 --- a/radiospectra/net/sources/tests/test_stereo_client.py +++ b/radiospectra/net/sources/tests/test_stereo_client.py @@ -12,7 +12,7 @@ from radiospectra.net.attrs import Spacecraft from radiospectra.net.sources.stereo import SWAVESClient -MOCK_PATH = "sunpy.net.scraper.urlopen" if sunpy.__version__ >= "3.1.0" else "sunpy.util.scraper.urlopen" +MOCK_PATH = "sunpy.net.scraper.urlopen" @pytest.fixture diff --git a/radiospectra/net/sources/tests/test_wind_client.py b/radiospectra/net/sources/tests/test_wind_client.py index 675fe73..ff412b4 100644 --- a/radiospectra/net/sources/tests/test_wind_client.py +++ b/radiospectra/net/sources/tests/test_wind_client.py @@ -11,7 +11,7 @@ from radiospectra.net.sources.wind import WAVESClient -MOCK_PATH = "sunpy.net.scraper.urlopen" if sunpy.__version__ >= "3.1.0" else "sunpy.util.scraper.urlopen" +MOCK_PATH = "sunpy.net.scraper.urlopen" @pytest.fixture diff --git a/radiospectra/net/sources/wind.py b/radiospectra/net/sources/wind.py index 06fe455..a1d3d3f 100644 --- a/radiospectra/net/sources/wind.py +++ b/radiospectra/net/sources/wind.py @@ -2,7 +2,7 @@ from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse from sunpy.time import TimeRange -from sunpy.util.scraper import Scraper +from sunpy.net.scraper import Scraper __all__ = ["WAVESClient"] diff --git a/setup.cfg b/setup.cfg index e492040..64d823d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ [metadata] name = radiospectra provides = radiospectra -description = "Provide support for some type of radio spectra in solar physics" +description = Provide support for some type of radio spectra in solar physics long_description = file: README.rst long_description_content_type = text/x-rst author = The SunPy Community @@ -21,26 +21,25 @@ classifiers = Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Topic :: Scientific/Engineering :: Physics [options] zip_safe = False -python_requires = >=3.7 +python_requires = >=3.8 packages = find: include_package_data = True setup_requires = setuptools_scm install_requires = - sunpy[net]>=3.0.0 + sunpy[net]>=4.0.0 numpy matplotlib scipy cdflib>=0.3.20 - [options.packages.find] exclude = radiospectra._dev @@ -107,8 +106,6 @@ filterwarnings = ignore:Distutils was imported before Setuptools # toolz internal deprecation warning https://github.com/pytoolz/toolz/issues/500 ignore:The toolz.compatibility module is no longer needed:DeprecationWarning - # Fix before sunpy 4.1 - ignore:The Scraper class is deprecated and may be removed in version 4.1.:sunpy.util.exceptions.SunpyDeprecationWarning [pycodestyle] max_line_length = 100 From b6c177119695ab6fbf1ef8dc03de1e6572693bf6 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 24 May 2022 14:48:21 -0700 Subject: [PATCH 3/6] changelog --- CHANGELOG.rst | 22 ++++++++++++++++++++-- changelog/44.feature.1.rst | 1 - changelog/44.feature.2.rst | 1 - changelog/54.feature.1.rst | 1 - changelog/54.feature.2.rst | 1 - radiospectra/spectrogram2/spectrogram.py | 4 ++-- setup.cfg | 1 + 7 files changed, 23 insertions(+), 8 deletions(-) delete mode 100644 changelog/44.feature.1.rst delete mode 100644 changelog/44.feature.2.rst delete mode 100644 changelog/54.feature.1.rst delete mode 100644 changelog/54.feature.2.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3f75afb..2607082 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,23 @@ -Radiospectra v0.3.0 (2021-04-01) -================================ +0.4.0 (2022-05-24) +================== + +Breaking Changes +---------------- + +- Minimum supported version of Python is now 3.8 +- Minimum supported version of ``sunpy`` is now 4.0.0 (LTS) + +Features +-------- + +- Add a new spectrogram class `radiospectra.spectrogram2.spectrogram.BaseSpectrogram` and factory `radiospectra.spectrogram2.spectrogram.SpectrogramFactory` with sources for `~radiospectra.spectrogram2.sources.SWAVESSpectrogram`, `~radiospectra.spectrogram2.sources.RFSSpectrogram`, `~radiospectra.spectrogram2.sources.CALISTOSpectrogram`, `~radiospectra.spectrogram2.sources.EOVSASpectrogram` and `~radiospectra.spectrogram2.sources.RSTNSpectrogram`. (`#44 `__) +- Add `sunpy.net.Fido` clients for `~radiospectra.net.sources.callisto.CALLISTOClient`, `~radiospectra.net.sources.eovsa.EOVSAClient` and `~radiospectra.net.sources.rstn.RSTNClient`. (`#44 `__) +- Improve `~radiospectra.spectrogram2.spectrogram.SpectrogramFactory` input handling more inputs formats data header pairs, files, urls. (`#54 `__) +- Add `sunpy.net.Fido` client `~radiospectra.net.sources.wind.Waves` and spectrogram class `~radiospectra.spectrogram2.sources.WAVESSpectrogram` for WIND/WAVES. (`#54 `__) + + +0.3.0 (2021-04-01) +================== Features -------- diff --git a/changelog/44.feature.1.rst b/changelog/44.feature.1.rst deleted file mode 100644 index 21ec77e..0000000 --- a/changelog/44.feature.1.rst +++ /dev/null @@ -1 +0,0 @@ -Add `sunpy.net.Fido` clients for `~radiospectra.net.sources.callisto.CALLISTOClient`, `~radiospectra.net.sources.eovsa.EOVSAClient` and `~radiospectra.net.sources.rstn.RSTNClient`. diff --git a/changelog/44.feature.2.rst b/changelog/44.feature.2.rst deleted file mode 100644 index 4e7a9a2..0000000 --- a/changelog/44.feature.2.rst +++ /dev/null @@ -1 +0,0 @@ -Add a new spectrogram class `radiospectra.spectrogram2.spectrogram.BaseSpectrogram` and factory `radiospectra.spectrogram2.spectrogram.SpectrogramFactory` with sources for `~radiospectra.spectrogram2.sources.SWAVESSpectrogram`, `~radiospectra.spectrogram2.sources.RFSSpectrogram`, `~radiospectra.spectrogram2.sources.CALISTOSpectrogram`, `~radiospectra.spectrogram2.sources.EOVSASpectrogram` and `~radiospectra.spectrogram2.sources.RSTNSpectrogram`. diff --git a/changelog/54.feature.1.rst b/changelog/54.feature.1.rst deleted file mode 100644 index dc6a5a1..0000000 --- a/changelog/54.feature.1.rst +++ /dev/null @@ -1 +0,0 @@ -Improve `~radiospectra.spectrogram2.spectrogram.SpectrogramFactory` input handling more inputs formats data header pairs, files, urls. diff --git a/changelog/54.feature.2.rst b/changelog/54.feature.2.rst deleted file mode 100644 index 39b28e9..0000000 --- a/changelog/54.feature.2.rst +++ /dev/null @@ -1 +0,0 @@ -Add `sunpy.net.Fido` client `~radiospectra.net.sources.wind.Waves` and spectrogram class `~radiospectra.spectrogram2.sources.WAVESSpectrogram` for WIND/WAVES. diff --git a/radiospectra/spectrogram2/spectrogram.py b/radiospectra/spectrogram2/spectrogram.py index a3032b9..d78c17f 100644 --- a/radiospectra/spectrogram2/spectrogram.py +++ b/radiospectra/spectrogram2/spectrogram.py @@ -14,14 +14,14 @@ import pandas as pd from matplotlib import pyplot as plt from matplotlib.image import NonUniformImage -from scipy.io.idl import readsav +from scipy.io import readsav import astropy.units as u from astropy.io.fits import Header from astropy.time import Time from astropy.visualization import quantity_support from sunpy.data import cache -from sunpy.io import fits +from astropy.io import fits from sunpy.net import attrs as a from sunpy.time import parse_time from sunpy.util.datatype_factory_base import ( diff --git a/setup.cfg b/setup.cfg index 64d823d..aa2002a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -106,6 +106,7 @@ filterwarnings = ignore:Distutils was imported before Setuptools # toolz internal deprecation warning https://github.com/pytoolz/toolz/issues/500 ignore:The toolz.compatibility module is no longer needed:DeprecationWarning + ignore:distutils Version classes are deprecated. Use packaging.version instead. [pycodestyle] max_line_length = 100 From 5396cfccfbcbf405399d4680716b714508bb39dc Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 24 May 2022 14:53:09 -0700 Subject: [PATCH 4/6] more --- radiospectra/net/sources/psp.py | 2 +- radiospectra/net/sources/rstn.py | 2 +- radiospectra/net/sources/stereo.py | 2 +- .../net/sources/tests/test_callisto_client.py | 2 +- .../net/sources/tests/test_eovsa_client.py | 1 - .../net/sources/tests/test_psp_client.py | 1 - .../net/sources/tests/test_rstn_client.py | 1 - .../net/sources/tests/test_stereo_client.py | 1 - .../net/sources/tests/test_wind_client.py | 1 - radiospectra/net/sources/wind.py | 2 +- radiospectra/spectrogram2/spectrogram.py | 2 +- radiospectra/tests/__init__.py | 4 --- radiospectra/tests/coveragerc | 31 ------------------- radiospectra/tests/setup_package.py | 2 -- 14 files changed, 6 insertions(+), 48 deletions(-) delete mode 100644 radiospectra/tests/coveragerc delete mode 100644 radiospectra/tests/setup_package.py diff --git a/radiospectra/net/sources/psp.py b/radiospectra/net/sources/psp.py index 93b40e5..0edc8f9 100644 --- a/radiospectra/net/sources/psp.py +++ b/radiospectra/net/sources/psp.py @@ -1,8 +1,8 @@ import astropy.units as u from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse -from sunpy.time.timerange import TimeRange from sunpy.net.scraper import Scraper +from sunpy.time.timerange import TimeRange __all__ = ["RFSClient"] diff --git a/radiospectra/net/sources/rstn.py b/radiospectra/net/sources/rstn.py index c207297..4ad0b47 100644 --- a/radiospectra/net/sources/rstn.py +++ b/radiospectra/net/sources/rstn.py @@ -1,7 +1,7 @@ from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse -from sunpy.time.timerange import TimeRange from sunpy.net.scraper import Scraper +from sunpy.time.timerange import TimeRange from radiospectra.net.attrs import Observatory diff --git a/radiospectra/net/sources/stereo.py b/radiospectra/net/sources/stereo.py index 644eb8f..4a9c388 100644 --- a/radiospectra/net/sources/stereo.py +++ b/radiospectra/net/sources/stereo.py @@ -3,8 +3,8 @@ import astropy.units as u from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse -from sunpy.time import TimeRange from sunpy.net.scraper import Scraper +from sunpy.time import TimeRange from radiospectra.net import attrs as ra diff --git a/radiospectra/net/sources/tests/test_callisto_client.py b/radiospectra/net/sources/tests/test_callisto_client.py index 6052029..a038c78 100644 --- a/radiospectra/net/sources/tests/test_callisto_client.py +++ b/radiospectra/net/sources/tests/test_callisto_client.py @@ -4,7 +4,6 @@ import pytest -import sunpy from sunpy.net import attrs as a from sunpy.net.fido_factory import Fido @@ -12,6 +11,7 @@ MOCK_PATH = "sunpy.net.scraper.urlopen" + @pytest.fixture def client(): return CALLISTOClient() diff --git a/radiospectra/net/sources/tests/test_eovsa_client.py b/radiospectra/net/sources/tests/test_eovsa_client.py index 4d1c5db..f7db381 100644 --- a/radiospectra/net/sources/tests/test_eovsa_client.py +++ b/radiospectra/net/sources/tests/test_eovsa_client.py @@ -4,7 +4,6 @@ import numpy as np import pytest -import sunpy from sunpy.net import attrs as a from sunpy.net.fido_factory import Fido diff --git a/radiospectra/net/sources/tests/test_psp_client.py b/radiospectra/net/sources/tests/test_psp_client.py index 71ecf6a..e718102 100644 --- a/radiospectra/net/sources/tests/test_psp_client.py +++ b/radiospectra/net/sources/tests/test_psp_client.py @@ -6,7 +6,6 @@ import pytest import astropy.units as u -import sunpy from astropy.time import Time from sunpy.net import Fido from sunpy.net import attrs as a diff --git a/radiospectra/net/sources/tests/test_rstn_client.py b/radiospectra/net/sources/tests/test_rstn_client.py index 54ca24e..89f5f47 100644 --- a/radiospectra/net/sources/tests/test_rstn_client.py +++ b/radiospectra/net/sources/tests/test_rstn_client.py @@ -3,7 +3,6 @@ import pytest -import sunpy from sunpy.net import attrs as a from sunpy.net.fido_factory import Fido diff --git a/radiospectra/net/sources/tests/test_stereo_client.py b/radiospectra/net/sources/tests/test_stereo_client.py index 96211b9..0ded3d2 100644 --- a/radiospectra/net/sources/tests/test_stereo_client.py +++ b/radiospectra/net/sources/tests/test_stereo_client.py @@ -5,7 +5,6 @@ import pytest import astropy.units as u -import sunpy from sunpy.net import Fido from sunpy.net import attrs as a diff --git a/radiospectra/net/sources/tests/test_wind_client.py b/radiospectra/net/sources/tests/test_wind_client.py index ff412b4..d960a8e 100644 --- a/radiospectra/net/sources/tests/test_wind_client.py +++ b/radiospectra/net/sources/tests/test_wind_client.py @@ -5,7 +5,6 @@ import pytest import astropy.units as u -import sunpy from sunpy.net import Fido from sunpy.net import attrs as a diff --git a/radiospectra/net/sources/wind.py b/radiospectra/net/sources/wind.py index a1d3d3f..6da0a9c 100644 --- a/radiospectra/net/sources/wind.py +++ b/radiospectra/net/sources/wind.py @@ -1,8 +1,8 @@ import astropy.units as u from sunpy.net import attrs as a from sunpy.net.dataretriever.client import GenericClient, QueryResponse -from sunpy.time import TimeRange from sunpy.net.scraper import Scraper +from sunpy.time import TimeRange __all__ = ["WAVESClient"] diff --git a/radiospectra/spectrogram2/spectrogram.py b/radiospectra/spectrogram2/spectrogram.py index d78c17f..b102f1f 100644 --- a/radiospectra/spectrogram2/spectrogram.py +++ b/radiospectra/spectrogram2/spectrogram.py @@ -17,11 +17,11 @@ from scipy.io import readsav import astropy.units as u +from astropy.io import fits from astropy.io.fits import Header from astropy.time import Time from astropy.visualization import quantity_support from sunpy.data import cache -from astropy.io import fits from sunpy.net import attrs as a from sunpy.time import parse_time from sunpy.util.datatype_factory_base import ( diff --git a/radiospectra/tests/__init__.py b/radiospectra/tests/__init__.py index 838b457..e69de29 100644 --- a/radiospectra/tests/__init__.py +++ b/radiospectra/tests/__init__.py @@ -1,4 +0,0 @@ -# Licensed under a 3-clause BSD style license - see LICENSE.rst -""" -This module contains package tests. -""" diff --git a/radiospectra/tests/coveragerc b/radiospectra/tests/coveragerc deleted file mode 100644 index af64a0b..0000000 --- a/radiospectra/tests/coveragerc +++ /dev/null @@ -1,31 +0,0 @@ -[run] -source = radiospectra -omit = - radiospectra/_sunpy_init* - radiospectra/conftest* - radiospectra/cython_version* - radiospectra/setup_package* - radiospectra/*/setup_package* - radiospectra/*/*/setup_package* - radiospectra/tests/* - radiospectra/*/tests/* - radiospectra/*/*/tests/* - radiospectra/version* - -[report] -exclude_lines = - # Have to re-enable the standard pragma - 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} diff --git a/radiospectra/tests/setup_package.py b/radiospectra/tests/setup_package.py deleted file mode 100644 index 17b092d..0000000 --- a/radiospectra/tests/setup_package.py +++ /dev/null @@ -1,2 +0,0 @@ -def get_package_data(): - return {_ASTROPY_PACKAGE_NAME_ + ".tests": ["coveragerc"]} From 57fc9ddba6517d55f3e2c3631175cc198b053353 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 24 May 2022 15:12:38 -0700 Subject: [PATCH 5/6] docfixes and test --- docs/code_ref/index.rst | 6 +++--- radiospectra/net/sources/callisto.py | 10 +++++----- radiospectra/net/sources/eovsa.py | 4 ++-- radiospectra/net/sources/psp.py | 3 ++- radiospectra/net/sources/stereo.py | 11 +++++------ radiospectra/net/sources/wind.py | 12 +++++++----- radiospectra/spectrogram2/spectrogram.py | 2 +- tox.ini | 3 ++- 8 files changed, 27 insertions(+), 24 deletions(-) diff --git a/docs/code_ref/index.rst b/docs/code_ref/index.rst index f4973c1..a7a3b65 100644 --- a/docs/code_ref/index.rst +++ b/docs/code_ref/index.rst @@ -1,8 +1,8 @@ .. _reference: -============== -Code Reference -============== +=== +API +=== .. toctree:: :maxdepth: 2 diff --git a/radiospectra/net/sources/callisto.py b/radiospectra/net/sources/callisto.py index ecd59f0..e8e9108 100644 --- a/radiospectra/net/sources/callisto.py +++ b/radiospectra/net/sources/callisto.py @@ -8,17 +8,17 @@ class CALLISTOClient(GenericClient): """ - Provides access to eCallisto radio spectrometer network `archive. + Provides access to `eCallisto radio spectrometer`_ `data archive`_. - `__ - at `FHNW, `__. + .. _`eCallisto radio spectrometer`_: http://soleil80.cs.technik.fhnw.ch/solarradio/data/2002-20yy_Callisto/ + .. _`data archive`: https://spdf.gsfc.nasa.gov - For further information `see `-- + `For further information `__. Notes ----- For specific information on the meaning of the filename in particular the ID field please - `see ` + `see `__ Examples -------- diff --git a/radiospectra/net/sources/eovsa.py b/radiospectra/net/sources/eovsa.py index fc8d85c..e1b69bc 100644 --- a/radiospectra/net/sources/eovsa.py +++ b/radiospectra/net/sources/eovsa.py @@ -6,9 +6,9 @@ class EOVSAClient(GenericClient): """ - Client provides access to `Extended Owens Valley Solar Array. + Provides access to `Extended Owens Valley Solar Array`_ (EOVSA) data. - `__ (EOVSA) data. + .. _`Extended Owens Valley Solar Array`: http://www.ovsa.njit.edu Examples -------- diff --git a/radiospectra/net/sources/psp.py b/radiospectra/net/sources/psp.py index 0edc8f9..a9f2e34 100644 --- a/radiospectra/net/sources/psp.py +++ b/radiospectra/net/sources/psp.py @@ -29,7 +29,8 @@ class RFSClient(GenericClient): Results from 1 Provider: 8 Results from the RFSClient: - Start Time End Time ... Provider Wavelength [2] + + Start Time End Time ... Provider Wavelength ... kHz ----------------------- ----------------------- ... -------- ----------------- 2019-10-02 00:00:00.000 2019-10-02 23:59:59.999 ... SPDF 10.0 .. 1700.0 diff --git a/radiospectra/net/sources/stereo.py b/radiospectra/net/sources/stereo.py index 4a9c388..01b0dcf 100644 --- a/radiospectra/net/sources/stereo.py +++ b/radiospectra/net/sources/stereo.py @@ -19,10 +19,10 @@ class SWAVESClient(GenericClient): """ - Provides access to STEREO `S-WAVES. + Provides access to `STEREO S-WAVES`_ radio `data archive`_. - `__ radio data `archive - `__ + .. _`STEREO S-WAVES`: https://swaves.gsfc.nasa.gov/swaves_instr.html + .. _`data archive`: https://solar-radio.gsfc.nasa.gov/data/stereo Examples -------- @@ -31,8 +31,8 @@ class SWAVESClient(GenericClient): >>> results = Fido.search(a.Time("2010/10/01", "2010/10/02"), ... a.Instrument('SWAVES')) # doctest: +REMOTE_DATA >>> results[1] #doctest: +REMOTE_DATA - + Start Time End Time ... Provider Wavelength ... kHz ----------------------- ----------------------- ... -------- ---------------- 2010-10-01 00:00:00.000 2010-10-01 23:59:59.999 ... NASA 10.0 .. 160.0 @@ -43,7 +43,6 @@ class SWAVESClient(GenericClient): 2010-10-02 00:00:00.000 2010-10-02 23:59:59.999 ... NASA 10.0 .. 160.0 2010-10-01 00:00:00.000 2010-10-01 23:59:59.999 ... NASA 125.0 .. 16000.0 2010-10-02 00:00:00.000 2010-10-02 23:59:59.999 ... NASA 125.0 .. 16000.0 - """ baseurl = ( diff --git a/radiospectra/net/sources/wind.py b/radiospectra/net/sources/wind.py index 6da0a9c..9d7c204 100644 --- a/radiospectra/net/sources/wind.py +++ b/radiospectra/net/sources/wind.py @@ -20,10 +20,10 @@ class WAVESClient(GenericClient): """ - Provides access to WIND `WAVES `__ radio data `archive. + Provides access to `WIND WAVES`_ radio `data archive`_. - `__ + .. _`WIND WAVES`: https://solar-radio.gsfc.nasa.gov/wind/instrument.html + .. _`data archive`: https://solar-radio.gsfc.nasa.gov/data/wind Examples -------- @@ -32,11 +32,12 @@ class WAVESClient(GenericClient): >>> results = Fido.search(a.Time("2010/10/01", "2010/10/02"), ... a.Instrument('WAVES')) # doctest: +REMOTE_DATA >>> results #doctest: +REMOTE_DATA - + Results from 1 Provider: 4 Results from the WAVESClient: - Start Time End Time ... Provider Wavelength [2] + + Start Time End Time ... Provider Wavelength ... kHz ----------------------- ----------------------- ... -------- ----------------- 2010-10-01 00:00:00.000 2010-10-01 23:59:59.999 ... NASA 20.0 .. 1040.0 @@ -44,6 +45,7 @@ class WAVESClient(GenericClient): 2010-10-01 00:00:00.000 2010-10-01 23:59:59.999 ... NASA 1075.0 .. 13825.0 2010-10-02 00:00:00.000 2010-10-02 23:59:59.999 ... NASA 1075.0 .. 13825.0 + """ baseurl = r"https://solar-radio.gsfc.nasa.gov/data/wind/{Wavelength}/{year}/{Wavelength}/" r"(\d){{8}}.{ext}" diff --git a/radiospectra/spectrogram2/spectrogram.py b/radiospectra/spectrogram2/spectrogram.py index b102f1f..b2c481c 100644 --- a/radiospectra/spectrogram2/spectrogram.py +++ b/radiospectra/spectrogram2/spectrogram.py @@ -671,7 +671,7 @@ def _read_cdf(file): @staticmethod def _read_fits(file): - hd_pairs = fits.read(file) + hd_pairs = fits.open(file) if "e-CALLISTO" in hd_pairs[0].header.get("CONTENT", ""): data = hd_pairs[0].data diff --git a/tox.ini b/tox.ini index 6190117..8d4e6d5 100644 --- a/tox.ini +++ b/tox.ini @@ -23,6 +23,7 @@ description = setenv = MPLBACKEND = agg COLUMNS = 180 + HIDE_PARFIVE_PROGESS = True PYTEST_COMMAND = pytest -vvv -s -ra --pyargs radiospectra --cov-report=xml --cov=radiospectra --cov-config={toxinidir}/setup.cfg {toxinidir}/docs devdeps,build_docs,online: HOME = {envtmpdir} SUNPY_SAMPLEDIR = {env:SUNPY_SAMPLEDIR:{toxinidir}/.tox/{envname}/sample_data/} @@ -77,7 +78,7 @@ commands = pre-commit run --verbose --all-files --show-diff-on-failure # This env requires tox-conda. -[testenv:conda] +[testenv:py39-conda] pypi_filter = basepython = python3.9 extras = From bd7519bec5cd203571fc0bf9868a4bb3f2bee842 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 24 May 2022 16:30:08 -0700 Subject: [PATCH 6/6] who even knows --- .pre-commit-config.yaml | 5 -- radiospectra/__init__.py | 2 +- radiospectra/_dev/__init__.py | 5 +- radiospectra/net/attrs.py | 2 +- radiospectra/net/sources/callisto.py | 16 +++-- radiospectra/net/sources/eovsa.py | 4 +- radiospectra/net/sources/psp.py | 16 ++--- radiospectra/net/sources/rstn.py | 4 +- radiospectra/net/sources/stereo.py | 15 ++--- radiospectra/net/sources/wind.py | 17 +++-- radiospectra/sources/callisto.py | 23 ++++--- radiospectra/spectrogram.py | 79 +++++++++++++----------- radiospectra/spectrogram2/__init__.py | 6 +- radiospectra/spectrogram2/spectrogram.py | 21 ++++--- radiospectra/spectrum.py | 5 +- radiospectra/tests/test_util.py | 14 ++--- radiospectra/util.py | 40 +++++++----- 17 files changed, 145 insertions(+), 129 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0f67641..54f9db2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,4 @@ repos: - - repo: https://github.com/myint/docformatter - rev: v1.4 - hooks: - - id: docformatter - args: [--in-place, --pre-summary-newline, --make-summary-multi] - repo: https://github.com/myint/autoflake rev: v1.4 hooks: diff --git a/radiospectra/__init__.py b/radiospectra/__init__.py index a049695..ec3e41f 100644 --- a/radiospectra/__init__.py +++ b/radiospectra/__init__.py @@ -1,5 +1,5 @@ """ -radiospectra +Radiospectra ============ An open-source Python library for radio spectra in solar physics. diff --git a/radiospectra/_dev/__init__.py b/radiospectra/_dev/__init__.py index 6415980..2508041 100644 --- a/radiospectra/_dev/__init__.py +++ b/radiospectra/_dev/__init__.py @@ -1,6 +1,7 @@ """ -This package contains utilities that are only used when developing drms in a -copy of the source repository. +This package contains utilities that are only used when developing drms in a copy of the source. + +repository. These files are not installed, and should not be assumed to exist at runtime. diff --git a/radiospectra/net/attrs.py b/radiospectra/net/attrs.py index 98e7654..2e27a94 100644 --- a/radiospectra/net/attrs.py +++ b/radiospectra/net/attrs.py @@ -5,7 +5,7 @@ class Spacecraft(SimpleAttr): """ - The STEREO Spacecraft A (Ahead) or B (Behind) + The STEREO Spacecraft A (Ahead) or B (Behind). """ diff --git a/radiospectra/net/sources/callisto.py b/radiospectra/net/sources/callisto.py index e8e9108..17e494b 100644 --- a/radiospectra/net/sources/callisto.py +++ b/radiospectra/net/sources/callisto.py @@ -8,17 +8,14 @@ class CALLISTOClient(GenericClient): """ - Provides access to `eCallisto radio spectrometer`_ `data archive`_. + Provides access to `eCallisto radio spectrometer `__ + `data archive `__. - .. _`eCallisto radio spectrometer`_: http://soleil80.cs.technik.fhnw.ch/solarradio/data/2002-20yy_Callisto/ - .. _`data archive`: https://spdf.gsfc.nasa.gov - - `For further information `__. + `Further information `__. Notes ----- - For specific information on the meaning of the filename in particular the ID field please - `see `__ + `Specific information on the meaning of the filename. `__ Examples -------- @@ -80,8 +77,9 @@ def register_values(cls): @classmethod def _can_handle_query(cls, *query): """ - Method the `sunpy.net.fido_factory.UnifiedDownloaderFactory` class uses - to dispatch queries to this Client. + Method the `sunpy.net.fido_factory.UnifiedDownloaderFactory` class uses to dispatch queries. + + to this Client. """ regattrs_dict = cls.register_values() optional = {k for k in regattrs_dict.keys()} - cls.required diff --git a/radiospectra/net/sources/eovsa.py b/radiospectra/net/sources/eovsa.py index e1b69bc..6581bfa 100644 --- a/radiospectra/net/sources/eovsa.py +++ b/radiospectra/net/sources/eovsa.py @@ -6,9 +6,7 @@ class EOVSAClient(GenericClient): """ - Provides access to `Extended Owens Valley Solar Array`_ (EOVSA) data. - - .. _`Extended Owens Valley Solar Array`: http://www.ovsa.njit.edu + Provides access to `Extended Owens Valley Solar Array `__ (EOVSA) data. Examples -------- diff --git a/radiospectra/net/sources/psp.py b/radiospectra/net/sources/psp.py index a9f2e34..a46a2c6 100644 --- a/radiospectra/net/sources/psp.py +++ b/radiospectra/net/sources/psp.py @@ -14,9 +14,9 @@ class RFSClient(GenericClient): """ - Provides access to Parker Solar Probe FIELDS Radio Frequency Spectrometer - data `archive `__ at `NASA - Goddard Space Physics Data Facility (SPDF) `__. + Provides access to Parker Solar Probe FIELDS Radio Frequency Spectrometer data + `archive `__ at + `NASA Goddard Space Physics Data Facility (SPDF) `__. Examples -------- @@ -54,8 +54,9 @@ class RFSClient(GenericClient): @classmethod def _check_wavelengths(cls, wavelength): """ - Check for overlap between given wavelength and receiver frequency - coverage defined in `RECEIVER_FREQUENCIES`. + Check for overlap between given wavelength and receiver frequency coverage defined in. + + `RECEIVER_FREQUENCIES`. Parameters ---------- @@ -121,8 +122,9 @@ def search(self, *args, **kwargs): def post_search_hook(self, exdict, matchdict): """ - This method converts 'rfs_hfr' and 'rfs_lfr' in the url's metadata to - the frequency ranges of for low and high frequency receivers. + This method converts 'rfs_hfr' and 'rfs_lfr' in the url's metadata to the frequency ranges. + + of for low and high frequency receivers. """ rowdict = super().post_search_hook(exdict, matchdict) if rowdict["Wavelength"] == "rfs_hfr": diff --git a/radiospectra/net/sources/rstn.py b/radiospectra/net/sources/rstn.py index 4ad0b47..e6eeb52 100644 --- a/radiospectra/net/sources/rstn.py +++ b/radiospectra/net/sources/rstn.py @@ -10,8 +10,8 @@ class RSTNClient(GenericClient): """ - Radio Spectrometer Telescope Network (RSTN) hosted at NOAA `National - Geophysical Data `__ (NGDC) archive. + Radio Spectrometer Telescope Network (RSTN) hosted at NOAA + `National Geophysical Data `__ (NGDC) archive. Examples -------- diff --git a/radiospectra/net/sources/stereo.py b/radiospectra/net/sources/stereo.py index 01b0dcf..bb5ec48 100644 --- a/radiospectra/net/sources/stereo.py +++ b/radiospectra/net/sources/stereo.py @@ -19,10 +19,9 @@ class SWAVESClient(GenericClient): """ - Provides access to `STEREO S-WAVES`_ radio `data archive`_. + Provides access to `STEREO S-WAVES `__ radio. - .. _`STEREO S-WAVES`: https://swaves.gsfc.nasa.gov/swaves_instr.html - .. _`data archive`: https://solar-radio.gsfc.nasa.gov/data/stereo + `data archive `__. Examples -------- @@ -55,8 +54,9 @@ class SWAVESClient(GenericClient): @classmethod def _check_wavelengths(cls, wavelength): """ - Check for overlap between given wavelength and receiver frequency - coverage defined in `RECEIVER_FREQUENCIES`. + Check for overlap between given wavelength and receiver frequency coverage defined in. + + `RECEIVER_FREQUENCIES`. Parameters ---------- @@ -124,8 +124,9 @@ def search(self, *args, **kwargs): def post_search_hook(self, exdict, matchdict): """ - This method converts 'rfs_hfr' and 'rfs_lfr' in the url's metadata to - the frequency ranges of for low and high frequency receivers. + This method converts 'rfs_hfr' and 'rfs_lfr' in the url's metadata to the frequency ranges. + + of for low and high frequency receivers. """ rowdict = super().post_search_hook(exdict, matchdict) if rowdict["Wavelength"] == "hfr": diff --git a/radiospectra/net/sources/wind.py b/radiospectra/net/sources/wind.py index 9d7c204..1f4d4c8 100644 --- a/radiospectra/net/sources/wind.py +++ b/radiospectra/net/sources/wind.py @@ -20,10 +20,8 @@ class WAVESClient(GenericClient): """ - Provides access to `WIND WAVES`_ radio `data archive`_. - - .. _`WIND WAVES`: https://solar-radio.gsfc.nasa.gov/wind/instrument.html - .. _`data archive`: https://solar-radio.gsfc.nasa.gov/data/wind + Provides access to `WIND WAVES `__ radio + `data archive `__. Examples -------- @@ -55,8 +53,9 @@ class WAVESClient(GenericClient): @classmethod def _check_wavelengths(cls, wavelength): """ - Check for overlap between given wavelength and receiver frequency - coverage defined in `RECEIVER_FREQUENCIES`. + Check for overlap between given wavelength and receiver frequency coverage defined in. + + `RECEIVER_FREQUENCIES`. Parameters ---------- @@ -122,9 +121,9 @@ def search(self, *args, **kwargs): def post_search_hook(self, exdict, matchdict): """ - This method converts 'rad1' and 'rad1' in the url's metadata to the - frequency ranges of for low and high frequency receivers and removes - the ext. + This method converts 'rad1' and 'rad1' in the url's metadata to the frequency ranges of for. + + low and high frequency receivers and removes the ext. """ rowdict = super().post_search_hook(exdict, matchdict) rowdict.pop("ext", None) diff --git a/radiospectra/sources/callisto.py b/radiospectra/sources/callisto.py index 472ba98..9a0ee86 100644 --- a/radiospectra/sources/callisto.py +++ b/radiospectra/sources/callisto.py @@ -208,8 +208,10 @@ def get_header(self): @classmethod def read(cls, filename, **kwargs): """ - Reads in FITS file and return a new CallistoSpectrogram. Any unknown - (i.e. any except filename) keyword arguments get passed to fits.open. + Reads in FITS file and return a new CallistoSpectrogram. + + Any unknown (i.e. any except + filename) keyword arguments get passed to fits.open. Parameters ---------- @@ -365,8 +367,7 @@ def read_many(cls, filenames, sort_by=None): @classmethod def from_range(cls, instrument, start, end, **kwargs): """ - Automatically download data from instrument between start and end and - join it together. + Automatically download data from instrument between start and end and join it together. Parameters ---------- @@ -422,8 +423,9 @@ def _fun(p): def _homogenize_params(self, other, maxdiff=1): """ - Return triple with a tuple of indices (in self and other, - respectively), factors and constants at these frequencies. + Return triple with a tuple of indices (in self and other, respectively), factors and. + + constants at these frequencies. Parameters ---------- @@ -453,10 +455,11 @@ def _homogenize_params(self, other, maxdiff=1): def homogenize(self, other, maxdiff=1): """ Return overlapping part of self and other as (self, other) tuple. - Homogenize intensities so that the images can be used with - combine_frequencies. Note that this works best when most of the picture - is signal, so use :meth:`in_interval` to select the subset of your - image before applying this method. + + Homogenize intensities so + that the images can be used with combine_frequencies. Note that this works best when most of + the picture is signal, so use :meth:`in_interval` to select the subset of your image before + applying this method. Parameters ---------- diff --git a/radiospectra/spectrogram.py b/radiospectra/spectrogram.py index 881b9ee..2343efa 100644 --- a/radiospectra/spectrogram.py +++ b/radiospectra/spectrogram.py @@ -43,8 +43,9 @@ def figure(*args, **kwargs): """ - Returns a new SpectroFigure, a figure extended with features useful for - analysis of spectrograms. + Returns a new SpectroFigure, a figure extended with features useful for analysis of. + + spectrograms. Compare pyplot.figure. """ @@ -64,8 +65,9 @@ def _min_delt(arr): def _list_formatter(lst, fun=None): """ - Returns a function that takes x, pos and returns fun(lst[x]) if fun is not - None, else lst[x] or "" if x is out of range. + Returns a function that takes x, pos and returns fun(lst[x]) if fun is not None, else lst[x] or. + + "" if x is out of range. """ def _fun(x, pos): @@ -399,8 +401,7 @@ def __init__( def time_formatter(self, x, pos): """ - This returns the label for the tick of value x at a specified pos on - the time axis. + This returns the label for the tick of value x at a specified pos on the time axis. """ # Callback, cannot avoid unused arguments. # pylint: disable=W0613 @@ -613,8 +614,7 @@ def __getitem__(self, key): def clip_freq(self, vmin=None, vmax=None): """ - Return a new spectrogram only consisting of frequencies in the - interval. + Return a new spectrogram only consisting of frequencies in the interval. [vmin, vmax]. @@ -640,9 +640,10 @@ def clip_freq(self, vmin=None, vmax=None): def auto_find_background(self, amount=0.05): """ - Automatically find the background. This is done by first subtracting - the average value in each channel and then finding those times which - have the lowest standard deviation. + Automatically find the background. + + This is done by first subtracting the average value in + each channel and then finding those times which have the lowest standard deviation. Parameters ---------- @@ -680,8 +681,9 @@ def subtract_bg(self): def randomized_auto_const_bg(self, amount): """ - Automatically determine background. Only consider a randomly chosen - subset of the image. + Automatically determine background. + + Only consider a randomly chosen subset of the image. Parameters ---------- @@ -713,8 +715,10 @@ def randomized_auto_const_bg(self, amount): def randomized_subtract_bg(self, amount): """ - Perform randomized constant background subtraction. Does not produce - the same result every time it is run. + Perform randomized constant background subtraction. + + Does not produce the same result every + time it is run. Parameters ---------- @@ -750,8 +754,10 @@ def clip_values(self, vmin=None, vmax=None, out=None): def rescale(self, vmin=0, vmax=1, dtype=np.dtype("float32")): """ - Rescale intensities to [vmin, vmax]. Note that vmin ≠ vmax and - spectrogram.min() ≠ spectrogram.max(). + Rescale intensities to [vmin, vmax]. + + Note that vmin ≠ vmax and spectrogram.min() ≠ + spectrogram.max(). Parameters ---------- @@ -776,8 +782,9 @@ def rescale(self, vmin=0, vmax=1, dtype=np.dtype("float32")): def interpolate(self, frequency): """ - Linearly interpolate intensity at unknown frequency using linear - interpolation of its two neighbours. + Linearly interpolate intensity at unknown frequency using linear interpolation of its two. + + neighbours. Parameters ---------- @@ -835,8 +842,9 @@ def linearize_freqs(self, delta_freq=None): def freq_overlap(self, other): """ - Get frequency range present in both spectrograms. Returns (min, max) - tuple. + Get frequency range present in both spectrograms. + + Returns (min, max) tuple. Parameters ---------- @@ -851,8 +859,9 @@ def freq_overlap(self, other): def time_to_x(self, time): """ - Return x-coordinate in spectrogram that corresponds to the passed - `~datetime.datetime` value. + Return x-coordinate in spectrogram that corresponds to the passed `~datetime.datetime`. + + value. Parameters ---------- @@ -942,8 +951,7 @@ def make_array(shape, dtype=np.dtype("float32")): @staticmethod def memmap(filename): """ - Return function that takes shape and dtype and returns a memory mapped - array. + Return function that takes shape and dtype and returns a memory mapped array. Parameters ---------- @@ -954,8 +962,7 @@ def memmap(filename): def resample_time(self, new_delt): """ - Rescale image so that the difference in time between pixels is new_delt - seconds. + Rescale image so that the difference in time between pixels is new_delt seconds. Parameters ---------- @@ -986,8 +993,7 @@ def resample_time(self, new_delt): @classmethod def join_many(cls, specs, mk_arr=None, nonlinear=False, maxgap=0, fill=JOIN_REPEAT): """ - Produce new Spectrogram that contains spectrograms joined together in - time. + Produce new Spectrogram that contains spectrograms joined together in time. Parameters ---------- @@ -1116,8 +1122,7 @@ def join_many(cls, specs, mk_arr=None, nonlinear=False, maxgap=0, fill=JOIN_REPE def time_to_x(self, time): """ - Return x-coordinate in spectrogram that corresponds to the passed - datetime value. + Return x-coordinate in spectrogram that corresponds to the passed datetime value. Parameters ---------- @@ -1161,8 +1166,10 @@ def intersect_time(specs): @classmethod def combine_frequencies(cls, specs): """ - Return new spectrogram that contains frequencies from all the - spectrograms in spec. Only returns time intersection of all of them. + Return new spectrogram that contains frequencies from all the spectrograms in spec. + + Only + returns time intersection of all of them. Parameters ---------- @@ -1204,8 +1211,10 @@ def combine_frequencies(cls, specs): def check_linearity(self, err=None, err_factor=None): """ - Check linearity of time axis. If err is given, tolerate absolute - derivation from average delta up to err. If err_factor is given, + Check linearity of time axis. + + If err is given, tolerate absolute derivation from average + delta up to err. If err_factor is given, tolerate up to err_factor * average_delta. If both are given, TypeError is raised. Default to err=0. diff --git a/radiospectra/spectrogram2/__init__.py b/radiospectra/spectrogram2/__init__.py index b458781..bd9ae77 100644 --- a/radiospectra/spectrogram2/__init__.py +++ b/radiospectra/spectrogram2/__init__.py @@ -1,7 +1,7 @@ """ -The spectrogram2 module aims to provide a more sunpy-like interface to -radiospectra data similar to that of `~sunpy.map.Map` and -`~sunpy.timeseries.TimeSeries`. +The spectrogram2 module aims to provide a more sunpy-like interface to radiospectra data similar to. + +that of `~sunpy.map.Map` and `~sunpy.timeseries.TimeSeries`. """ from radiospectra.spectrogram2.sources import ( diff --git a/radiospectra/spectrogram2/spectrogram.py b/radiospectra/spectrogram2/spectrogram.py index b2c481c..7579048 100644 --- a/radiospectra/spectrogram2/spectrogram.py +++ b/radiospectra/spectrogram2/spectrogram.py @@ -178,7 +178,7 @@ def plot(self, axes=None, **kwargs): class NonUniformImagePlotMixin: """ - Class provides plotting functions using `NonUniformImage` + Class provides plotting functions using `NonUniformImage`. """ def plotim(self, fig=None, axes=None, **kwargs): @@ -325,8 +325,10 @@ def _validate_meta(self, meta): def _parse_args(self, *args, silence_errors=False, **kwargs): """ - Parses an args list into data-header pairs. args can contain any - mixture of the following entries: + Parses an args list into data-header pairs. + + args can contain any mixture of the following + entries: * tuples of data,header * data, header not in a tuple @@ -420,12 +422,13 @@ def _parse_path(self, arg, **kwargs): def __call__(self, *args, silence_errors=False, **kwargs): """ - Method for running the factory. Takes arbitrary arguments and keyword - arguments and passes them to a sequence of pre-registered types to - determine which is the correct spectrogram-type to build. Arguments - args and kwargs are passed through to the validation function and to - the constructor for the final type. For spectrogram types, validation - function must take a data-header pair as an argument. + Method for running the factory. + + Takes arbitrary arguments and keyword arguments and passes + them to a sequence of pre-registered types to determine which is the correct spectrogram- + type to build. Arguments args and kwargs are passed through to the validation function and + to the constructor for the final type. For spectrogram types, validation function must take + a data-header pair as an argument. Parameters ---------- diff --git a/radiospectra/spectrum.py b/radiospectra/spectrum.py index f8e2c27..015efcc 100644 --- a/radiospectra/spectrum.py +++ b/radiospectra/spectrum.py @@ -17,7 +17,6 @@ class Spectrum(np.ndarray): One-dimensional array which the intensity at a particular frequency at every data-point. - Examples -------- >>> from radiospectra.spectrum import Spectrum @@ -69,7 +68,9 @@ def plot(self, axes=None, **matplot_args): def peek(self, **matplot_args): """ - Plot spectrum onto a new figure. An example is shown below. + Plot spectrum onto a new figure. + + An example is shown below. .. plot:: diff --git a/radiospectra/tests/test_util.py b/radiospectra/tests/test_util.py index abf57e5..cd3db10 100644 --- a/radiospectra/tests/test_util.py +++ b/radiospectra/tests/test_util.py @@ -67,8 +67,9 @@ def test_types(): def test_minimal_pairs(): """ - This should return the pairs of elements from list1 and list2 with minimal - difference between their values. + This should return the pairs of elements from list1 and list2 with minimal difference between. + + their values. """ list1 = [0, 5, 10, 15, 20, 25] list2 = [3, 12, 19, 21, 26, 29] @@ -116,8 +117,7 @@ class TestC(TestA): def test_merge(): """ - This should return a sorted (from greatest to least) merged list from list1 - and list2. + This should return a sorted (from greatest to least) merged list from list1 and list2. """ list1 = [13, 11, 9, 7, 5, 3, 1] list2 = [14, 12, 10, 8, 6, 4, 2] @@ -129,9 +129,9 @@ def test_merge(): def test_to_signed(): """ - This should return a signed type that can hold uint32 and ensure that an - exception is raised when attempting to convert an unsigned 64 bit integer - to an integer. + This should return a signed type that can hold uint32 and ensure that an exception is raised. + + when attempting to convert an unsigned 64 bit integer to an integer. """ assert to_signed(np.dtype("uint32")) == np.dtype("int64") diff --git a/radiospectra/util.py b/radiospectra/util.py index 429aa28..fe11325 100644 --- a/radiospectra/util.py +++ b/radiospectra/util.py @@ -1,8 +1,9 @@ """ -Offer a callable object that dispatches based on arbitrary conditions and -function signature. That means, whenever it is called, it finds the registered -methods that match the input's signature and then checks for user-defined -conditions and types. +Offer a callable object that dispatches based on arbitrary conditions and function signature. + +That +means, whenever it is called, it finds the registered methods that match the input's signature and +then checks for user-defined conditions and types. First, we need to create a new ConditionalDispatch @@ -39,7 +40,6 @@ "There are no functions matching your input parameter " TypeError: There are no functions matching your input parameter signature. - We can then add a branch for floats, giving the condition None that means that this branch is always executed for floats. @@ -101,8 +101,9 @@ def merge(items, key=(lambda x: x)): """ - Given sorted lists of iterables, return new iterable that returns elements - of all iterables sorted with respect to key. + Given sorted lists of iterables, return new iterable that returns elements of all iterables. + + sorted with respect to key. """ state = {} for item in map(iter, items): @@ -138,8 +139,10 @@ def common_base(objs): def to_signed(dtype): """ - Return dtype that can hold data of passed dtype but is signed. Raise - ValueError if no such dtype exists. + Return dtype that can hold data of passed dtype but is signed. + + Raise ValueError if no such dtype + exists. Parameters ---------- @@ -166,8 +169,10 @@ def get_day(dt): def minimal_pairs(one, other): """ - Find pairs of values in one and other with minimal distance. Assumes one - and other are sorted in the same sort sequence. + Find pairs of values in one and other with minimal distance. + + Assumes one and other are sorted in + the same sort sequence. Parameters ---------- @@ -207,7 +212,7 @@ def minimal_pairs(one, other): def run_cls(name): """ - run_cls("foo")(cls, \\*args, \\**kwargs) -> cls.foo(\\*args, \\**kwargs) + Run_cls("foo")(cls, \\*args, \\**kwargs) -> cls.foo(\\*args, \\**kwargs). """ fun = lambda cls, *args, **kwargs: getattr(cls, name)(*args, **kwargs) # NOQA fun.__name__ = str(name) @@ -298,8 +303,7 @@ def _dec(fun): def add(self, fun, condition=None, types=None, check=True): """ - Add fun to ConditionalDispatch under the condition that the arguments - must match. + Add fun to ConditionalDispatch under the condition that the arguments must match. If condition is left out, the function is executed for every input that matches the signature. Functions are considered in @@ -341,9 +345,11 @@ def wrapper(self): def get_signatures(self, prefix="", start=0): """ - Return an iterator containing all possible function signatures. If - prefix is given, use it as function name in signatures, else leave it - out. If start is given, leave out first n elements. + Return an iterator containing all possible function signatures. + + If prefix is given, use it + as function name in signatures, else leave it out. If start is given, leave out first n + elements. If start is -1, leave out first element if the function was created by run_cls.