muninn 7.0__tar.gz → 7.0.2__tar.gz

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.
Files changed (68) hide show
  1. {muninn-7.0 → muninn-7.0.2}/CHANGES +16 -0
  2. {muninn-7.0 → muninn-7.0.2}/PKG-INFO +2 -1
  3. {muninn-7.0 → muninn-7.0.2}/muninn/__init__.py +1 -1
  4. {muninn-7.0 → muninn-7.0.2}/muninn/archive.py +5 -2
  5. {muninn-7.0 → muninn-7.0.2}/muninn/geometry.py +10 -5
  6. {muninn-7.0 → muninn-7.0.2}/muninn/language.py +1 -1
  7. {muninn-7.0 → muninn-7.0.2}/muninn/tools/search.py +2 -2
  8. {muninn-7.0 → muninn-7.0.2}/muninn/tools/summary.py +1 -1
  9. {muninn-7.0 → muninn-7.0.2}/muninn/tools/sync.py +8 -7
  10. {muninn-7.0 → muninn-7.0.2}/muninn.egg-info/PKG-INFO +2 -1
  11. {muninn-7.0 → muninn-7.0.2}/setup.py +2 -1
  12. {muninn-7.0 → muninn-7.0.2}/test/test.py +1 -1
  13. {muninn-7.0 → muninn-7.0.2}/DEVELOPER.md +0 -0
  14. {muninn-7.0 → muninn-7.0.2}/LICENSE +0 -0
  15. {muninn-7.0 → muninn-7.0.2}/MANIFEST.in +0 -0
  16. {muninn-7.0 → muninn-7.0.2}/README.md +0 -0
  17. {muninn-7.0 → muninn-7.0.2}/muninn/_compat.py +0 -0
  18. {muninn-7.0 → muninn-7.0.2}/muninn/config.py +0 -0
  19. {muninn-7.0 → muninn-7.0.2}/muninn/core.py +0 -0
  20. {muninn-7.0 → muninn-7.0.2}/muninn/database/__init__.py +0 -0
  21. {muninn-7.0 → muninn-7.0.2}/muninn/database/base.py +0 -0
  22. {muninn-7.0 → muninn-7.0.2}/muninn/database/blobgeometry.py +0 -0
  23. {muninn-7.0 → muninn-7.0.2}/muninn/database/ewkb.py +0 -0
  24. {muninn-7.0 → muninn-7.0.2}/muninn/database/postgresql.py +0 -0
  25. {muninn-7.0 → muninn-7.0.2}/muninn/database/sql.py +0 -0
  26. {muninn-7.0 → muninn-7.0.2}/muninn/database/sqlite.py +0 -0
  27. {muninn-7.0 → muninn-7.0.2}/muninn/enum.py +0 -0
  28. {muninn-7.0 → muninn-7.0.2}/muninn/exceptions.py +0 -0
  29. {muninn-7.0 → muninn-7.0.2}/muninn/extension.py +0 -0
  30. {muninn-7.0 → muninn-7.0.2}/muninn/function.py +0 -0
  31. {muninn-7.0 → muninn-7.0.2}/muninn/remote.py +0 -0
  32. {muninn-7.0 → muninn-7.0.2}/muninn/schema.py +0 -0
  33. {muninn-7.0 → muninn-7.0.2}/muninn/storage/__init__.py +0 -0
  34. {muninn-7.0 → muninn-7.0.2}/muninn/storage/base.py +0 -0
  35. {muninn-7.0 → muninn-7.0.2}/muninn/storage/fs.py +0 -0
  36. {muninn-7.0 → muninn-7.0.2}/muninn/storage/s3.py +0 -0
  37. {muninn-7.0 → muninn-7.0.2}/muninn/storage/swift.py +0 -0
  38. {muninn-7.0 → muninn-7.0.2}/muninn/struct.py +0 -0
  39. {muninn-7.0 → muninn-7.0.2}/muninn/tools/__init__.py +0 -0
  40. {muninn-7.0 → muninn-7.0.2}/muninn/tools/attach.py +0 -0
  41. {muninn-7.0 → muninn-7.0.2}/muninn/tools/destroy.py +0 -0
  42. {muninn-7.0 → muninn-7.0.2}/muninn/tools/export.py +0 -0
  43. {muninn-7.0 → muninn-7.0.2}/muninn/tools/hash.py +0 -0
  44. {muninn-7.0 → muninn-7.0.2}/muninn/tools/info.py +0 -0
  45. {muninn-7.0 → muninn-7.0.2}/muninn/tools/ingest.py +0 -0
  46. {muninn-7.0 → muninn-7.0.2}/muninn/tools/list_tags.py +0 -0
  47. {muninn-7.0 → muninn-7.0.2}/muninn/tools/prepare.py +0 -0
  48. {muninn-7.0 → muninn-7.0.2}/muninn/tools/pull.py +0 -0
  49. {muninn-7.0 → muninn-7.0.2}/muninn/tools/remove.py +0 -0
  50. {muninn-7.0 → muninn-7.0.2}/muninn/tools/retrieve.py +0 -0
  51. {muninn-7.0 → muninn-7.0.2}/muninn/tools/strip.py +0 -0
  52. {muninn-7.0 → muninn-7.0.2}/muninn/tools/tag.py +0 -0
  53. {muninn-7.0 → muninn-7.0.2}/muninn/tools/untag.py +0 -0
  54. {muninn-7.0 → muninn-7.0.2}/muninn/tools/update.py +0 -0
  55. {muninn-7.0 → muninn-7.0.2}/muninn/tools/utils.py +0 -0
  56. {muninn-7.0 → muninn-7.0.2}/muninn/util.py +0 -0
  57. {muninn-7.0 → muninn-7.0.2}/muninn/visitor.py +0 -0
  58. {muninn-7.0 → muninn-7.0.2}/muninn.egg-info/SOURCES.txt +0 -0
  59. {muninn-7.0 → muninn-7.0.2}/muninn.egg-info/dependency_links.txt +0 -0
  60. {muninn-7.0 → muninn-7.0.2}/muninn.egg-info/entry_points.txt +0 -0
  61. {muninn-7.0 → muninn-7.0.2}/muninn.egg-info/top_level.txt +0 -0
  62. {muninn-7.0 → muninn-7.0.2}/setup.cfg +0 -0
  63. {muninn-7.0 → muninn-7.0.2}/test/coverage.sh +0 -0
  64. {muninn-7.0 → muninn-7.0.2}/test/data/README +0 -0
  65. {muninn-7.0 → muninn-7.0.2}/test/data/multi/1.txt +0 -0
  66. {muninn-7.0 → muninn-7.0.2}/test/data/multi/2.txt +0 -0
  67. {muninn-7.0 → muninn-7.0.2}/test/data/pi.txt +0 -0
  68. {muninn-7.0 → muninn-7.0.2}/test/product_type.py.template +0 -0
@@ -1,3 +1,19 @@
1
+ 7.0.2 2025-10-10
2
+ ~~~~~~~~~~~~~~~~
3
+
4
+ * Fixed issue where a Geometry Linearring could not be closed or had a
5
+ duplicate closing point.
6
+
7
+ 7.0.1 2025-08-25
8
+ ~~~~~~~~~~~~~~~~
9
+
10
+ * Fixed incorrect unit of sizes >= Petabyte for the -H command line option.
11
+
12
+ * 'muninn-search --path' now shows the content of remote_url if a product
13
+ is not in the archive. A leading file:// in the remote_url is then omitted.
14
+
15
+ * Allow muninn-sync start/end arguments to be a date+time argument.
16
+
1
17
  7.0 2025-08-14
2
18
  ~~~~~~~~~~~~~~
3
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.2
2
2
  Name: muninn
3
- Version: 7.0
3
+ Version: 7.0.2
4
4
  Summary: Data product catalogue and archive system
5
5
  Home-page: https://github.com/stcorp/muninn
6
6
  Author: S[&]T
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
22
23
  Classifier: License :: OSI Approved :: BSD License
23
24
  Classifier: Operating System :: OS Independent
24
25
  Classifier: Topic :: Scientific/Engineering
@@ -4,7 +4,7 @@
4
4
 
5
5
  from __future__ import absolute_import, division, print_function
6
6
 
7
- __version__ = "7.0.0"
7
+ __version__ = "7.0.2"
8
8
  __copyright__ = "Copyright (C) 2014-2025 S[&]T, The Netherlands."
9
9
 
10
10
  __all__ = ["Error", "InternalError", "Struct", "Archive", "open", "config_path"]
@@ -96,7 +96,7 @@ def _load_synchronizer_module(name):
96
96
  try:
97
97
  __import__(name)
98
98
  except ImportError as e:
99
- raise Error("import of syncrhonizer %r failed (%s)" % (name, e))
99
+ raise Error("import of synchronizer %r failed (%s)" % (name, e))
100
100
 
101
101
  return sys.modules[name]
102
102
 
@@ -1314,8 +1314,11 @@ class Archive(object):
1314
1314
  if archive_path is not None and self._storage is not None:
1315
1315
  product_path = self._product_path(product)
1316
1316
  return os.path.join(self._storage.global_prefix, product_path)
1317
- elif remote_url is not None:
1317
+ if remote_url is not None:
1318
+ if remote_url.startswith('file://'):
1319
+ return remote_url[7:]
1318
1320
  return remote_url
1321
+ return None
1319
1322
 
1320
1323
  def pull(self, where="", parameters={}, verify_hash=False, verify_hash_download=False):
1321
1324
  """Pull one or more remote products into the archive.
@@ -284,10 +284,15 @@ class LineString(GeometrySequence):
284
284
 
285
285
  class LinearRing(GeometrySequence):
286
286
  def __init__(self, geometries=[]):
287
+ geometries = list(geometries)
288
+ if len(geometries) > 1 and geometries[0] != geometries[-1]:
289
+ # close the ring
290
+ geometries.append(geometries[0])
291
+
287
292
  super(LinearRing, self).__init__(geometries)
288
293
 
289
- if self and len(self) < 3:
290
- raise ValueError("linear ring should be empty or should contain >= 3 points")
294
+ if self and len(self) < 4:
295
+ raise ValueError("linear ring should be empty or should contain >= 4 points")
291
296
 
292
297
  def point(self, index):
293
298
  return self[index]
@@ -296,8 +301,7 @@ class LinearRing(GeometrySequence):
296
301
  if not self:
297
302
  wkt = "EMPTY"
298
303
  else:
299
- wkt = "(%s, %f %f)" % (", ".join(["%f %f" % (point.x, point.y) for point in self]), self.point(0).x,
300
- self.point(0).y)
304
+ wkt = "(" + ", ".join(["%f %f" % (point.x, point.y) for point in self]) + ")"
301
305
  return "LINESTRING " + wkt if tagged else wkt
302
306
 
303
307
  def __repr__(self):
@@ -421,7 +425,8 @@ class Polygon(GeometrySequence):
421
425
  del crossing_lat[min_index]
422
426
  for pts in pts_set:
423
427
  # close ring
424
- pts.append(pts[0])
428
+ if pts[0] != pts[-1]:
429
+ pts.append(pts[0])
425
430
  if len(pts_set) == 1:
426
431
  return Polygon([LinearRing(pts)])
427
432
  else:
@@ -485,7 +485,7 @@ def parse_linear_ring(stream):
485
485
  if points[-1] != points[0]:
486
486
  raise Error("char %d: linear ring should be closed" % stream.token_start_position)
487
487
 
488
- return geometry.LinearRing(points[:-1])
488
+ return geometry.LinearRing(points)
489
489
 
490
490
 
491
491
  def parse_polygon(stream):
@@ -121,12 +121,12 @@ def uuid(args):
121
121
  def paths(args):
122
122
  with muninn.open(args.archive) as archive:
123
123
  # Collect possibly multiple sort order specifier lists into a single list.
124
- order_by_default = ['+core.archive_path', '+core.physical_name']
124
+ order_by_default = ['+core.archive_path', '+core.physical_name', '+core.remote_url']
125
125
  order_by = order_by_default if not args.order_by else sum(args.order_by, []) + order_by_default
126
126
 
127
127
  # Find products using the search expression and print the paths of the products found.
128
128
  products = archive.search(args.expression, order_by, args.limit,
129
- property_names=['archive_path', 'physical_name'])
129
+ property_names=['archive_path', 'physical_name', 'remote_url'])
130
130
  for product in products:
131
131
  product_path = archive.product_path(product)
132
132
  if product_path is not None:
@@ -34,7 +34,7 @@ def ceil(size):
34
34
  return integer_size + 1 if size > integer_size else integer_size
35
35
 
36
36
 
37
- def human_readable_size(size, base=1024, powers=["Bi", "Ki", "Mi", "Gi", "Ti", "Ei"]):
37
+ def human_readable_size(size, base=1024, powers=["Bi", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]):
38
38
  if len(powers) == 0:
39
39
  return str(size)
40
40
 
@@ -5,19 +5,20 @@
5
5
  from __future__ import absolute_import, division, print_function
6
6
 
7
7
  import argparse
8
- from datetime import datetime
8
+ import datetime
9
9
 
10
10
  import muninn
11
11
 
12
12
  from muninn.tools.utils import create_parser, parse_args_and_run
13
13
 
14
14
 
15
- def valid_date(date: str) -> datetime:
16
- date_fmt = '%Y-%m-%d'
17
- try:
18
- return datetime.strptime(date, date_fmt)
19
- except ValueError:
20
- raise argparse.ArgumentTypeError(f"invalid date: {date} (expected '{date_fmt}')")
15
+ def valid_date(arg: str) -> datetime:
16
+ for format_string in ("%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S.%f"):
17
+ try:
18
+ return datetime.datetime.strptime(arg, format_string)
19
+ except ValueError:
20
+ pass
21
+ raise argparse.ArgumentTypeError(f"invalid datetime: {arg} (expected 'YYYY-MM-DD(THH:MM:SS(.ffffff))')")
21
22
 
22
23
 
23
24
  def run(args):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.2
2
2
  Name: muninn
3
- Version: 7.0
3
+ Version: 7.0.2
4
4
  Summary: Data product catalogue and archive system
5
5
  Home-page: https://github.com/stcorp/muninn
6
6
  Author: S[&]T
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
22
23
  Classifier: License :: OSI Approved :: BSD License
23
24
  Classifier: Operating System :: OS Independent
24
25
  Classifier: Topic :: Scientific/Engineering
@@ -15,7 +15,7 @@ requirements = []
15
15
 
16
16
  setup(
17
17
  name="muninn",
18
- version="7.0",
18
+ version="7.0.2",
19
19
  description="Data product catalogue and archive system",
20
20
  url="https://github.com/stcorp/muninn",
21
21
  author="S[&]T",
@@ -54,6 +54,7 @@ setup(
54
54
  "Programming Language :: Python :: 3.11",
55
55
  "Programming Language :: Python :: 3.12",
56
56
  "Programming Language :: Python :: 3.13",
57
+ "Programming Language :: Python :: 3.14",
57
58
  "License :: OSI Approved :: BSD License",
58
59
  "Operating System :: OS Independent",
59
60
  "Topic :: Scientific/Engineering",
@@ -1370,7 +1370,7 @@ class TestArchivePureCatalogue: # TODO merge with TestArchive?
1370
1370
  assert properties.core.remote_url == 'file://' + os.path.realpath('data/a.txt').replace('\\', '/')
1371
1371
  assert len(archive_pure.search()) == 1
1372
1372
 
1373
- assert archive_pure.product_path(properties).startswith('file://')
1373
+ assert archive_pure.product_path(properties).startswith('/')
1374
1374
 
1375
1375
  def test_remove(self, archive_pure):
1376
1376
  properties = archive_pure.ingest(
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes