| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  | """
 | 
					
						
							|  |  |  | Interface adapters for low-level readers. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import abc | 
					
						
							|  |  |  | import io | 
					
						
							|  |  |  | import itertools | 
					
						
							|  |  |  | from typing import BinaryIO, List | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .abc import Traversable, TraversableResources | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SimpleReader(abc.ABC): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     The minimum, low-level interface required from a resource | 
					
						
							|  |  |  |     provider. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-01 11:07:32 -05:00
										 |  |  |     @property | 
					
						
							|  |  |  |     @abc.abstractmethod | 
					
						
							|  |  |  |     def package(self) -> str: | 
					
						
							| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         The name of the package for which this reader loads resources. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @abc.abstractmethod | 
					
						
							| 
									
										
										
										
											2023-01-01 11:07:32 -05:00
										 |  |  |     def children(self) -> List['SimpleReader']: | 
					
						
							| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Obtain an iterable of SimpleReader for available | 
					
						
							|  |  |  |         child containers (e.g. directories). | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @abc.abstractmethod | 
					
						
							| 
									
										
										
										
											2023-01-01 11:07:32 -05:00
										 |  |  |     def resources(self) -> List[str]: | 
					
						
							| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Obtain available named resources for this virtual package. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @abc.abstractmethod | 
					
						
							| 
									
										
										
										
											2023-01-01 11:07:32 -05:00
										 |  |  |     def open_binary(self, resource: str) -> BinaryIO: | 
					
						
							| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Obtain a File-like for a named resource. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def name(self): | 
					
						
							|  |  |  |         return self.package.split('.')[-1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-01 11:07:32 -05:00
										 |  |  | class ResourceContainer(Traversable): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Traversable container for a package's resources via its reader. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, reader: SimpleReader): | 
					
						
							|  |  |  |         self.reader = reader | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_dir(self): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_file(self): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def iterdir(self): | 
					
						
							|  |  |  |         files = (ResourceHandle(self, name) for name in self.reader.resources) | 
					
						
							|  |  |  |         dirs = map(ResourceContainer, self.reader.children()) | 
					
						
							|  |  |  |         return itertools.chain(files, dirs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def open(self, *args, **kwargs): | 
					
						
							|  |  |  |         raise IsADirectoryError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  | class ResourceHandle(Traversable): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Handle to a named resource in a ResourceReader. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-01 11:07:32 -05:00
										 |  |  |     def __init__(self, parent: ResourceContainer, name: str): | 
					
						
							| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  |         self.parent = parent | 
					
						
							| 
									
										
										
										
											2025-01-26 18:04:09 +01:00
										 |  |  |         self.name = name  # type: ignore[misc] | 
					
						
							| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def is_file(self): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_dir(self): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def open(self, mode='r', *args, **kwargs): | 
					
						
							|  |  |  |         stream = self.parent.reader.open_binary(self.name) | 
					
						
							|  |  |  |         if 'b' not in mode: | 
					
						
							| 
									
										
										
										
											2024-02-20 17:09:46 +03:00
										 |  |  |             stream = io.TextIOWrapper(stream, *args, **kwargs) | 
					
						
							| 
									
										
										
										
											2021-12-30 21:00:48 -05:00
										 |  |  |         return stream | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def joinpath(self, name): | 
					
						
							|  |  |  |         raise RuntimeError("Cannot traverse into a resource") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TraversableReader(TraversableResources, SimpleReader): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     A TraversableResources based on SimpleReader. Resource providers | 
					
						
							|  |  |  |     may derive from this class to provide the TraversableResources | 
					
						
							|  |  |  |     interface by supplying the SimpleReader interface. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def files(self): | 
					
						
							|  |  |  |         return ResourceContainer(self) |