Coverage for attribuutit/shp.py: 90.91%

25 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-04 15:52:25 +00:00

1import pathlib 

2from typing import no_type_check 

3 

4import shapefile # type: ignore 

5 

6 

7@no_type_check 

8def shape_type(code: int) -> str: 

9 """Look up the name (code) from the integer code reported by shapefile or UNKNOWN""" 

10 shape_type_map = { 

11 -1: 'UNKNOWN', 

12 0: 'NULL', 

13 1: 'POINT', 

14 3: 'POLYLINE', 

15 5: 'POLYGON', 

16 8: 'MULTIPOINT', 

17 11: 'POINTZ', 

18 13: 'POLYLINEZ', 

19 15: 'POLYGONZ', 

20 18: 'MULTIPOINTZ', 

21 21: 'POINTM', 

22 23: 'POLYLINEM', 

23 25: 'POLYGONM', 

24 28: 'MULTIPOINTM', 

25 31: 'MULTIPATCH', 

26 } 

27 name = shape_type_map.get(code) 

28 return name if name else shape_type_map[-1] 

29 

30 

31@no_type_check 

32def load(path: pathlib.Path): 

33 """Load the shape file at path.""" 

34 error = '' 

35 with shapefile.Reader(path) as shape: 

36 shape_type_name = shape_type(shape.shapeType) 

37 # upstream_name = shape.shapeTypeName 

38 feature_count = len(shape) 

39 bounding_box = shape.bbox 

40 try: 

41 geo_json = shape.__geo_interface__ 

42 except shapefile.ShapefileException as err: 

43 geo_json = None 

44 error = f'problem reading database of shape for {path} with {err}' 

45 

46 return error, { 

47 'folder_path': str(path.parent), 

48 'file_name': path.name, 

49 'file_suffixes': path.suffixes, 

50 'shape_type_name': shape_type_name, 

51 'feature_count': feature_count, 

52 'bounding_box': bounding_box, 

53 'has_geo_json': bool(geo_json), 

54 'geo_json_type': geo_json.get('type', None) if geo_json else None, 

55 } 

56 

57 

58@no_type_check 

59def summary(shp_model, full_path=False): 

60 """Summarize the shapefile model as single line string.""" 

61 path_disp = pathlib.Path(shp_model['folder_path']) / shp_model['file_name'] if full_path else shp_model['file_name'] 

62 return ( 

63 f'{path_disp} ->' 

64 f" {shp_model['geo_json_type'] if shp_model['has_geo_json'] else shp_model['shape_type_name']}" 

65 f"/{shp_model['feature_count']} within {shp_model['bounding_box']}" 

66 )