| 
									
										
										
										
											2020-05-08 19:20:26 -04:00
										 |  |  | import os | 
					
						
							|  |  |  | import pathlib | 
					
						
							| 
									
										
										
										
											2020-06-09 19:50:01 +02:00
										 |  |  | import zipfile | 
					
						
							| 
									
										
										
										
											2020-05-08 19:20:26 -04:00
										 |  |  | import tempfile | 
					
						
							|  |  |  | import functools | 
					
						
							|  |  |  | import contextlib | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 19:50:01 +02:00
										 |  |  | def from_package(package): | 
					
						
							| 
									
										
										
										
											2020-05-08 19:20:26 -04:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-06-09 19:50:01 +02:00
										 |  |  |     Return a Traversable object for the given package. | 
					
						
							| 
									
										
										
										
											2020-05-08 19:20:26 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-06-14 08:12:20 -04:00
										 |  |  |     return fallback_resources(package.__spec__) | 
					
						
							| 
									
										
										
										
											2020-06-07 18:30:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 19:50:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | def fallback_resources(spec): | 
					
						
							|  |  |  |     package_directory = pathlib.Path(spec.origin).parent | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         archive_path = spec.loader.archive | 
					
						
							|  |  |  |         rel_path = package_directory.relative_to(archive_path) | 
					
						
							|  |  |  |         return zipfile.Path(archive_path, str(rel_path) + '/') | 
					
						
							|  |  |  |     except Exception: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     return package_directory | 
					
						
							| 
									
										
										
										
											2020-05-08 19:20:26 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @contextlib.contextmanager | 
					
						
							|  |  |  | def _tempfile(reader, suffix=''): | 
					
						
							|  |  |  |     # Not using tempfile.NamedTemporaryFile as it leads to deeper 'try' | 
					
						
							|  |  |  |     # blocks due to the need to close the temporary file to work on Windows | 
					
						
							|  |  |  |     # properly. | 
					
						
							|  |  |  |     fd, raw_path = tempfile.mkstemp(suffix=suffix) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         os.write(fd, reader()) | 
					
						
							|  |  |  |         os.close(fd) | 
					
						
							|  |  |  |         yield pathlib.Path(raw_path) | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             os.remove(raw_path) | 
					
						
							|  |  |  |         except FileNotFoundError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @functools.singledispatch | 
					
						
							|  |  |  | @contextlib.contextmanager | 
					
						
							|  |  |  | def as_file(path): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Given a Traversable object, return that object as a | 
					
						
							|  |  |  |     path on the local file system in a context manager. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     with _tempfile(path.read_bytes, suffix=path.name) as local: | 
					
						
							|  |  |  |         yield local | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @as_file.register(pathlib.Path) | 
					
						
							|  |  |  | @contextlib.contextmanager | 
					
						
							|  |  |  | def _(path): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Degenerate behavior for pathlib.Path objects. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     yield path |