81 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			81 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| Helper functions for file reading and writing
 | |
| """
 | |
| from typing import IO, Iterator
 | |
| import re
 | |
| import pathlib
 | |
| import logging
 | |
| import tempfile
 | |
| import shutil
 | |
| from contextlib import contextmanager
 | |
| 
 | |
| from .. import Pattern, PatternError
 | |
| from ..shapes import Polygon, Path
 | |
| 
 | |
| 
 | |
| logger = logging.getLogger(__name__)
 | |
| 
 | |
| 
 | |
| def mangle_name(name: str) -> str:
 | |
|     """
 | |
|     Sanitize a name.
 | |
| 
 | |
|     Args:
 | |
|         name: Name we want to mangle.
 | |
| 
 | |
|     Returns:
 | |
|         Mangled name.
 | |
|     """
 | |
|     expression = re.compile(r'[^A-Za-z0-9_\?\$]')
 | |
|     sanitized_name = expression.sub('_', name)
 | |
|     return sanitized_name
 | |
| 
 | |
| 
 | |
| def clean_pattern_vertices(pat: Pattern) -> Pattern:
 | |
|     """
 | |
|     Given a pattern, remove any redundant vertices in its polygons and paths.
 | |
|     The cleaning process completely removes any polygons with zero area or <3 vertices.
 | |
| 
 | |
|     Args:
 | |
|         pat: Pattern to clean
 | |
| 
 | |
|     Returns:
 | |
|         pat
 | |
|     """
 | |
|     for shapes in pat.shapes.values():
 | |
|         remove_inds = []
 | |
|         for ii, shape in enumerate(shapes):
 | |
|             if not isinstance(shape, (Polygon, Path)):
 | |
|                 continue
 | |
|             try:
 | |
|                 shape.clean_vertices()
 | |
|             except PatternError:
 | |
|                 remove_inds.append(ii)
 | |
|         for ii in sorted(remove_inds, reverse=True):
 | |
|             del shapes[ii]
 | |
|     return pat
 | |
| 
 | |
| 
 | |
| def is_gzipped(path: pathlib.Path) -> bool:
 | |
|     with open(path, 'rb') as stream:
 | |
|         magic_bytes = stream.read(2)
 | |
|         return magic_bytes == b'\x1f\x8b'
 | |
| 
 | |
| 
 | |
| @contextmanager
 | |
| def tmpfile(path: str | pathlib.Path) -> Iterator[IO[bytes]]:
 | |
|     """
 | |
|     Context manager which allows you to write to a temporary file,
 | |
|     and move that file into its final location only after the write
 | |
|     has finished.
 | |
|     """
 | |
|     path = pathlib.Path(path)
 | |
|     suffixes = ''.join(path.suffixes)
 | |
|     with tempfile.NamedTemporaryFile(suffix=suffixes, delete=False) as tmp_stream:
 | |
|         yield tmp_stream
 | |
| 
 | |
|     try:
 | |
|         shutil.move(tmp_stream.name, path)
 | |
|     finally:
 | |
|         pathlib.Path(tmp_stream.name).unlink(missing_ok=True)
 |