lsst-resources 29.2025.4300__tar.gz → 29.2025.4400__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.
- {lsst_resources-29.2025.4300/python/lsst_resources.egg-info → lsst_resources-29.2025.4400}/PKG-INFO +3 -3
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/pyproject.toml +3 -3
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/_resourceHandles/_davResourceHandle.py +7 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/_resourcePath.py +17 -2
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/davutils.py +163 -88
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/file.py +1 -1
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/http.py +2 -2
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/schemeless.py +6 -3
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/tests.py +14 -0
- lsst_resources-29.2025.4400/python/lsst/resources/version.py +2 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400/python/lsst_resources.egg-info}/PKG-INFO +3 -3
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_schemeless.py +11 -0
- lsst_resources-29.2025.4300/python/lsst/resources/version.py +0 -2
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/COPYRIGHT +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/LICENSE +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/MANIFEST.in +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/README.md +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/doc/lsst.resources/CHANGES.rst +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/doc/lsst.resources/dav.rst +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/doc/lsst.resources/index.rst +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/doc/lsst.resources/internal-api.rst +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/doc/lsst.resources/s3.rst +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/__init__.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/__init__.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/_resourceHandles/__init__.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/_resourceHandles/_baseResourceHandle.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/_resourceHandles/_fileResourceHandle.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/_resourceHandles/_httpResourceHandle.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/_resourceHandles/_s3ResourceHandle.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/dav.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/gs.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/location.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/mem.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/packageresource.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/py.typed +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/s3.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/s3utils.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/utils.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst_resources.egg-info/SOURCES.txt +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst_resources.egg-info/dependency_links.txt +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst_resources.egg-info/requires.txt +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst_resources.egg-info/top_level.txt +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst_resources.egg-info/zip-safe +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/setup.cfg +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_dav.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_file.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_gs.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_http.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_location.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_mem.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_resource.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_s3.py +0 -0
- {lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/tests/test_s3utils.py +0 -0
{lsst_resources-29.2025.4300/python/lsst_resources.egg-info → lsst_resources-29.2025.4400}/PKG-INFO
RENAMED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-resources
|
|
3
|
-
Version: 29.2025.
|
|
3
|
+
Version: 29.2025.4400
|
|
4
4
|
Summary: An abstraction layer for reading and writing from URI file resources.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
|
-
License: BSD
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
7
|
Project-URL: Homepage, https://github.com/lsst/resources
|
|
8
8
|
Keywords: lsst
|
|
9
9
|
Classifier: Intended Audience :: Developers
|
|
10
|
-
Classifier: License :: OSI Approved :: BSD License
|
|
11
10
|
Classifier: Operating System :: OS Independent
|
|
12
11
|
Classifier: Programming Language :: Python :: 3
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Requires-Python: >=3.11.0
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: COPYRIGHT
|
|
@@ -5,18 +5,19 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "lsst-resources"
|
|
7
7
|
description = "An abstraction layer for reading and writing from URI file resources."
|
|
8
|
-
license =
|
|
8
|
+
license = "BSD-3-Clause"
|
|
9
|
+
license-files = ["COPYRIGHT", "LICENSE"]
|
|
9
10
|
readme = "README.md"
|
|
10
11
|
authors = [
|
|
11
12
|
{name="Rubin Observatory Data Management", email="dm-admin@lists.lsst.org"},
|
|
12
13
|
]
|
|
13
14
|
classifiers = [
|
|
14
15
|
"Intended Audience :: Developers",
|
|
15
|
-
"License :: OSI Approved :: BSD License",
|
|
16
16
|
"Operating System :: OS Independent",
|
|
17
17
|
"Programming Language :: Python :: 3",
|
|
18
18
|
"Programming Language :: Python :: 3.11",
|
|
19
19
|
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
20
21
|
]
|
|
21
22
|
keywords = ["lsst"]
|
|
22
23
|
dependencies = [
|
|
@@ -53,7 +54,6 @@ where = ["python"]
|
|
|
53
54
|
|
|
54
55
|
[tool.setuptools]
|
|
55
56
|
zip-safe = true
|
|
56
|
-
license-files = ["COPYRIGHT", "LICENSE"]
|
|
57
57
|
|
|
58
58
|
[tool.setuptools.package-data]
|
|
59
59
|
"lsst.resources" = ["py.typed"]
|
|
@@ -36,6 +36,8 @@ class DavReadResourceHandle(BaseResourceHandle[bytes]):
|
|
|
36
36
|
Logger to used when writing messages.
|
|
37
37
|
uri : `lsst.resources.dav.DavResourcePath`
|
|
38
38
|
URI of remote resource.
|
|
39
|
+
stat : `DavFileMetadata`
|
|
40
|
+
Information about this resource.
|
|
39
41
|
newline : `str` or `None`, optional
|
|
40
42
|
When doing multiline operations, break the stream on given character.
|
|
41
43
|
Defaults to newline. If a file is opened in binary mode, this argument
|
|
@@ -181,6 +183,11 @@ class DavReadResourceHandle(BaseResourceHandle[bytes]):
|
|
|
181
183
|
def readinto(self, output: bytearray) -> int:
|
|
182
184
|
"""Read up to `len(output)` bytes into `output` and return the number
|
|
183
185
|
of bytes read.
|
|
186
|
+
|
|
187
|
+
Parameters
|
|
188
|
+
----------
|
|
189
|
+
output : `bytearray`
|
|
190
|
+
Byte array to write output into.
|
|
184
191
|
"""
|
|
185
192
|
if self._eof or len(output) == 0:
|
|
186
193
|
return 0
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/_resourcePath.py
RENAMED
|
@@ -22,6 +22,7 @@ import logging
|
|
|
22
22
|
import os
|
|
23
23
|
import posixpath
|
|
24
24
|
import re
|
|
25
|
+
import sys
|
|
25
26
|
import urllib.parse
|
|
26
27
|
from collections import defaultdict
|
|
27
28
|
from pathlib import Path, PurePath, PurePosixPath
|
|
@@ -870,7 +871,7 @@ class ResourcePath: # numpydoc ignore=PR02
|
|
|
870
871
|
params=path_uri.params,
|
|
871
872
|
)
|
|
872
873
|
|
|
873
|
-
def relative_to(self, other: ResourcePath) -> str | None:
|
|
874
|
+
def relative_to(self, other: ResourcePath, walk_up: bool = False) -> str | None:
|
|
874
875
|
"""Return the relative path from this URI to the other URI.
|
|
875
876
|
|
|
876
877
|
Parameters
|
|
@@ -878,6 +879,9 @@ class ResourcePath: # numpydoc ignore=PR02
|
|
|
878
879
|
other : `ResourcePath`
|
|
879
880
|
URI to use to calculate the relative path. Must be a parent
|
|
880
881
|
of this URI.
|
|
882
|
+
walk_up : `bool`, optional
|
|
883
|
+
Control whether "``..``" can be used to resolve a relative path.
|
|
884
|
+
Default is `False`. Can not be `True` on Python version 3.11.
|
|
881
885
|
|
|
882
886
|
Returns
|
|
883
887
|
-------
|
|
@@ -896,11 +900,22 @@ class ResourcePath: # numpydoc ignore=PR02
|
|
|
896
900
|
if not {self.netloc, other.netloc}.issubset(local_netlocs):
|
|
897
901
|
return None
|
|
898
902
|
|
|
903
|
+
# Rather than trying to guess a failure reason from the TypeError
|
|
904
|
+
# explicitly check for python 3.11. Doing this will simplify the
|
|
905
|
+
# rediscovery of a useless python version check when we set a new
|
|
906
|
+
# minimum version.
|
|
907
|
+
kwargs = {}
|
|
908
|
+
if walk_up:
|
|
909
|
+
if sys.version_info < (3, 12, 0):
|
|
910
|
+
raise TypeError("walk_up parameter can not be true in python 3.11 and older")
|
|
911
|
+
|
|
912
|
+
kwargs["walk_up"] = True
|
|
913
|
+
|
|
899
914
|
enclosed_path = self._pathLib(self.relativeToPathRoot)
|
|
900
915
|
parent_path = other.relativeToPathRoot
|
|
901
916
|
subpath: str | None
|
|
902
917
|
try:
|
|
903
|
-
subpath = str(enclosed_path.relative_to(parent_path))
|
|
918
|
+
subpath = str(enclosed_path.relative_to(parent_path, **kwargs))
|
|
904
919
|
except ValueError:
|
|
905
920
|
subpath = None
|
|
906
921
|
else:
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/davutils.py
RENAMED
|
@@ -58,12 +58,12 @@ def normalize_path(path: str | None) -> str:
|
|
|
58
58
|
Parameters
|
|
59
59
|
----------
|
|
60
60
|
path : `str`, optional
|
|
61
|
-
Path to normalize
|
|
61
|
+
Path to normalize (e.g., '/path/to/..///normalize/').
|
|
62
62
|
|
|
63
63
|
Returns
|
|
64
64
|
-------
|
|
65
65
|
url : `str`
|
|
66
|
-
Normalized URL
|
|
66
|
+
Normalized URL (e.g., '/path/normalize').
|
|
67
67
|
"""
|
|
68
68
|
return "/" if not path else "/" + posixpath.normpath(path).lstrip("/")
|
|
69
69
|
|
|
@@ -75,20 +75,18 @@ def normalize_url(url: str, preserve_scheme: bool = False, preserve_path: bool =
|
|
|
75
75
|
Parameters
|
|
76
76
|
----------
|
|
77
77
|
url : `str`
|
|
78
|
-
URL to normalize
|
|
79
|
-
|
|
78
|
+
URL to normalize (e.g., 'davs://example.org:1234///path/to//../dir/').
|
|
80
79
|
preserve_scheme : `bool`
|
|
81
80
|
If True the scheme of `url` will be preserved. Otherwise the scheme
|
|
82
81
|
of the returned normalized URL will be 'http' or 'https'.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if True, the path of `url` will be preserved in the returned
|
|
82
|
+
preserve_path : `bool`
|
|
83
|
+
If True, the path of `url` will be preserved in the returned
|
|
86
84
|
normalized URL, otherwise, the returned URL will have '/' as path.
|
|
87
85
|
|
|
88
86
|
Returns
|
|
89
87
|
-------
|
|
90
88
|
url : `str`
|
|
91
|
-
Normalized URL
|
|
89
|
+
Normalized URL (e.g. 'https://example.org:1234/path/dir').
|
|
92
90
|
"""
|
|
93
91
|
parsed = parse_url(url)
|
|
94
92
|
if parsed.scheme is None:
|
|
@@ -324,7 +322,7 @@ class DavConfigPool:
|
|
|
324
322
|
|
|
325
323
|
Parameters
|
|
326
324
|
----------
|
|
327
|
-
|
|
325
|
+
filename : `list` [ `str` ]
|
|
328
326
|
List of environment variables or file names to load the configuration
|
|
329
327
|
from. The first file found in the list will be read and the
|
|
330
328
|
configuration settings for all webDAV endpoints will be extracted
|
|
@@ -416,7 +414,12 @@ class DavConfigPool:
|
|
|
416
414
|
|
|
417
415
|
def get_config_for_url(self, url: str) -> DavConfig:
|
|
418
416
|
"""Return the configuration to use a webDAV client when interacting
|
|
419
|
-
|
|
417
|
+
with the server which hosts the resource at `url`.
|
|
418
|
+
|
|
419
|
+
Parameters
|
|
420
|
+
----------
|
|
421
|
+
url : `str`
|
|
422
|
+
URL for which to obtain a configuration.
|
|
420
423
|
"""
|
|
421
424
|
# Select the configuration for the endpoint of the provided URL.
|
|
422
425
|
normalized_url: str = normalize_url(url, preserve_path=False)
|
|
@@ -446,7 +449,7 @@ def make_retry(config: DavConfig) -> Retry:
|
|
|
446
449
|
Returns
|
|
447
450
|
-------
|
|
448
451
|
retry : `urllib3.util.Retry`
|
|
449
|
-
|
|
452
|
+
Retry object to he used when creating a ``urllib3.PoolManager``.
|
|
450
453
|
"""
|
|
451
454
|
backoff_min: float = config.retry_backoff_min
|
|
452
455
|
backoff_max: float = config.retry_backoff_max
|
|
@@ -534,6 +537,13 @@ class DavClientPool:
|
|
|
534
537
|
"""Return a client for interacting with the endpoint where `url`
|
|
535
538
|
is hosted.
|
|
536
539
|
|
|
540
|
+
Parameters
|
|
541
|
+
----------
|
|
542
|
+
url : `str`
|
|
543
|
+
URL for which to obtain a client.
|
|
544
|
+
|
|
545
|
+
Notes
|
|
546
|
+
-----
|
|
537
547
|
The returned client is thread-safe. If a client for that endpoint
|
|
538
548
|
already exists it is reused, otherwise a new client is created
|
|
539
549
|
with the appropriate configuration for interacting with the storage
|
|
@@ -600,10 +610,13 @@ class DavClient:
|
|
|
600
610
|
Parameters
|
|
601
611
|
----------
|
|
602
612
|
url : `str`
|
|
603
|
-
Root URL of the storage endpoint (e.g.
|
|
604
|
-
|
|
613
|
+
Root URL of the storage endpoint (e.g.
|
|
614
|
+
"https://host.example.org:1234/").
|
|
605
615
|
config : `DavConfig`
|
|
606
616
|
Configuration to initialize this client.
|
|
617
|
+
accepts_ranges : `bool` | `None`
|
|
618
|
+
Indicate whether the remote server accepts the ``Range`` header in GET
|
|
619
|
+
requests.
|
|
607
620
|
"""
|
|
608
621
|
|
|
609
622
|
def __init__(self, url: str, config: DavConfig, accepts_ranges: bool | None = None) -> None:
|
|
@@ -721,9 +734,14 @@ class DavClient:
|
|
|
721
734
|
|
|
722
735
|
def get_server_details(self, url: str) -> dict[str, str]:
|
|
723
736
|
"""
|
|
724
|
-
Retrieve the details of the server and check it
|
|
737
|
+
Retrieve the details of the server and check it advertises compliance
|
|
725
738
|
to class 1 of webDAV protocol.
|
|
726
739
|
|
|
740
|
+
Parameters
|
|
741
|
+
----------
|
|
742
|
+
url : `str`
|
|
743
|
+
URL to check.
|
|
744
|
+
|
|
727
745
|
Returns
|
|
728
746
|
-------
|
|
729
747
|
details: `dic[str, str]`
|
|
@@ -807,17 +825,17 @@ class DavClient:
|
|
|
807
825
|
Target URL.
|
|
808
826
|
headers : `dict[str, str]`, optional
|
|
809
827
|
Headers to sent with the request.
|
|
810
|
-
body: `bytes` or `str` or `None`, optional
|
|
828
|
+
body : `bytes` or `str` or `None`, optional
|
|
811
829
|
Request body.
|
|
812
|
-
pool_manager: `PoolManager`, optional
|
|
830
|
+
pool_manager : `PoolManager`, optional
|
|
813
831
|
Pool manager to use to send the request. By default, the requests
|
|
814
832
|
are sent to the frontend servers.
|
|
815
|
-
preload_content: `bool`, optional
|
|
833
|
+
preload_content : `bool`, optional
|
|
816
834
|
If True, the response body is downloaded and can be retrieved
|
|
817
835
|
via the returned response `.data` property. If False, the
|
|
818
836
|
caller needs to call `.read()` on the returned response object to
|
|
819
837
|
download the body, either entirely in one call or by chunks.
|
|
820
|
-
redirect: `bool`, optional
|
|
838
|
+
redirect : `bool`, optional
|
|
821
839
|
If True, automatically handle redirects. If False, the returned
|
|
822
840
|
response may contain a redirection to another location.
|
|
823
841
|
|
|
@@ -871,7 +889,7 @@ class DavClient:
|
|
|
871
889
|
Target URL.
|
|
872
890
|
headers : `dict[str, str]`, optional
|
|
873
891
|
Headers to sent with the request.
|
|
874
|
-
preload_content: `bool`, optional
|
|
892
|
+
preload_content : `bool`, optional
|
|
875
893
|
If True, the response body is downloaded and can be retrieved
|
|
876
894
|
via the returned response `.data` property. If False, the
|
|
877
895
|
caller needs to call the `.read()` on the returned response
|
|
@@ -934,7 +952,7 @@ class DavClient:
|
|
|
934
952
|
----------
|
|
935
953
|
url : `str`
|
|
936
954
|
Target URL.
|
|
937
|
-
data: `BinaryIO` or `bytes`
|
|
955
|
+
data : `BinaryIO` or `bytes`
|
|
938
956
|
Request body.
|
|
939
957
|
"""
|
|
940
958
|
# Send a PUT request with empty body and handle redirection. This
|
|
@@ -1000,8 +1018,7 @@ class DavClient:
|
|
|
1000
1018
|
----------
|
|
1001
1019
|
url : `str`
|
|
1002
1020
|
Target URL.
|
|
1003
|
-
|
|
1004
|
-
raise_if_not_found: `bool``
|
|
1021
|
+
headers : `bool``
|
|
1005
1022
|
If the target URL is not found, raise an exception. Otherwise
|
|
1006
1023
|
just return the response.
|
|
1007
1024
|
"""
|
|
@@ -1063,9 +1080,9 @@ class DavClient:
|
|
|
1063
1080
|
Returns
|
|
1064
1081
|
-------
|
|
1065
1082
|
result: `DavResourceMetadata``
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1083
|
+
Details of the resources at `url`. If no resource was found at
|
|
1084
|
+
that URL no exception is raised. Instead the returned details allow
|
|
1085
|
+
for detecting that the resource does not exist.
|
|
1069
1086
|
"""
|
|
1070
1087
|
resp = self._propfind(url)
|
|
1071
1088
|
match resp.status:
|
|
@@ -1095,43 +1112,48 @@ class DavClient:
|
|
|
1095
1112
|
Returns
|
|
1096
1113
|
-------
|
|
1097
1114
|
result: `dict``
|
|
1098
|
-
|
|
1099
1115
|
For an existing file, the returned value has the form:
|
|
1100
1116
|
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
"
|
|
1117
|
+
.. code-block:: json
|
|
1118
|
+
|
|
1119
|
+
{
|
|
1120
|
+
"name": name,
|
|
1121
|
+
"size": 1234,
|
|
1122
|
+
"type": "file",
|
|
1123
|
+
"last_modified":
|
|
1124
|
+
datetime.datetime(2025, 4, 10, 15, 12, 51, 227854),
|
|
1125
|
+
"checksums": {
|
|
1126
|
+
"adler32": "0fc5f83f",
|
|
1127
|
+
"md5": "1f57339acdec099c6c0a41f8e3d5fcd0",
|
|
1128
|
+
}
|
|
1110
1129
|
}
|
|
1111
|
-
}
|
|
1112
1130
|
|
|
1113
1131
|
For an existing directory, the returned value has the form:
|
|
1114
1132
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1133
|
+
.. code-block:: json
|
|
1134
|
+
|
|
1135
|
+
{
|
|
1136
|
+
"name": name,
|
|
1137
|
+
"size": 0,
|
|
1138
|
+
"type": "directory",
|
|
1139
|
+
"last_modified":
|
|
1140
|
+
datetime.datetime(2025, 4, 10, 15, 12, 51, 227854),
|
|
1141
|
+
"checksums": {},
|
|
1142
|
+
}
|
|
1123
1143
|
|
|
1124
|
-
For
|
|
1144
|
+
For a non-existing file or directory, the returned value has the
|
|
1125
1145
|
form:
|
|
1126
1146
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1147
|
+
.. code-block:: json
|
|
1148
|
+
|
|
1149
|
+
{
|
|
1150
|
+
"name": name,
|
|
1151
|
+
"size": None,
|
|
1152
|
+
"type": None,
|
|
1153
|
+
"last_modified":
|
|
1132
1154
|
datetime.datetime(1, 1, 1, 0, 0),
|
|
1133
|
-
|
|
1134
|
-
|
|
1155
|
+
"checksums": {},
|
|
1156
|
+
}
|
|
1135
1157
|
|
|
1136
1158
|
Notes
|
|
1137
1159
|
-----
|
|
@@ -1234,12 +1256,11 @@ class DavClient:
|
|
|
1234
1256
|
----------
|
|
1235
1257
|
url : `str`
|
|
1236
1258
|
Target URL.
|
|
1237
|
-
|
|
1238
|
-
start: `int`
|
|
1259
|
+
start : `int`
|
|
1239
1260
|
Starting byte offset of the range to download.
|
|
1240
|
-
end: `int`
|
|
1261
|
+
end : `int`
|
|
1241
1262
|
Ending byte offset of the range to download.
|
|
1242
|
-
headers: `dict[str,str]`, optional
|
|
1263
|
+
headers : `dict[str,str]`, optional
|
|
1243
1264
|
Specific headers to sent with the GET request.
|
|
1244
1265
|
|
|
1245
1266
|
Returns
|
|
@@ -1268,13 +1289,13 @@ class DavClient:
|
|
|
1268
1289
|
----------
|
|
1269
1290
|
url : `str`
|
|
1270
1291
|
Target URL.
|
|
1271
|
-
|
|
1272
|
-
filename: `str`
|
|
1292
|
+
filename : `str`
|
|
1273
1293
|
Local file to write the content to. If the file already exists,
|
|
1274
1294
|
it will be rewritten.
|
|
1275
|
-
|
|
1276
|
-
chunk_size: `int`
|
|
1295
|
+
chunk_size : `int`
|
|
1277
1296
|
Size of the chunks to write to `filename`.
|
|
1297
|
+
close_connection : `bool`
|
|
1298
|
+
Whether to close the connection after download.
|
|
1278
1299
|
|
|
1279
1300
|
Returns
|
|
1280
1301
|
-------
|
|
@@ -1330,8 +1351,7 @@ class DavClient:
|
|
|
1330
1351
|
----------
|
|
1331
1352
|
url : `str`
|
|
1332
1353
|
Target URL.
|
|
1333
|
-
|
|
1334
|
-
data: `bytes`
|
|
1354
|
+
data : `bytes`
|
|
1335
1355
|
Sequence of bytes to upload.
|
|
1336
1356
|
|
|
1337
1357
|
Notes
|
|
@@ -1350,7 +1370,7 @@ class DavClient:
|
|
|
1350
1370
|
Parameters
|
|
1351
1371
|
----------
|
|
1352
1372
|
url : `str`
|
|
1353
|
-
Target URL
|
|
1373
|
+
Target URL.
|
|
1354
1374
|
|
|
1355
1375
|
Returns
|
|
1356
1376
|
-------
|
|
@@ -1412,6 +1432,11 @@ class DavClient:
|
|
|
1412
1432
|
def accepts_ranges(self, url: str) -> bool:
|
|
1413
1433
|
"""Return `True` if the server supports a 'Range' header in
|
|
1414
1434
|
GET requests against `url`.
|
|
1435
|
+
|
|
1436
|
+
Parameters
|
|
1437
|
+
----------
|
|
1438
|
+
url : `str`
|
|
1439
|
+
Target URL.
|
|
1415
1440
|
"""
|
|
1416
1441
|
# If we have already determined that the server accepts "Range" for
|
|
1417
1442
|
# another URL, we assume that it implements that feature for any
|
|
@@ -1486,6 +1511,8 @@ class DavClient:
|
|
|
1486
1511
|
|
|
1487
1512
|
Parameters
|
|
1488
1513
|
----------
|
|
1514
|
+
url : `str`
|
|
1515
|
+
Target URL.
|
|
1489
1516
|
expiration_time_seconds : `int`
|
|
1490
1517
|
Number of seconds until the generated URL is no longer valid.
|
|
1491
1518
|
|
|
@@ -1502,6 +1529,8 @@ class DavClient:
|
|
|
1502
1529
|
|
|
1503
1530
|
Parameters
|
|
1504
1531
|
----------
|
|
1532
|
+
url : `str`
|
|
1533
|
+
Target URL.
|
|
1505
1534
|
expiration_time_seconds : `int`
|
|
1506
1535
|
Number of seconds until the generated URL is no longer valid.
|
|
1507
1536
|
|
|
@@ -1530,10 +1559,13 @@ class DavClientURLSigner(DavClient):
|
|
|
1530
1559
|
Parameters
|
|
1531
1560
|
----------
|
|
1532
1561
|
url : `str`
|
|
1533
|
-
Root URL of the storage endpoint
|
|
1534
|
-
|
|
1562
|
+
Root URL of the storage endpoint
|
|
1563
|
+
(e.g. "https://host.example.org:1234/").
|
|
1535
1564
|
config : `DavConfig`
|
|
1536
1565
|
Configuration to initialize this client.
|
|
1566
|
+
accepts_ranges : `bool` | `None`
|
|
1567
|
+
Indicate whether the remote server accepts the ``Range`` header in GET
|
|
1568
|
+
requests.
|
|
1537
1569
|
"""
|
|
1538
1570
|
|
|
1539
1571
|
def __init__(self, url: str, config: DavConfig, accepts_ranges: bool | None = None) -> None:
|
|
@@ -1772,10 +1804,13 @@ class DavClientDCache(DavClientURLSigner):
|
|
|
1772
1804
|
Parameters
|
|
1773
1805
|
----------
|
|
1774
1806
|
url : `str`
|
|
1775
|
-
Root URL of the storage endpoint
|
|
1776
|
-
|
|
1807
|
+
Root URL of the storage endpoint
|
|
1808
|
+
(e.g. "https://host.example.org:1234/").
|
|
1777
1809
|
config : `DavConfig`
|
|
1778
1810
|
Configuration to initialize this client.
|
|
1811
|
+
accepts_ranges : `bool` | `None`
|
|
1812
|
+
Indicate whether the remote server accepts the ``Range`` header in GET
|
|
1813
|
+
requests.
|
|
1779
1814
|
"""
|
|
1780
1815
|
|
|
1781
1816
|
def __init__(self, url: str, config: DavConfig, accepts_ranges: bool | None = None) -> None:
|
|
@@ -1817,7 +1852,7 @@ class DavClientDCache(DavClientURLSigner):
|
|
|
1817
1852
|
Target URL.
|
|
1818
1853
|
headers : `dict[str, str]`, optional
|
|
1819
1854
|
Headers to sent with the request.
|
|
1820
|
-
preload_content: `bool`, optional
|
|
1855
|
+
preload_content : `bool`, optional
|
|
1821
1856
|
If True, the response body is downloaded and can be retrieved
|
|
1822
1857
|
via the returned response `.data` property. If False, the
|
|
1823
1858
|
caller needs to call the `.read()` on the returned response
|
|
@@ -1900,7 +1935,7 @@ class DavClientDCache(DavClientURLSigner):
|
|
|
1900
1935
|
----------
|
|
1901
1936
|
url : `str`
|
|
1902
1937
|
Target URL.
|
|
1903
|
-
data: `BinaryIO` or `bytes`
|
|
1938
|
+
data : `BinaryIO` or `bytes`
|
|
1904
1939
|
Request body.
|
|
1905
1940
|
"""
|
|
1906
1941
|
# Send a PUT request with empty body to the dCache frontend server to
|
|
@@ -1999,10 +2034,13 @@ class DavClientXrootD(DavClientURLSigner):
|
|
|
1999
2034
|
Parameters
|
|
2000
2035
|
----------
|
|
2001
2036
|
url : `str`
|
|
2002
|
-
Root URL of the storage endpoint
|
|
2003
|
-
|
|
2037
|
+
Root URL of the storage endpoint
|
|
2038
|
+
(e.g. "https://host.example.org:1234/").
|
|
2004
2039
|
config : `DavConfig`
|
|
2005
2040
|
Configuration to initialize this client.
|
|
2041
|
+
accepts_ranges : `bool` | `None`
|
|
2042
|
+
Indicate whether the remote server accepts the ``Range`` header in GET
|
|
2043
|
+
requests.
|
|
2006
2044
|
"""
|
|
2007
2045
|
|
|
2008
2046
|
def __init__(self, url: str, config: DavConfig, accepts_ranges: bool | None = None) -> None:
|
|
@@ -2019,7 +2057,7 @@ class DavClientXrootD(DavClientURLSigner):
|
|
|
2019
2057
|
Target URL.
|
|
2020
2058
|
headers : `dict[str, str]`, optional
|
|
2021
2059
|
Headers to sent with the request.
|
|
2022
|
-
preload_content: `bool`, optional
|
|
2060
|
+
preload_content : `bool`, optional
|
|
2023
2061
|
If True, the response body is downloaded and can be retrieved
|
|
2024
2062
|
via the returned response `.data` property. If False, the
|
|
2025
2063
|
caller needs to call the `.read()` on the returned response
|
|
@@ -2087,7 +2125,7 @@ class DavClientXrootD(DavClientURLSigner):
|
|
|
2087
2125
|
----------
|
|
2088
2126
|
url : `str`
|
|
2089
2127
|
Target URL.
|
|
2090
|
-
data: `BinaryIO` or `bytes`
|
|
2128
|
+
data : `BinaryIO` or `bytes`
|
|
2091
2129
|
Request body.
|
|
2092
2130
|
"""
|
|
2093
2131
|
# Send a PUT request with empty body to the XRootD frontend server to
|
|
@@ -2196,7 +2234,27 @@ class DavClientXrootD(DavClientURLSigner):
|
|
|
2196
2234
|
|
|
2197
2235
|
|
|
2198
2236
|
class DavFileMetadata:
|
|
2199
|
-
"""Container for attributes of interest of a webDAV file or directory.
|
|
2237
|
+
"""Container for attributes of interest of a webDAV file or directory.
|
|
2238
|
+
|
|
2239
|
+
Parameters
|
|
2240
|
+
----------
|
|
2241
|
+
base_url : `str`
|
|
2242
|
+
Base URL.
|
|
2243
|
+
href : `str`, optional
|
|
2244
|
+
Path component that can be added to the base URL.
|
|
2245
|
+
name : `str`, optional
|
|
2246
|
+
Name.
|
|
2247
|
+
exists : `bool`, optional
|
|
2248
|
+
Whether file or directory exist.
|
|
2249
|
+
size : `int`, optional
|
|
2250
|
+
Size of file.
|
|
2251
|
+
is_dir : `bool`, optional
|
|
2252
|
+
Whether the URL points to a directory or file.
|
|
2253
|
+
last_modified : `bool`, optional
|
|
2254
|
+
Last modified date.
|
|
2255
|
+
checksums : `dict` [ `str`, `str` ] | `None`, optional
|
|
2256
|
+
Checksums.
|
|
2257
|
+
"""
|
|
2200
2258
|
|
|
2201
2259
|
def __init__(
|
|
2202
2260
|
self,
|
|
@@ -2220,7 +2278,15 @@ class DavFileMetadata:
|
|
|
2220
2278
|
|
|
2221
2279
|
@staticmethod
|
|
2222
2280
|
def from_property(base_url: str, property: DavProperty) -> DavFileMetadata:
|
|
2223
|
-
"""Create an instance from the values in `property`.
|
|
2281
|
+
"""Create an instance from the values in `property`.
|
|
2282
|
+
|
|
2283
|
+
Parameters
|
|
2284
|
+
----------
|
|
2285
|
+
base_url : `str`
|
|
2286
|
+
Base URL.
|
|
2287
|
+
property : `DavProperty`
|
|
2288
|
+
Properties to associate with URL.
|
|
2289
|
+
"""
|
|
2224
2290
|
return DavFileMetadata(
|
|
2225
2291
|
base_url=base_url,
|
|
2226
2292
|
href=property.href,
|
|
@@ -2416,13 +2482,7 @@ class DavProperty:
|
|
|
2416
2482
|
|
|
2417
2483
|
|
|
2418
2484
|
class DavPropfindParser:
|
|
2419
|
-
"""Helper class to parse the response body of a PROPFIND request.
|
|
2420
|
-
|
|
2421
|
-
Parameters
|
|
2422
|
-
----------
|
|
2423
|
-
body : `bytes`
|
|
2424
|
-
The XML-encoded response body to PROPFIND.
|
|
2425
|
-
"""
|
|
2485
|
+
"""Helper class to parse the response body of a PROPFIND request."""
|
|
2426
2486
|
|
|
2427
2487
|
def __init__(self) -> None:
|
|
2428
2488
|
return
|
|
@@ -2434,11 +2494,12 @@ class DavPropfindParser:
|
|
|
2434
2494
|
Parameters
|
|
2435
2495
|
----------
|
|
2436
2496
|
body : `bytes`
|
|
2437
|
-
XML-encoded response body to a PROPFIND request
|
|
2497
|
+
XML-encoded response body to a PROPFIND request.
|
|
2438
2498
|
|
|
2439
2499
|
Returns
|
|
2440
2500
|
-------
|
|
2441
|
-
responses : `
|
|
2501
|
+
responses : `list` [ `DavProperty` ]
|
|
2502
|
+
Parsed content of the response.
|
|
2442
2503
|
|
|
2443
2504
|
Notes
|
|
2444
2505
|
-----
|
|
@@ -2550,7 +2611,13 @@ class TokenAuthorizer:
|
|
|
2550
2611
|
return owner_accessible and not group_accessible and not other_accessible
|
|
2551
2612
|
|
|
2552
2613
|
def set_authorization(self, headers: dict[str, str]) -> None:
|
|
2553
|
-
"""Add the 'Authorization' header to `headers`.
|
|
2614
|
+
"""Add the 'Authorization' header to `headers`.
|
|
2615
|
+
|
|
2616
|
+
Parameters
|
|
2617
|
+
----------
|
|
2618
|
+
headers : `dict` [ `str`, `str` ]
|
|
2619
|
+
Dict to augment with authorization information.
|
|
2620
|
+
"""
|
|
2554
2621
|
if self._token is None:
|
|
2555
2622
|
return
|
|
2556
2623
|
|
|
@@ -2565,8 +2632,8 @@ def expand_vars(path: str | None) -> str | None:
|
|
|
2565
2632
|
Parameters
|
|
2566
2633
|
----------
|
|
2567
2634
|
path : `str` or `None`
|
|
2568
|
-
|
|
2569
|
-
|
|
2635
|
+
Abolute or relative path which may include an environment variable
|
|
2636
|
+
(e.g. '$HOME/path/to/my/file').
|
|
2570
2637
|
|
|
2571
2638
|
Returns
|
|
2572
2639
|
-------
|
|
@@ -2577,7 +2644,15 @@ def expand_vars(path: str | None) -> str | None:
|
|
|
2577
2644
|
|
|
2578
2645
|
|
|
2579
2646
|
def dump_response(method: str, resp: HTTPResponse) -> None:
|
|
2580
|
-
"""Dump response for debugging purposes.
|
|
2647
|
+
"""Dump response for debugging purposes.
|
|
2648
|
+
|
|
2649
|
+
Parameters
|
|
2650
|
+
----------
|
|
2651
|
+
method : `str`
|
|
2652
|
+
Method name to include in log output.
|
|
2653
|
+
resp : `HTTPResponse`
|
|
2654
|
+
Response to dump.
|
|
2655
|
+
"""
|
|
2581
2656
|
log.debug("%s %s", method, resp.geturl())
|
|
2582
2657
|
for header, value in resp.headers.items():
|
|
2583
2658
|
log.debug(" %s: %s", header, value)
|
|
@@ -108,7 +108,7 @@ class FileResourcePath(ResourcePath):
|
|
|
108
108
|
|
|
109
109
|
def write(self, data: bytes, overwrite: bool = True) -> None:
|
|
110
110
|
dir = os.path.dirname(self.ospath)
|
|
111
|
-
if not os.path.exists(dir):
|
|
111
|
+
if dir and not os.path.exists(dir):
|
|
112
112
|
_create_directories(dir)
|
|
113
113
|
mode = "wb" if overwrite else "xb"
|
|
114
114
|
with open(self.ospath, mode) as f:
|
|
@@ -774,8 +774,8 @@ class HttpResourcePath(ResourcePath):
|
|
|
774
774
|
generated internally by `HttpResourcePath` (e.g. authentication
|
|
775
775
|
headers).
|
|
776
776
|
|
|
777
|
-
|
|
778
|
-
|
|
777
|
+
Returns
|
|
778
|
+
-------
|
|
779
779
|
instance : `ResourcePath`
|
|
780
780
|
Newly-created `HttpResourcePath` instance.
|
|
781
781
|
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/schemeless.py
RENAMED
|
@@ -105,13 +105,16 @@ class SchemelessResourcePath(FileResourcePath):
|
|
|
105
105
|
return stat.S_ISDIR(status.st_mode)
|
|
106
106
|
return self.dirLike
|
|
107
107
|
|
|
108
|
-
def relative_to(self, other: ResourcePath) -> str | None:
|
|
108
|
+
def relative_to(self, other: ResourcePath, walk_up: bool = False) -> str | None:
|
|
109
109
|
"""Return the relative path from this URI to the other URI.
|
|
110
110
|
|
|
111
111
|
Parameters
|
|
112
112
|
----------
|
|
113
113
|
other : `ResourcePath`
|
|
114
114
|
URI to use to calculate the relative path.
|
|
115
|
+
walk_up : `bool`, optional
|
|
116
|
+
Control whether "``..``" can be used to resolve a relative path.
|
|
117
|
+
Default is `False`. Can not be `True` on Python version 3.11.
|
|
115
118
|
|
|
116
119
|
Returns
|
|
117
120
|
-------
|
|
@@ -146,8 +149,8 @@ class SchemelessResourcePath(FileResourcePath):
|
|
|
146
149
|
raise RuntimeError(f"Unexpected combination of {child}.relative_to({other}).")
|
|
147
150
|
|
|
148
151
|
if child is None:
|
|
149
|
-
return super().relative_to(other)
|
|
150
|
-
return child.relative_to(other)
|
|
152
|
+
return super().relative_to(other, walk_up=walk_up)
|
|
153
|
+
return child.relative_to(other, walk_up=walk_up)
|
|
151
154
|
|
|
152
155
|
@classmethod
|
|
153
156
|
def _fixupPathUri(
|
|
@@ -17,6 +17,7 @@ import os
|
|
|
17
17
|
import pathlib
|
|
18
18
|
import random
|
|
19
19
|
import string
|
|
20
|
+
import sys
|
|
20
21
|
import tempfile
|
|
21
22
|
import unittest
|
|
22
23
|
import urllib.parse
|
|
@@ -375,6 +376,19 @@ class GenericTestCase(_GenericTestCase):
|
|
|
375
376
|
parent = ResourcePath("d/e.txt", forceAbsolute=False)
|
|
376
377
|
self.assertIsNone(child.relative_to(parent), f"{child}.relative_to({parent})")
|
|
377
378
|
|
|
379
|
+
# Allow .. in response.
|
|
380
|
+
child = ResourcePath(self._make_uri("a/b/c/d.txt"), forceAbsolute=False)
|
|
381
|
+
parent = ResourcePath(self._make_uri("a/b/d/e/"), forceAbsolute=False)
|
|
382
|
+
self.assertIsNone(child.relative_to(parent), f"{child}.relative_to({parent})")
|
|
383
|
+
|
|
384
|
+
if sys.version_info >= (3, 12, 0):
|
|
385
|
+
# Fails on python 3.11.
|
|
386
|
+
self.assertEqual(
|
|
387
|
+
child.relative_to(parent, walk_up=True),
|
|
388
|
+
"../../c/d.txt",
|
|
389
|
+
f"{child}.relative_to({parent}, walk_up=True)",
|
|
390
|
+
)
|
|
391
|
+
|
|
378
392
|
def test_parents(self) -> None:
|
|
379
393
|
"""Test of splitting and parent walking."""
|
|
380
394
|
parent = ResourcePath(self._make_uri("somedir"), forceDirectory=True)
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400/python/lsst_resources.egg-info}/PKG-INFO
RENAMED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-resources
|
|
3
|
-
Version: 29.2025.
|
|
3
|
+
Version: 29.2025.4400
|
|
4
4
|
Summary: An abstraction layer for reading and writing from URI file resources.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
|
-
License: BSD
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
7
|
Project-URL: Homepage, https://github.com/lsst/resources
|
|
8
8
|
Keywords: lsst
|
|
9
9
|
Classifier: Intended Audience :: Developers
|
|
10
|
-
Classifier: License :: OSI Approved :: BSD License
|
|
11
10
|
Classifier: Operating System :: OS Independent
|
|
12
11
|
Classifier: Programming Language :: Python :: 3
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Requires-Python: >=3.11.0
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: COPYRIGHT
|
|
@@ -98,6 +98,17 @@ class SchemelessTestCase(unittest.TestCase):
|
|
|
98
98
|
self.assertFalse(f.isdir())
|
|
99
99
|
self.assertIsNone(f.dirLike)
|
|
100
100
|
|
|
101
|
+
def test_cwd_write(self):
|
|
102
|
+
f = None
|
|
103
|
+
try:
|
|
104
|
+
f = ResourcePath("cwd.txt", forceAbsolute=False)
|
|
105
|
+
f.write(b"abc")
|
|
106
|
+
written = f.read()
|
|
107
|
+
self.assertEqual(written, b"abc")
|
|
108
|
+
finally:
|
|
109
|
+
if f:
|
|
110
|
+
f.remove()
|
|
111
|
+
|
|
101
112
|
|
|
102
113
|
if __name__ == "__main__":
|
|
103
114
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/doc/lsst.resources/internal-api.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/location.py
RENAMED
|
File without changes
|
|
File without changes
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/packageresource.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst/resources/s3utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_resources-29.2025.4300 → lsst_resources-29.2025.4400}/python/lsst_resources.egg-info/zip-safe
RENAMED
|
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
|