1- import os
21import uuid
32from abc import abstractmethod
43from collections .abc import Callable
54from dataclasses import dataclass
65from datetime import date
7- from pathlib import Path
6+ from pathlib import PurePath , PureWindowsPath
87from typing import Protocol
8+ from urllib .parse import urlunparse
99
1010
1111@dataclass
@@ -16,11 +16,36 @@ class PathInfo:
1616 :param filename: Base filename to use generated by FilenameProvider, w/o extension
1717 :param create_dir_depth: Optional depth of directories to create if they do not
1818 exist
19+ :param directory_uri: Optional URI to use for reading back resources. If not set,
20+ it will be generated from the directory path.
1921 """
2022
21- directory_path : Path
23+ directory_path : PurePath
2224 filename : str
2325 create_dir_depth : int = 0
26+ directory_uri : str | None = None
27+
28+ def __post_init__ (self ):
29+ if not self .directory_path .is_absolute ():
30+ raise ValueError (
31+ f"directory_path must be an absolute path, got { self .directory_path } "
32+ )
33+
34+ # If directory uri is not set, set it using the directory path.
35+ if self .directory_uri is None :
36+ self .directory_uri = urlunparse (
37+ (
38+ "file" ,
39+ "localhost" ,
40+ f"{ self .directory_path .as_posix ()} /" ,
41+ "" ,
42+ "" ,
43+ None ,
44+ )
45+ )
46+ elif not self .directory_uri .endswith ("/" ):
47+ # Ensure the directory URI ends with a slash.
48+ self .directory_uri += "/"
2449
2550
2651class FilenameProvider (Protocol ):
@@ -112,18 +137,21 @@ class StaticPathProvider(PathProvider):
112137 def __init__ (
113138 self ,
114139 filename_provider : FilenameProvider ,
115- directory_path : Path | str ,
140+ directory_path : PurePath ,
141+ directory_uri : str | None = None ,
116142 create_dir_depth : int = 0 ,
117143 ) -> None :
118144 self ._filename_provider = filename_provider
119- self ._directory_path = Path (directory_path )
145+ self ._directory_path = directory_path
146+ self ._directory_uri = directory_uri
120147 self ._create_dir_depth = create_dir_depth
121148
122149 def __call__ (self , device_name : str | None = None ) -> PathInfo :
123150 filename = self ._filename_provider (device_name )
124151
125152 return PathInfo (
126153 directory_path = self ._directory_path ,
154+ directory_uri = self ._directory_uri ,
127155 filename = filename ,
128156 create_dir_depth = self ._create_dir_depth ,
129157 )
@@ -135,7 +163,8 @@ class AutoIncrementingPathProvider(PathProvider):
135163 def __init__ (
136164 self ,
137165 filename_provider : FilenameProvider ,
138- base_directory_path : Path ,
166+ base_directory_path : PurePath ,
167+ base_directory_uri : str | None = None ,
139168 create_dir_depth : int = 0 ,
140169 max_digits : int = 5 ,
141170 starting_value : int = 0 ,
@@ -146,6 +175,12 @@ def __init__(
146175 ) -> None :
147176 self ._filename_provider = filename_provider
148177 self ._base_directory_path = base_directory_path
178+ self ._base_directory_uri = base_directory_uri
179+ if (
180+ self ._base_directory_uri is not None
181+ and not self ._base_directory_uri .endswith ("/" )
182+ ):
183+ self ._base_directory_uri += "/"
149184 self ._create_dir_depth = create_dir_depth
150185 self ._base_name = base_name
151186 self ._starting_value = starting_value
@@ -174,8 +209,13 @@ def __call__(self, device_name: str | None = None) -> PathInfo:
174209 self ._inc_counter = 0
175210 self ._current_value += self ._increment
176211
212+ directory_uri = None
213+ if self ._base_directory_uri is not None :
214+ directory_uri = f"{ self ._base_directory_uri } { auto_inc_dir_name } "
215+
177216 return PathInfo (
178217 directory_path = self ._base_directory_path / auto_inc_dir_name ,
218+ directory_uri = directory_uri ,
179219 filename = filename ,
180220 create_dir_depth = self ._create_dir_depth ,
181221 )
@@ -187,34 +227,52 @@ class YMDPathProvider(PathProvider):
187227 def __init__ (
188228 self ,
189229 filename_provider : FilenameProvider ,
190- base_directory_path : Path ,
230+ base_directory_path : PurePath ,
231+ base_directory_uri : str | None = None ,
191232 create_dir_depth : int = - 3 , # Default to -3 to create YMD dirs
192233 device_name_as_base_dir : bool = False ,
193234 ) -> None :
194235 self ._filename_provider = filename_provider
195- self ._base_directory_path = Path (base_directory_path )
236+ self ._base_directory_path = base_directory_path
237+ self ._base_directory_uri = base_directory_uri
238+ if (
239+ self ._base_directory_uri is not None
240+ and not self ._base_directory_uri .endswith ("/" )
241+ ):
242+ self ._base_directory_uri += "/"
196243 self ._create_dir_depth = create_dir_depth
197244 self ._device_name_as_base_dir = device_name_as_base_dir
198245
199246 def __call__ (self , device_name : str | None = None ) -> PathInfo :
200- sep = os .path .sep
247+ path_type = type (self ._base_directory_path )
248+ if path_type == PureWindowsPath :
249+ sep = "\\ "
250+ else :
251+ sep = "/"
252+
201253 current_date = date .today ().strftime (f"%Y{ sep } %m{ sep } %d" )
202254 if device_name is None :
203255 ymd_dir_path = current_date
204256 elif self ._device_name_as_base_dir :
205- ymd_dir_path = os . path . join (
257+ ymd_dir_path = path_type (
206258 current_date ,
207259 device_name ,
208260 )
209261 else :
210- ymd_dir_path = os . path . join (
262+ ymd_dir_path = path_type (
211263 device_name ,
212264 current_date ,
213265 )
214266
215267 filename = self ._filename_provider (device_name )
268+
269+ directory_uri = None
270+ if self ._base_directory_uri is not None :
271+ directory_uri = f"{ self ._base_directory_uri } { ymd_dir_path } "
272+
216273 return PathInfo (
217274 directory_path = self ._base_directory_path / ymd_dir_path ,
275+ directory_uri = directory_uri ,
218276 filename = filename ,
219277 create_dir_depth = self ._create_dir_depth ,
220278 )
0 commit comments