cloudnetpy 1.58.0__py3-none-any.whl → 1.58.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -372,7 +372,10 @@ def _parse_spectrum(tokens: Iterator[str]) -> np.ndarray:
372
372
  return np.array(values, dtype="i2").reshape((32, 32))
373
373
 
374
374
 
375
- PARSERS: dict[str, Callable[[Iterator[str]], Any]] = {
375
+ ParserType = Callable[[Iterator[str]], Any]
376
+
377
+
378
+ PARSERS: dict[str, ParserType] = {
376
379
  "I_heating": _parse_float,
377
380
  "T_sensor": _parse_int,
378
381
  "_T_pcb": _parse_int,
@@ -401,6 +404,16 @@ PARSERS: dict[str, Callable[[Iterator[str]], Any]] = {
401
404
  "visibility": _parse_int,
402
405
  }
403
406
 
407
+ EMPTY_VALUES: dict[ParserType, Any] = {
408
+ _parse_int: 0,
409
+ _parse_float: 0.0,
410
+ _parse_date: datetime.date(2000, 1, 1),
411
+ _parse_time: datetime.time(12, 0, 0),
412
+ _parse_datetime: datetime.datetime(2000, 1, 1),
413
+ _parse_vector: np.zeros(32, dtype=float),
414
+ _parse_spectrum: np.zeros((32, 32), dtype="i2"),
415
+ }
416
+
404
417
 
405
418
  def _parse_headers(line: str) -> list[str]:
406
419
  return [CSV_HEADERS[header.strip()] for header in line.split(";")]
@@ -508,7 +521,7 @@ def _read_toa5(filename: str | PathLike) -> dict[str, list]:
508
521
  return data
509
522
 
510
523
 
511
- def _read_typ_op4a(lines: list[str]) -> dict[str, list]:
524
+ def _read_typ_op4a(lines: list[str]) -> dict[str, Any]:
512
525
  """Read output of "CS/PA" command. The output starts with line "TYP OP4A"
513
526
  followed by one line per measured variable in format: <number>:<value>.
514
527
  Output ends with characters: <ETX><CR><LF><NUL>. Lines are separated by
@@ -527,7 +540,7 @@ def _read_typ_op4a(lines: list[str]) -> dict[str, list]:
527
540
  continue
528
541
  parser = PARSERS.get(varname, next)
529
542
  tokens = value.split(";")
530
- data[varname] = [parser(iter(tokens))]
543
+ data[varname] = parser(iter(tokens))
531
544
  return data
532
545
 
533
546
 
@@ -538,15 +551,26 @@ def _read_fmi(content: str):
538
551
  - output of "CS/PA" command without non-printable characters at the end
539
552
  - "]\n"
540
553
  """
541
- output: dict[str, Any] = defaultdict(list)
554
+ output: dict[str, list] = {"_datetime": []}
542
555
  for m in re.finditer(
543
556
  r"\[(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+) "
544
557
  r"(?P<hour>\d+):(?P<minute>\d+):(?P<second>\d+)"
545
558
  r"(?P<output>[^\]]*)\]",
546
559
  content,
547
560
  ):
548
- for key, value in _read_typ_op4a(m["output"].splitlines()).items():
561
+ try:
562
+ record = _read_typ_op4a(m["output"].splitlines())
563
+ except ValueError:
564
+ continue
565
+
566
+ for key, value in record.items():
567
+ if key not in output:
568
+ output[key] = [None] * len(output["_datetime"])
549
569
  output[key].append(value)
570
+ for key in output:
571
+ if key not in record and key != "_datetime":
572
+ output[key].append(None)
573
+
550
574
  output["_datetime"].append(
551
575
  datetime.datetime(
552
576
  int(m["year"]),
@@ -577,6 +601,7 @@ def _read_parsivel(
577
601
  data = _read_toa5(filename)
578
602
  elif "TYP OP4A" in lines[0]:
579
603
  data = _read_typ_op4a(lines)
604
+ data = {key: [value] for key, value in data.items()}
580
605
  elif "Date" in lines[0]:
581
606
  headers = _parse_headers(lines[0])
582
607
  data = _read_rows(headers, lines[1:])
@@ -597,6 +622,17 @@ def _read_parsivel(
597
622
  combined_data[key].extend(values)
598
623
  if timestamps is not None:
599
624
  combined_data["_datetime"] = list(timestamps)
600
- result = {key: np.array(value) for key, value in combined_data.items()}
625
+ result = {}
626
+ for key, value in combined_data.items():
627
+ array = np.array(
628
+ [
629
+ x
630
+ if x is not None
631
+ else (EMPTY_VALUES[PARSERS[key]] if key in PARSERS else "")
632
+ for x in value
633
+ ]
634
+ )
635
+ mask = [np.full(array.shape[1:], x is None) for x in value]
636
+ result[key] = ma.array(array, mask=mask)
601
637
  result["time"] = result["_datetime"].astype("datetime64[s]")
602
638
  return result
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 58
3
- PATCH = 0
3
+ PATCH = 1
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudnetpy
3
- Version: 1.58.0
3
+ Version: 1.58.1
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -8,7 +8,7 @@ cloudnetpy/metadata.py,sha256=Bcu1a9UyUq61jomuZ0_6hYIOzf61e5qCXeiwLm46ikw,5040
8
8
  cloudnetpy/output.py,sha256=WoVTNuxni0DUr163vZ-_mDr1brXhY15XSlGMrq9Aoqw,14700
9
9
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  cloudnetpy/utils.py,sha256=0TlHm71YtSrKXBsRKctitnhQrvZPE-ulEVeAQW-oK58,27398
11
- cloudnetpy/version.py,sha256=XqM3W37Oj7sDo5sKL2WvA97PmZnS5J5o73R1isvo-0o,72
11
+ cloudnetpy/version.py,sha256=ACE_5AEhiiFIDukxdKYlkIvBmsdfhExmwRoHxF3tRPs,72
12
12
  cloudnetpy/categorize/__init__.py,sha256=gP5q3Vis1y9u9OWgA_idlbjfWXYN_S0IBSWdwBhL_uU,69
13
13
  cloudnetpy/categorize/atmos.py,sha256=fWW8ye_8HZASRAiYwURFKWzcGOYIA2RKeVxCq0lVOuM,12389
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=wndpwJxc2-QnNTkV8tc8I11Vs_WkNz9sVMX1fuGgUC4,3777
@@ -49,7 +49,7 @@ cloudnetpy/instruments/vaisala.py,sha256=E6PaK26lHprqOJUCEDZPZQu83Qan9n_THudTFQM
49
49
  cloudnetpy/instruments/weather_station.py,sha256=IMJHGXfMhb4jJw_i66oGDCkeeRn3_eko8zVehu6Fte0,5970
50
50
  cloudnetpy/instruments/disdrometer/__init__.py,sha256=lyjwttWvFvuwYxEkusoAvgRcbBmglmOp5HJOpXUqLWo,93
51
51
  cloudnetpy/instruments/disdrometer/common.py,sha256=TTsvWzhHg5tansTs47WB-7uuBRCZdjbFQMAyAQtFkSU,15636
52
- cloudnetpy/instruments/disdrometer/parsivel.py,sha256=myBHJw4VDPJErPlzAgwLoTjUQOGcvXdbvvy0MEjyGBc,21293
52
+ cloudnetpy/instruments/disdrometer/parsivel.py,sha256=TWq8VgG8U75AJQfCX-V2y8qy-nO6dKMOGd2eG8-u7to,22342
53
53
  cloudnetpy/instruments/disdrometer/thies.py,sha256=h7EwZ9tn47UUMiYqDQ68vkXv4q0rEqX1ZeFXd7XJYNg,5050
54
54
  cloudnetpy/model_evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  cloudnetpy/model_evaluation/file_handler.py,sha256=oUGIblcEWLLv16YKUch-M5KA-dGRAcuHa-9anP3xtX4,6447
@@ -107,8 +107,8 @@ cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe5
107
107
  cloudnetpy/products/mwr_tools.py,sha256=PRm5aCULccUehU-Byk55wYhhEHseMjoAjGBu5TSyHao,4621
108
108
  cloudnetpy/products/product_tools.py,sha256=rhx_Ru9FLlQqCNM-awoiHx18-Aq1eBwL9LiUaQoJs6k,10412
109
109
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
110
- cloudnetpy-1.58.0.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
111
- cloudnetpy-1.58.0.dist-info/METADATA,sha256=4nf1luVgeUXnmfw4rzTUg4HPFKNKgBR0HXckc_OG7b8,5733
112
- cloudnetpy-1.58.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
113
- cloudnetpy-1.58.0.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
114
- cloudnetpy-1.58.0.dist-info/RECORD,,
110
+ cloudnetpy-1.58.1.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
111
+ cloudnetpy-1.58.1.dist-info/METADATA,sha256=CqdJACjYG1_pszHVdzrrr6RZGJNO-YUvhSmrNEuBhz8,5733
112
+ cloudnetpy-1.58.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
113
+ cloudnetpy-1.58.1.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
114
+ cloudnetpy-1.58.1.dist-info/RECORD,,