Coverage for pyguymer3/geo/getRecordAttribute.py: 3%

31 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-08 18:47 +0000

1#!/usr/bin/env python3 

2 

3# Define function ... 

4def getRecordAttribute( 

5 record, 

6 attribute, 

7 /, 

8 *, 

9 strict = False, 

10): 

11 """Get an attribute of a Shapefile record 

12 

13 This function gets an attribute of a Shapefile record, falling back on 

14 different attributes to work around inconsistencies in records in Shapefiles 

15 obtained from `Natural Earth <https://www.naturalearthdata.com>`_. 

16 

17 For example, if the user wants the "ISO_A2" attribute then this function 

18 (with ``strict = False``) will return the first value it finds (which does 

19 *not* equal "-99") from: 

20 

21 * ``record.attributes["ISO_A2"]`` 

22 * ``record.attributes["iso_a2"]`` 

23 * ``record.attributes["ISO_A2_EH"]`` 

24 * ``record.attributes["iso_a2_eh"]`` 

25 

26 Parameters 

27 ---------- 

28 record : cartopy.io.shapereader.Record 

29 the record 

30 attribute : str 

31 the attribute 

32 debug : bool, optional 

33 if ``True`` then return "-99" if that is what the value is; if ``False`` 

34 then continue looping through the possibilities 

35 

36 Returns 

37 ------- 

38 value : str 

39 the value 

40 

41 Notes 

42 ----- 

43 According to the developer of Natural Earth [1]_ : 

44 

45 "Because Natural Earth has a more fidelity than ISO, and tracks 

46 countries that ISO doesn't, Natural Earth maintains it's own set of 

47 3-character codes for each admin-0 related feature." 

48 

49 Therefore, when "ISO_A2" or "ISO_A3" are not populated I must fall back on 

50 "ISO_A2_EH" and "ISO_A3_EH" instead. 

51 

52 Copyright 2017 Thomas Guymer [2]_ 

53 

54 References 

55 ---------- 

56 .. [1] developer comment on issue #268 of Natural Earth, https://github.com/nvkelso/natural-earth-vector/issues/268#issuecomment-778832542 

57 .. [2] PyGuymer3, https://github.com/Guymer/PyGuymer3 

58 """ 

59 

60 # Import standard modules ... 

61 import os 

62 

63 # Import special modules ... 

64 try: 

65 import cartopy 

66 cartopy.config.update( 

67 { 

68 "cache_dir" : os.path.expanduser("~/.local/share/cartopy_cache"), 

69 } 

70 ) 

71 except: 

72 raise Exception("\"cartopy\" is not installed; run \"pip install --user Cartopy\"") from None 

73 

74 # ************************************************************************** 

75 

76 # Check argument ... 

77 assert isinstance(record, cartopy.io.shapereader.Record), "\"record\" is not a Record" 

78 

79 # Loop over possible attribute names ... 

80 for posAttribute in [attribute.upper(), attribute.lower()]: 

81 # Skip if it is not present ... 

82 if posAttribute not in record.attributes: 

83 continue 

84 

85 # Extract the value (whilst handling Natural Earth's foibles) ... 

86 value = record.attributes[posAttribute] 

87 if isinstance(value, str): 

88 value = value.replace("\x00", " ").strip() 

89 

90 # Check if the user wants to be strict ... 

91 if strict: 

92 # Return answer ... 

93 return value 

94 

95 # Skip if it is bad and we want to try more possible attribute names ... 

96 if value == "-99": 

97 continue 

98 

99 # Return answer ... 

100 return value 

101 

102 # Loop over possible attribute names ... 

103 for posAttribute in [f"{attribute.upper()}_EH", f"{attribute.lower()}_eh"]: 

104 # Skip if it is not present ... 

105 if posAttribute not in record.attributes: 

106 continue 

107 

108 # Extract the value (whilst handling Natural Earth's foibles) ... 

109 value = record.attributes[posAttribute] 

110 if isinstance(value, str): 

111 value = value.replace("\x00", " ").strip() 

112 

113 # Check if the user wants to be strict ... 

114 if strict: 

115 # Return answer ... 

116 return value 

117 

118 # Skip if it is bad and we want to try more possible attribute names ... 

119 if value == "-99": 

120 continue 

121 

122 # Return answer ... 

123 return value 

124 

125 # Return answer ... 

126 return "ERROR"