Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saving a ninjotiff file fails with AttributeError: 'XRImage' object has no attribute 'channels' #11

Open
gerritholl opened this issue Mar 28, 2019 · 9 comments

Comments

@gerritholl
Copy link
Member

Describe the bug

When calling the satpy Scene.save_datasets using writer="ninjotiff", an uncaught exception is raised: AttributeError: 'XRImage' object has no attribute 'channels'

To Reproduce

from satpy import Scene
from satpy.utils import debug_on
debug_on()
from glob import glob
filenames = glob("/tmp/seviri/H-000*1500*")
sc = Scene(reader="seviri_l1b_hrit", filenames=filenames)
sc.load(["VIS006", "VIS008", "IR_108"])
ls = sc.resample("eurol")
ls.save_datasets(writer="ninjotiff", filename="/tmp/testn.tif")

Expected behavior

I expect that output is written and no exception is raised. I would probably also like to not see any warning messages but I don't know if those are related to the problem causing the exception.

Actual results

/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/dask/config.py:168: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.                                                                                                                                                                                                                                                                                  [19/60]
  data = yaml.load(f.read()) or {}
/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/distributed/config.py:20: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  defaults = yaml.load(f)
[DEBUG: 2019-03-28 13:37:07 : satpy.scene] Setting 'PPP_CONFIG_DIR' to '/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python*/site-packages/satpy/etc'
[DEBUG: 2019-03-28 13:37:07 : satpy.readers] Reading ['/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/etc/readers/seviri_l1b_hrit.yaml']
[DEBUG: 2019-03-28 13:37:07 : satpy.readers.yaml_reader] Assigning to seviri_l1b_hrit: ['/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000007___-201606011500-
__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000008___-201606011500-__', '
/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000008___-201606011500-__', '/tmp/s
eviri/H-000-MSG3__-MSG3________-IR_120___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000001___-201606011500-__', '/tmp/seviri/
H-000-MSG3__-MSG3________-IR_108___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000008___-201606011500-__', '/tmp/seviri/H-000-
MSG3__-MSG3________-IR_097___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-_________-PRO______-201606011500-__', '/tmp/seviri/H-000-MSG3__
-MSG3________-WV_073___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3_
_______-WV_073___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3_______
_-IR_039___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_0
16___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-
000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000006
___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000004___-20
1606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-_________-EPI______-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000020___-20160601
1500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000022___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000019___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000012___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000006___-201606011500-_
_', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000010___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000011___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000009___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000017___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000016___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000013___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000014___-201606011500-__', '/
tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000021___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000018___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000024___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000023___-201606011500-__', '/tmp/se
viri/H-000-MSG3__-MSG3________-HRV______-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000015___-201606011500-__']
[INFO: 2019-03-28 13:37:07 : hrit_msg] No IMPF configuration field found in prologue.
[DEBUG: 2019-03-28 13:37:08 : satpy.composites] Looking for composites config file seviri.yaml
[DEBUG: 2019-03-28 13:37:08 : satpy.composites] Looking for composites config file visir.yaml
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.007857
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.006732
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.006805
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.006784
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.006905
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.006897
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.006894
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.006942
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004683
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.005133
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004710
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004681
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004688
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.008215
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004987
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004489
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004633
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004610
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004626
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004658
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.009303
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.005038
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004523
[DEBUG: 2019-03-28 13:37:08 : hrit_msg] Calibration time 0:00:00.004530
[DEBUG: 2019-03-28 13:37:08 : satpy.scene] Setting 'PPP_CONFIG_DIR' to '/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python*/site-packages/satpy/etc'
[DEBUG: 2019-03-28 13:37:08 : satpy.scene] Resampling DatasetID(name='IR_108', wavelength=(9.8, 10.8, 11.8), resolution=3000.403165817, polarization=None, calibration='brightness_temperature', level=None, modifiers=())
[INFO: 2019-03-28 13:37:10 : satpy.resample] Using default KDTree resampler
[DEBUG: 2019-03-28 13:37:10 : satpy.resample] Computing kd-tree parameters
[DEBUG: 2019-03-28 13:37:10 : satpy.resample] Resampling reshape-6f37a4d992d6ffe4a61825cb2ee5da49
[DEBUG: 2019-03-28 13:37:10 : satpy.scene] Resampling DatasetID(name='VIS008', wavelength=(0.74, 0.81, 0.88), resolution=3000.403165817, polarization=None, calibration='reflectance', level=None, modifiers=())
[DEBUG: 2019-03-28 13:37:10 : satpy.resample] Computing kd-tree parameters
[DEBUG: 2019-03-28 13:37:10 : satpy.resample] Resampling reshape-82f00134ddfb95a08aafe671656a291c
[DEBUG: 2019-03-28 13:37:10 : satpy.scene] Resampling DatasetID(name='VIS006', wavelength=(0.56, 0.635, 0.71), resolution=3000.403165817, polarization=None, calibration='reflectance', level=None, modifiers=())
[DEBUG: 2019-03-28 13:37:10 : satpy.resample] Computing kd-tree parameters
[DEBUG: 2019-03-28 13:37:10 : satpy.resample] Resampling reshape-f3fb1589385959a1e9b814c182bbae79
[DEBUG: 2019-03-28 13:37:10 : satpy.writers] Reading ['/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/etc/writers/ninjotiff.yaml']
/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/pyninjotiff/tifffile.py:155: UserWarning: failed to import the optional _tifffile C extension module.
Loading of some compressed images will be slow.
Tifffile.c can be obtained at http://www.lfd.uci.edu/~gohlke/
  "failed to import the optional _tifffile C extension module.\n"
[DEBUG: 2019-03-28 13:37:10 : satpy.writers] Enhancement configuration options: [{'method': <function stretch at 0x7f6921334938>, 'name': 'stretch', 'kwargs': {'stretch': 'linear'}}]
[DEBUG: 2019-03-28 13:37:10 : trollimage.xrimage] Applying stretch linear with parameters {}
[DEBUG: 2019-03-28 13:37:10 : trollimage.xrimage] Perform a linear contrast stretch.
[DEBUG: 2019-03-28 13:37:10 : trollimage.xrimage] Calculate the histogram quantiles:
[DEBUG: 2019-03-28 13:37:10 : trollimage.xrimage] Left and right quantiles: 0.005 0.005
Traceback (most recent call last):
  File "mwe.py", line 9, in <module>
    ls.save_datasets(writer="ninjotiff", filename="/tmp/testn.tif")
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/scene.py", line 1181, in save_datasets
    return writer.save_datasets(datasets, compute=compute, **save_kwargs)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/writers/__init__.py", line 639, in save_datasets
    results.append(self.save_dataset(ds, compute=False, **kwargs))
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/writers/__init__.py", line 770, in save_dataset
    return self.save_image(img, filename=filename, compute=compute, fill_value=fill_value, **kwargs)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/writers/ninjotiff.py", line 53, in save_image
    nt.save(img, filename, **kwargs)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/pyninjotiff/ninjotiff.py", line 487, in save
    value_range_measurement_unit=value_range_measurement_unit,)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/pyninjotiff/ninjotiff.py", line 314, in _finalize
    data = img.channels[0]
AttributeError: 'XRImage' object has no attribute 'channels'

Environment Info:

  • Python 2.7.16 (pyninjotiff does not currently support Python 3, see pyninjotiff is not Python 3 compatible #10)
  • OS: CentOS Linux release 7.6.1810 (Core), Linux kernel 3.10.0-957.5.1.el7.x86_64
  • SatPy Version: 0.13.0
  • PyResample Version: 1.11.2
  • pyninjotiff version: 0.1.0
@gerritholl
Copy link
Member Author

Running from the latest git master, the same test scripts fails with KeyError: 'sat_id' instead (see below).

I don't know if this is the same issue or a different issue. It does appear to run slightly longer.

/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/dask/config.py:168: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.                                                                                                                                                                                                                                                                                 [45/195]
  data = yaml.load(f.read()) or {}
/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/distributed/config.py:20: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  defaults = yaml.load(f)
[DEBUG: 2019-03-28 13:54:40 : satpy.scene] Setting 'PPP_CONFIG_DIR' to '/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python*/site-packages/satpy/etc'
[DEBUG: 2019-03-28 13:54:40 : satpy.readers] Reading ['/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/etc/readers/seviri_l1b_hrit.yaml']
[DEBUG: 2019-03-28 13:54:40 : satpy.readers.yaml_reader] Assigning to seviri_l1b_hrit: ['/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000007___-201606011500-
__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_087___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000008___-201606011500-__', '
/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_062___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000008___-201606011500-__', '/tmp/s
eviri/H-000-MSG3__-MSG3________-IR_120___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_120___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000001___-201606011500-__', '/tmp/seviri/
H-000-MSG3__-MSG3________-IR_108___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_108___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000008___-201606011500-__', '/tmp/seviri/H-000-
MSG3__-MSG3________-IR_097___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_097___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-_________-PRO______-201606011500-__', '/tmp/seviri/H-000-MSG3__
-MSG3________-WV_073___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-WV_073___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3_
_______-WV_073___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3_______
_-IR_039___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_039___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_0
16___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_016___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-
000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-IR_134___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000006
___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS006___-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000006___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000004___-20
1606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-VIS008___-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-_________-EPI______-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000020___-20160601
1500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000008___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000022___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000002___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000019___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000004___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000012___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000006___-201606011500-_
_', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000010___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000011___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000009___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000017___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000016___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000013___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000014___-201606011500-__', '/
tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000001___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000003___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000021___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000018___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000005___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000024___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000023___-201606011500-__', '/tmp/se
viri/H-000-MSG3__-MSG3________-HRV______-000007___-201606011500-__', '/tmp/seviri/H-000-MSG3__-MSG3________-HRV______-000015___-201606011500-__']
[INFO: 2019-03-28 13:54:40 : hrit_msg] No IMPF configuration field found in prologue.
[DEBUG: 2019-03-28 13:54:40 : satpy.composites] Looking for composites config file seviri.yaml
[DEBUG: 2019-03-28 13:54:40 : satpy.composites] Looking for composites config file visir.yaml
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.007924
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.006818
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.006919
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.006889
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.006953
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.006952
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.006958
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.006986
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004737
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.005189
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004710
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004736
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004699
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004657
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.009599
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004995
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004735
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004720
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.005228
[DEBUG: 2019-03-28 13:54:40 : hrit_msg] Calibration time 0:00:00.004704
[DEBUG: 2019-03-28 13:54:41 : hrit_msg] Calibration time 0:00:00.004733
[DEBUG: 2019-03-28 13:54:41 : hrit_msg] Calibration time 0:00:00.009278
[DEBUG: 2019-03-28 13:54:41 : hrit_msg] Calibration time 0:00:00.005475
[DEBUG: 2019-03-28 13:54:41 : hrit_msg] Calibration time 0:00:00.004634
[DEBUG: 2019-03-28 13:54:41 : satpy.scene] Setting 'PPP_CONFIG_DIR' to '/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python*/site-packages/satpy/etc'
[DEBUG: 2019-03-28 13:54:41 : satpy.scene] Resampling DatasetID(name='IR_108', wavelength=(9.8, 10.8, 11.8), resolution=3000.403165817, polarization=None, calibration='brightness_temperature', level=None, modifiers=())
[INFO: 2019-03-28 13:54:42 : satpy.resample] Using default KDTree resampler
[DEBUG: 2019-03-28 13:54:42 : satpy.resample] Computing kd-tree parameters
[DEBUG: 2019-03-28 13:54:42 : satpy.resample] Resampling reshape-6f37a4d992d6ffe4a61825cb2ee5da49
[DEBUG: 2019-03-28 13:54:42 : satpy.scene] Resampling DatasetID(name='VIS008', wavelength=(0.74, 0.81, 0.88), resolution=3000.403165817, polarization=None, calibration='reflectance', level=None, modifiers=())
[DEBUG: 2019-03-28 13:54:42 : satpy.resample] Computing kd-tree parameters
[DEBUG: 2019-03-28 13:54:42 : satpy.resample] Resampling reshape-82f00134ddfb95a08aafe671656a291c
[DEBUG: 2019-03-28 13:54:42 : satpy.scene] Resampling DatasetID(name='VIS006', wavelength=(0.56, 0.635, 0.71), resolution=3000.403165817, polarization=None, calibration='reflectance', level=None, modifiers=())
[DEBUG: 2019-03-28 13:54:42 : satpy.resample] Computing kd-tree parameters
[DEBUG: 2019-03-28 13:54:42 : satpy.resample] Resampling reshape-f3fb1589385959a1e9b814c182bbae79
[DEBUG: 2019-03-28 13:54:42 : satpy.writers] Reading ['/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/etc/writers/ninjotiff.yaml']
/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/pyninjotiff/tifffile.py:155: UserWarning: failed to import the optional _tifffile C extension module.
Loading of some compressed images will be slow.
Tifffile.c can be obtained at http://www.lfd.uci.edu/~gohlke/
  "failed to import the optional _tifffile C extension module.\n"
[DEBUG: 2019-03-28 13:54:42 : satpy.writers] Enhancement configuration options: [{'method': <function stretch at 0x7f30c88c9938>, 'name': 'stretch', 'kwargs': {'stretch': 'linear'}}]
[DEBUG: 2019-03-28 13:54:42 : trollimage.xrimage] Applying stretch linear with parameters {}
[DEBUG: 2019-03-28 13:54:42 : trollimage.xrimage] Perform a linear contrast stretch.
[DEBUG: 2019-03-28 13:54:42 : trollimage.xrimage] Calculate the histogram quantiles:
[DEBUG: 2019-03-28 13:54:42 : trollimage.xrimage] Left and right quantiles: 0.005 0.005
[DEBUG: 2019-03-28 13:54:49 : trollimage.xrimage] Interval: left=<xarray.DataArray (bands: 1)>
array([221.103226])
Coordinates:
    quantile  float64 0.005
Dimensions without coordinates: bands, right=<xarray.DataArray (bands: 1)>
array([323.125336])
Coordinates:
    quantile  float64 0.995
Dimensions without coordinates: bands
[DEBUG: 2019-03-28 13:54:56 : trollimage.xrimage] Interval: left=<xarray.DataArray (bands: 1)>
array([221.103226])
Coordinates:
    quantile  float64 0.005
Dimensions without coordinates: bands, right=<xarray.DataArray (bands: 1)>
array([323.125336])
Coordinates:
    quantile  float64 0.995
Dimensions without coordinates: bands
[DEBUG: 2019-03-28 13:54:56 : pyninjotiff.ninjotiff] Before scaling: 0.00, 197.34, 255.00
[DEBUG: 2019-03-28 13:54:56 : pyninjotiff.ninjotiff] Doing auto scaling
[DEBUG: 2019-03-28 13:54:56 : pyninjotiff.ninjotiff] After scaling:  1.00, 197.34, 255.00
[DEBUG: 2019-03-28 13:54:56 : pyninjotiff.ninjotiff] Rescaling:      0.00, 197.11, 255.00
[INFO: 2019-03-28 13:54:56 : pyninjotiff.ninjotiff] Will generate single band product
[INFO: 2019-03-28 13:54:56 : pyninjotiff.ninjotiff] Creating output file '/tmp/testn.tif'
Traceback (most recent call last):
  File "mwe.py", line 9, in <module>
    ls.save_datasets(writer="ninjotiff", filename="/tmp/testn.tif")
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/scene.py", line 1181, in save_datasets
    return writer.save_datasets(datasets, compute=compute, **save_kwargs)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/writers/__init__.py", line 639, in save_datasets
    results.append(self.save_dataset(ds, compute=False, **kwargs))
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/writers/__init__.py", line 770, in save_dataset
    return self.save_image(img, filename=filename, compute=compute, fill_value=fill_value, **kwargs)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/writers/ninjotiff.py", line 53, in save_image
    nt.save(img, filename, **kwargs)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/pyninjotiff/ninjotiff.py", line 590, in save
    write(data, filename, area_def, ninjo_product_name, **kwargs)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/pyninjotiff/ninjotiff.py", line 700, in write
    _write(image_data, output_fn, write_rgb=write_rgb, **options)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/pyninjotiff/ninjotiff.py", line 846, in _write
    sat_id = int(kwargs.pop("sat_id"))
KeyError: 'sat_id'

@djhoese
Copy link
Member

djhoese commented Apr 2, 2019

@gerritholl I'm guessing this is bad documentation, but what if you pass sat_id as a keyword argument to the writer?

@gerritholl
Copy link
Member Author

Then I get KeyError: 'chan_id'. If I also pass chan_id, I get KeyError: 'data_source'. Then 'data_cat'. After several tries of passing a string to 'data_cat', where I have no clue what to pass either but where I do get an understandable error message if I pass something wrong (first character must be 'P' or 'G', second character must be 'O' or 'P', last 2 characters must be one of ['RN','RB','RA','BN','AN']), I try:

'''ls.save_datasets(writer="ninjotiff", filename="/tmp/testn.tif", sat_id=42, chan_id=0, data_source="unknown", data_cat="PORN")'''

which gives me the traceback

Traceback (most recent call last):
  File "mwe.py", line 10, in <module>
    ls.save_datasets(writer="ninjotiff", filename="/tmp/testn.tif", sat_id=42, chan_id=0, data_source="unknown", data_cat="PORN")
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/scene.py", line 1183, in save_datasets
    return writer.save_datasets(datasets, compute=compute, **save_kwargs)
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/writers/__init__.py", line 643, in save_datasets
    return compute_writer_results([results])
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/satpy/writers/__init__.py", line 492, in compute_writer_results
    delayeds.append(da.store(sources, targets, compute=False))
  File "/opt/pytroll/pytroll_inst/miniconda3/envs/pytroll_py27/lib/python2.7/site-packages/dask/array/core.py", line 669, in store
    % (len(sources), len(targets)))
ValueError: Different number of sources [0] and targets [3]

Which leads me to believe this issue may well be one of documentation, as all I tried to get PyTroll to write ninjotiff was to replace geotiff by ninjotiff in the Scene.save_datasets call — it may well be this is not expected to work at all. I could not found dedicated ninjotiff documentation on readthedocs, but I should have looked at the examples in the ninjotiff repo.

@gerritholl
Copy link
Member Author

The script works if I replace the last line by:

ls.save_dataset("IR_108", filename="/tmp/testn.tif", writer='ninjotiff', sat_id=6300014, chan_id=900015, data_cat='GORN', data_source='EUMCAST', physic_unit='K', nbits=8)

So ninjotiff does work, but I was calling it wrongly; it required certain keyword arguments, and apparently works with save_dataset but not with save_datasets (at least I did not find an example with save_datasets).

@djhoese
Copy link
Member

djhoese commented Apr 2, 2019

Given the keyword arguments needed that are per-dataset I don't think it would be possible to support save_datasets easily. We'll have to make sure it raises an exception.

@mraspaud
Copy link
Member

Ok, so we could fix the sat ID and probably the chan ID from the satpy metadata. Question is if we do it in the satpy writer, or in this package. @djhoese ?

@djhoese
Copy link
Member

djhoese commented Aug 23, 2019

I could see it being in either. Correct me if I'm wrong, but I think some organizations have different ID numbers (@goodsonr?), so having one "truth" may not work. We could have defaults that work for most people though.

I personally feel like the string -> ID number conversion could/should go here in pyninjotiff. If there needs to be another package (in the future?) to convert from "any name" -> "standard satellite name" -> "satellite ninjo ID" then we could do that too.

@goodsonr
Copy link
Contributor

goodsonr commented Aug 23, 2019

correct in that not all organizations use the same IDs. IDs for satellites/channels are contained in ninjo config files SatNames.properties and SatChannels.properties. When I was fooling around with making ninjo-tiffs I just had my own translation table to read-up the NinJo ID given the SatPy channel or product name (for non-wavelength products such as RGB or Level 2)

@mraspaud
Copy link
Member

Alright, so I think we will leave the automatic sat and chan ID out for now.

Regarding the save_dataset vs save_datasets issue, I believe this has to be solved in the satpy ninjotiff writter. PR coming soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants