Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/contrib/gis/management/commands/ogrinspect.py: 2%

48 statements  

« prev     ^ index     » next       coverage.py v7.0.5, created at 2023-01-17 06:13 +0000

1import argparse 

2 

3from django.contrib.gis import gdal 

4from django.core.management.base import BaseCommand, CommandError 

5from django.utils.inspect import get_func_args 

6 

7 

8class LayerOptionAction(argparse.Action): 

9 """ 

10 Custom argparse action for the `ogrinspect` `layer_key` keyword option 

11 which may be an integer or a string. 

12 """ 

13 

14 def __call__(self, parser, namespace, value, option_string=None): 

15 try: 

16 setattr(namespace, self.dest, int(value)) 

17 except ValueError: 

18 setattr(namespace, self.dest, value) 

19 

20 

21class ListOptionAction(argparse.Action): 

22 """ 

23 Custom argparse action for `ogrinspect` keywords that require 

24 a string list. If the string is 'True'/'true' then the option 

25 value will be a boolean instead. 

26 """ 

27 

28 def __call__(self, parser, namespace, value, option_string=None): 

29 if value.lower() == "true": 

30 setattr(namespace, self.dest, True) 

31 else: 

32 setattr(namespace, self.dest, value.split(",")) 

33 

34 

35class Command(BaseCommand): 

36 help = ( 

37 "Inspects the given OGR-compatible data source (e.g., a shapefile) and " 

38 "outputs\na GeoDjango model with the given model name. For example:\n" 

39 " ./manage.py ogrinspect zipcode.shp Zipcode" 

40 ) 

41 

42 requires_system_checks = [] 

43 

44 def add_arguments(self, parser): 

45 parser.add_argument("data_source", help="Path to the data source.") 

46 parser.add_argument("model_name", help="Name of the model to create.") 

47 parser.add_argument( 

48 "--blank", 

49 action=ListOptionAction, 

50 default=False, 

51 help="Use a comma separated list of OGR field names to add " 

52 "the `blank=True` option to the field definition. Set to `true` " 

53 "to apply to all applicable fields.", 

54 ) 

55 parser.add_argument( 

56 "--decimal", 

57 action=ListOptionAction, 

58 default=False, 

59 help="Use a comma separated list of OGR float fields to " 

60 "generate `DecimalField` instead of the default " 

61 "`FloatField`. Set to `true` to apply to all OGR float fields.", 

62 ) 

63 parser.add_argument( 

64 "--geom-name", 

65 default="geom", 

66 help="Specifies the model name for the Geometry Field (defaults to `geom`)", 

67 ) 

68 parser.add_argument( 

69 "--layer", 

70 dest="layer_key", 

71 action=LayerOptionAction, 

72 default=0, 

73 help="The key for specifying which layer in the OGR data " 

74 "source to use. Defaults to 0 (the first layer). May be " 

75 "an integer or a string identifier for the layer.", 

76 ) 

77 parser.add_argument( 

78 "--multi-geom", 

79 action="store_true", 

80 help="Treat the geometry in the data source as a geometry collection.", 

81 ) 

82 parser.add_argument( 

83 "--name-field", 

84 help="Specifies a field name to return for the __str__() method.", 

85 ) 

86 parser.add_argument( 

87 "--no-imports", 

88 action="store_false", 

89 dest="imports", 

90 help="Do not include `from django.contrib.gis.db import models` statement.", 

91 ) 

92 parser.add_argument( 

93 "--null", 

94 action=ListOptionAction, 

95 default=False, 

96 help="Use a comma separated list of OGR field names to add " 

97 "the `null=True` option to the field definition. Set to `true` " 

98 "to apply to all applicable fields.", 

99 ) 

100 parser.add_argument( 

101 "--srid", 

102 help="The SRID to use for the Geometry Field. If it can be " 

103 "determined, the SRID of the data source is used.", 

104 ) 

105 parser.add_argument( 

106 "--mapping", 

107 action="store_true", 

108 help="Generate mapping dictionary for use with `LayerMapping`.", 

109 ) 

110 

111 def handle(self, *args, **options): 

112 data_source, model_name = options.pop("data_source"), options.pop("model_name") 

113 

114 # Getting the OGR DataSource from the string parameter. 

115 try: 

116 ds = gdal.DataSource(data_source) 

117 except gdal.GDALException as msg: 

118 raise CommandError(msg) 

119 

120 # Returning the output of ogrinspect with the given arguments 

121 # and options. 

122 from django.contrib.gis.utils.ogrinspect import _ogrinspect, mapping 

123 

124 # Filter options to params accepted by `_ogrinspect` 

125 ogr_options = { 

126 k: v 

127 for k, v in options.items() 

128 if k in get_func_args(_ogrinspect) and v is not None 

129 } 

130 output = [s for s in _ogrinspect(ds, model_name, **ogr_options)] 

131 

132 if options["mapping"]: 

133 # Constructing the keyword arguments for `mapping`, and 

134 # calling it on the data source. 

135 kwargs = { 

136 "geom_name": options["geom_name"], 

137 "layer_key": options["layer_key"], 

138 "multi_geom": options["multi_geom"], 

139 } 

140 mapping_dict = mapping(ds, **kwargs) 

141 # This extra legwork is so that the dictionary definition comes 

142 # out in the same order as the fields in the model definition. 

143 rev_mapping = {v: k for k, v in mapping_dict.items()} 

144 output.extend( 

145 [ 

146 "", 

147 "", 

148 "# Auto-generated `LayerMapping` dictionary for %s model" 

149 % model_name, 

150 "%s_mapping = {" % model_name.lower(), 

151 ] 

152 ) 

153 output.extend( 

154 " '%s': '%s'," % (rev_mapping[ogr_fld], ogr_fld) 

155 for ogr_fld in ds[options["layer_key"]].fields 

156 ) 

157 output.extend( 

158 [ 

159 " '%s': '%s'," 

160 % (options["geom_name"], mapping_dict[options["geom_name"]]), 

161 "}", 

162 ] 

163 ) 

164 return "\n".join(output)