thds.core 1.46.20251008013227__py3-none-any.whl → 1.46.20251008224105__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.

Potentially problematic release.


This version of thds.core might be problematic. Click here for more details.

@@ -1,4 +1,5 @@
1
1
  import os
2
+ import stat
2
3
  import sys
3
4
  import typing as ty
4
5
  from functools import partial
@@ -43,20 +44,21 @@ def from_file(
43
44
  responsibility to ensure that your file has been uploaded to the URI you provide.
44
45
  """
45
46
  path = path_from_uri(filename) if isinstance(filename, str) else Path(filename)
46
- if not path.exists():
47
- raise FileNotFoundError(path)
47
+ stats = path.stat() # raises FileNotFoundError if file doesn't exist
48
+ if stat.S_ISDIR(stats.st_mode):
49
+ raise IsADirectoryError(path)
48
50
 
49
51
  file_hash = hash or hash_file(path) # use automatic hash algo if not specified!
50
52
  if uri:
51
- src = from_uri(uri, file_hash)
53
+ src = from_uri(uri, file_hash, stats.st_size)
52
54
  else:
53
- src = Source(to_uri(path), file_hash)
55
+ src = Source(to_uri(path), file_hash, stats.st_size)
54
56
  src._set_cached_path(path) # internally, it's okay to hack around immutability.
55
57
  return src
56
58
 
57
59
 
58
60
  class FromUri(ty.Protocol):
59
- def __call__(self, hash: ty.Optional[Hash]) -> Source:
61
+ def __call__(self, hash: ty.Optional[Hash], size: int = 0) -> Source:
60
62
  """Closure over a URI that creates a Source from a URI.
61
63
 
62
64
  The Hash may be used to short-circuit creation that would result in creating
@@ -84,13 +86,20 @@ def register_from_uri_handler(key: str, handler: FromUriHandler):
84
86
  _FROM_URI_HANDLERS[key] = handler
85
87
 
86
88
 
89
+ def _from_local_uri(uri: str, hash: ty.Optional[Hash], size: int = 0) -> Source:
90
+ """fulfill the FromUri interface"""
91
+ return from_file(path_from_uri(uri), hash)
92
+
93
+
94
+ def _local_file_uri_handler(uri: str) -> ty.Optional[FromUri]:
95
+ return partial(_from_local_uri, uri) if is_file_uri(uri) else None
96
+
97
+
87
98
  _FROM_URI_HANDLERS: ty.Dict[str, FromUriHandler] = dict()
88
- register_from_uri_handler(
89
- "local_file", lambda uri: partial(from_file, path_from_uri(uri)) if is_file_uri(uri) else None
90
- )
99
+ register_from_uri_handler("local_file", _local_file_uri_handler)
91
100
 
92
101
 
93
- def from_uri(uri: str, hash: ty.Optional[Hash] = None) -> Source:
102
+ def from_uri(uri: str, hash: ty.Optional[Hash] = None, size: int = 0) -> Source:
94
103
  """Create a read-only Source from a URI. The data should already exist at this remote
95
104
  URI, although Source itself can make no guarantee that it always represents real data
96
105
  - only that any data it does represent is read-only.
@@ -101,5 +110,5 @@ def from_uri(uri: str, hash: ty.Optional[Hash] = None) -> Source:
101
110
  """
102
111
  for handler in _FROM_URI_HANDLERS.values():
103
112
  if from_uri_ := handler(uri):
104
- return from_uri_(hash)
105
- return Source(uri=uri, hash=hash)
113
+ return from_uri_(hash, size)
114
+ return Source(uri=uri, hash=hash, size=size)
thds/core/source/serde.py CHANGED
@@ -36,6 +36,7 @@ def from_json(json_source: str, hash_parsers: ty.Collection[HashParser] = base_p
36
36
  return _construct.from_uri(
37
37
  uri=d["uri"],
38
38
  hash=next(filter(None, (p(d) for p in hash_parsers)), None),
39
+ size=d.get("size") or 0,
39
40
  )
40
41
 
41
42
 
@@ -57,7 +58,7 @@ def to_json(
57
58
  hash_dict = (
58
59
  next(filter(None, (ser(source.hash) for ser in hash_serializers if source.hash)), None)
59
60
  ) or dict()
60
- return json.dumps(dict(uri=source.uri, **hash_dict))
61
+ return json.dumps(dict(uri=source.uri, size=source.size, **hash_dict))
61
62
 
62
63
 
63
64
  def from_unknown_user_path(path: types.StrOrPath, desired_uri: str) -> Source:
thds/core/source/src.py CHANGED
@@ -45,6 +45,8 @@ class Source(os.PathLike):
45
45
  hash: ty.Optional[hashing.Hash] = None
46
46
  # hash and equality are based only on the _identity_ of the object,
47
47
  # not on the other properties that provide some caching functionality.
48
+ size: int = 0
49
+ # in bytes
48
50
 
49
51
  @property
50
52
  def cached_path(self) -> ty.Optional[Path]:
@@ -95,7 +97,7 @@ class Source(os.PathLike):
95
97
  return from_file(filename, hash, uri)
96
98
 
97
99
  @staticmethod
98
- def from_uri(uri: str, hash: ty.Optional[hashing.Hash] = None) -> "Source":
100
+ def from_uri(uri: str, hash: ty.Optional[hashing.Hash] = None, size: int = 0) -> "Source":
99
101
  from ._construct import from_uri
100
102
 
101
- return from_uri(uri, hash)
103
+ return from_uri(uri, hash, size)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thds.core
3
- Version: 1.46.20251008013227
3
+ Version: 1.46.20251008224105
4
4
  Summary: Core utilities.
5
5
  Author-email: Trilliant Health <info@trillianthealth.com>
6
6
  License: MIT
@@ -53,11 +53,11 @@ thds/core/log/kw_formatter.py,sha256=9-MVOd2r5NEkYNne9qWyFMeR5lac3w7mjHXsDa681i0
53
53
  thds/core/log/kw_logger.py,sha256=CyZVPnkUMtrUL2Lyk261AIEPmoP-buf_suFAhQlU1io,4063
54
54
  thds/core/log/logfmt.py,sha256=i66zoG2oERnE1P_0TVXdlfJ1YgUmvtMjqRtdV5u2SvU,10366
55
55
  thds/core/source/__init__.py,sha256=e-cRoLl1HKY3YrDjpV5p_i7zvr1L4q51-t1ISTxdig4,543
56
- thds/core/source/_construct.py,sha256=lt6OUOz_s9VBZMZJHXVpfIjmuTH7w1PBhpre0dlW1Zw,3914
56
+ thds/core/source/_construct.py,sha256=jtsh0Du67TslWjCLASZ3pAMeaiowfgm7Bt50zIhwx7k,4330
57
57
  thds/core/source/_construct_tree.py,sha256=5Zk3a5a0uVxklWw6q4JOvI_bErqwlBngUz4TyEAWn1g,616
58
58
  thds/core/source/_download.py,sha256=faKWxgzw1fTqOoyjtgi4IyhiZpBYTm_GZxwqC6LTiXU,2764
59
- thds/core/source/serde.py,sha256=zEAR24AewgDqqkIxcPpS7NZ-ZbEnQPK_A7siWlE3Q0E,3091
60
- thds/core/source/src.py,sha256=nTUBgsAES0J73enIEbc5BitgnxA5kBnf88oYZoMQGnM,4596
59
+ thds/core/source/serde.py,sha256=fCcsqER21uI41og24pDDVsksTYFIgOiz_2v3MJPpb2Y,3142
60
+ thds/core/source/src.py,sha256=Pbe8W_M1oaWwC1UKX3JtB25h3hzSNU9aCiVSkNz32Pk,4650
61
61
  thds/core/source/tree.py,sha256=iNCoCE655MwXQwc2Y0IIm1HMVk5Inj0NGVU9U8Wl_90,4317
62
62
  thds/core/sqlite/__init__.py,sha256=xJbwCoIeiOvsZDc2PlkJukRKmv3fIgSny68O6lulGPw,613
63
63
  thds/core/sqlite/connect.py,sha256=l4QaSAI8RjP7Qh2FjmJ3EwRgfGf65Z3-LjtC9ocHM_U,977
@@ -74,8 +74,8 @@ thds/core/sqlite/structured.py,sha256=8t1B6XbM5NnudKEeBLsdjRVbSXXSr6iHOW0HwEAqtX
74
74
  thds/core/sqlite/types.py,sha256=oq8m0UrvSn1IqWWcQ4FPptfAhdj6DllnCe7puVqSHlY,1297
75
75
  thds/core/sqlite/upsert.py,sha256=BmKK6fsGVedt43iY-Lp7dnAu8aJ1e9CYlPVEQR2pMj4,5827
76
76
  thds/core/sqlite/write.py,sha256=z0219vDkQDCnsV0WLvsj94keItr7H4j7Y_evbcoBrWU,3458
77
- thds_core-1.46.20251008013227.dist-info/METADATA,sha256=4q7nlyNrthr2-I0JqR4T0YLldKPouABTwC1NDWlAQyM,2216
78
- thds_core-1.46.20251008013227.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
79
- thds_core-1.46.20251008013227.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
80
- thds_core-1.46.20251008013227.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
81
- thds_core-1.46.20251008013227.dist-info/RECORD,,
77
+ thds_core-1.46.20251008224105.dist-info/METADATA,sha256=0U7El82Q5euMyobeHWCgu9R5KN7tUKRO6qeHyAA7GUw,2216
78
+ thds_core-1.46.20251008224105.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
79
+ thds_core-1.46.20251008224105.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
80
+ thds_core-1.46.20251008224105.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
81
+ thds_core-1.46.20251008224105.dist-info/RECORD,,