Skip to content

convert.py

Bases: YamlFile

A class to apply a YAML config file and convert ODK to OSM.

Returns:

Type Description
Convert

An instance of this object

Source code in osm_merge/fieldwork/convert.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def __init__(
    self,
    xform: str = None,
):
    if xform is not None:
        file = xform
    else:
        file = rootdir + "/fieldwork/xforms.yaml"
    self.yaml = YamlFile(file)
    self.filespec = file
    # Parse the file contents into a data structure to make it
    # easier to retrieve values
    self.convert = dict()
    self.ignore = list()
    self.private = list()
    self.defaults = dict()
    self.entries = dict()
    self.types = dict()
    self.saved = dict()
    for item in self.yaml.yaml["convert"]:
        key = list(item.keys())[0]
        value = item[key]
        # print("ZZZZ: %r, %r" % (key, value))
        if type(value) is str:
            self.convert[key] = value
        elif type(value) is list:
            vals = dict()
            for entry in value:
                if type(entry) is str:
                    # epdb.st()
                    tag = entry
                else:
                    tag = list(entry.keys())[0]
                    vals[tag] = entry[tag]
            self.convert[key] = vals
    self.ignore = self.yaml.yaml["ignore"]
    self.private = self.yaml.yaml["private"]
    if "multiple" in self.yaml.yaml:
        self.multiple = self.yaml.yaml["multiple"]
    else:
        self.multiple = list()

privateData

privateData(keyword)

Search the private data category for a keyword.

Parameters:

Name Type Description Default
keyword str

The keyword to search for

required

Returns:

Type Description
bool

=If the keyword is in the private data section

Source code in osm_merge/fieldwork/convert.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
def privateData(
    self,
    keyword: str,
) -> bool:
    """
    Search the private data category for a keyword.

    Args:
        keyword (str): The keyword to search for

    Returns:
        (bool): =If the keyword is in the private data section
    """
    return keyword.lower() in self.private

convertData

convertData(keyword)

Search the convert data category for a keyword.

Parameters:

Name Type Description Default
keyword str

The keyword to search for

required

Returns:

Type Description
bool

Check to see if the keyword is in the convert data section

Source code in osm_merge/fieldwork/convert.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def convertData(
    self,
    keyword: str,
) -> bool:
    """
    Search the convert data category for a keyword.

    Args:
        keyword (str): The keyword to search for

    Returns:
        (bool): Check to see if the keyword is in the convert data section
    """
    return keyword.lower() in self.convert

ignoreData

ignoreData(keyword)

Search the convert data category for a ketyword.

Parameters:

Name Type Description Default
keyword str

The keyword to search for

required

Returns:

Type Description
bool

Check to see if the keyword is in the ignore data section

Source code in osm_merge/fieldwork/convert.py
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def ignoreData(
    self,
    keyword: str,
) -> bool:
    """
    Search the convert data category for a ketyword.

    Args:
        keyword (str): The keyword to search for

    Returns:
        (bool): Check to see if the keyword is in the ignore data section
    """
    return keyword.lower() in self.ignore

getKeyword

getKeyword(value)

Get the keyword for a value from the yaml file.

Parameters:

Name Type Description Default
value str

The value to find the keyword for

required

Returns:

Type Description
str

The keyword if found, or None

Source code in osm_merge/fieldwork/convert.py
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
def getKeyword(
    self,
    value: str,
) -> str:
    """
    Get the keyword for a value from the yaml file.

    Args:
        value (str): The value to find the keyword for

    Returns:
        (str): The keyword if found, or None
    """
    key = self.yaml.yaml(value)
    if type(key) == bool:
        return value
    if len(key) == 0:
        key = self.yaml.getKeyword(value)
    return key

getValues

getValues(keyword=None)

Get the values for a primary key.

Parameters:

Name Type Description Default
keyword str

The keyword to get the value of

None

Returns:

Type Description
str

The values or None

Source code in osm_merge/fieldwork/convert.py
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
def getValues(
    self,
    keyword: str = None,
) -> str:
    """
    Get the values for a primary key.

    Args:
        keyword (str): The keyword to get the value of

    Returns:
        (str): The values or None
    """
    if keyword is not None:
        if keyword in self.convert:
            return self.convert[keyword]
    else:
        return None

convertEntry

convertEntry(tag, value)

Convert a tag and value from the ODK represention to an OSM one.

Parameters:

Name Type Description Default
tag str

The tag from the ODK XML file

required
value str

The value from the ODK XML file

required

Returns:

Type Description
list

The converted values

Source code in osm_merge/fieldwork/convert.py
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
def convertEntry(
    self,
    tag: str,
    value: str,
) -> list:
    """
    Convert a tag and value from the ODK represention to an OSM one.

    Args:
        tag (str): The tag from the ODK XML file
        value (str): The value from the ODK XML file

    Returns:
        (list): The converted values
    """
    all = list()

    # If it's not in any conversion data, pass it through unchanged.
    if tag.lower() in self.ignore:
        # logging.debug(f"FIXME: Ignoring {tag}")
        return None
    low = tag.lower()
    if value is None:
        return low

    if low not in self.convert and low not in self.ignore and low not in self.private:
        return {tag: value}

    newtag = tag.lower()
    newval = value
    # If the tag is in the config file, convert it.
    if self.convertData(newtag):
        newtag = self.convertTag(newtag)
        # if newtag != tag:
        #    logging.debug(f"Converted Tag for entry {tag} to {newtag}")

    # Truncate the elevation, as it's really long
    if newtag == "ele":
        value = value[:7]
    newval = self.convertValue(newtag, value)
    # logging.debug("Converted Value for entry '%s' to '%s'" % (value, newval))
    # there can be multiple new tag/value pairs for some values from ODK
    if type(newval) == str:
        all.append({newtag: newval})
    elif type(newval) == list:
        for entry in newval:
            if type(entry) == str:
                all.append({newtag: newval})
            elif type(entry) == dict:
                for k, v in entry.items():
                    all.append({k: v})
    return all

convertValue

convertValue(tag, value)

Convert a single tag value.

Parameters:

Name Type Description Default
tag str

The tag from the ODK XML file

required
value str

The value from the ODK XML file

required

Returns:

Type Description
list

The converted values

Source code in osm_merge/fieldwork/convert.py
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def convertValue(
    self,
    tag: str,
    value: str,
) -> list:
    """
    Convert a single tag value.

    Args:
        tag (str): The tag from the ODK XML file
        value (str): The value from the ODK XML file

    Returns:
        (list): The converted values
    """
    all = list()

    vals = self.getValues(tag)
    # There is no conversion data for this tag
    if vals is None:
        return value

    if type(vals) is dict:
        if value not in vals:
            all.append({tag: value})
            return all
        if type(vals[value]) is bool:
            entry = dict()
            if vals[value]:
                entry[tag] = "yes"
            else:
                entry[tag] = "no"
            all.append(entry)
            return all
        for item in vals[value].split(","):
            entry = dict()
            tmp = item.split("=")
            if len(tmp) == 1:
                entry[tag] = vals[value]
            else:
                entry[tmp[0]] = tmp[1]
                logging.debug("\tValue %s converted value to %s" % (value, entry))
            all.append(entry)
    return all

convertTag

convertTag(tag)

Convert a single tag.

Parameters:

Name Type Description Default
tag str

The tag from the ODK XML file

required

Returns:

Type Description
str

The new tag

Source code in osm_merge/fieldwork/convert.py
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
def convertTag(
    self,
    tag: str,
) -> str:
    """
    Convert a single tag.

    Args:
        tag (str): The tag from the ODK XML file

    Returns:
        (str): The new tag
    """
    low = tag.lower()
    if low in self.convert:
        newtag = self.convert[low]
        if type(newtag) is str:
            # logging.debug("\tTag '%s' converted tag to '%s'" % (tag, newtag))
            tmp = newtag.split("=")
            if len(tmp) > 1:
                newtag = tmp[0]
        elif type(newtag) is list:
            logging.error("FIXME: list()")
            # epdb.st()
            return low, value
        elif type(newtag) is dict:
            # logging.error("FIXME: dict()")
            return low
        return newtag.lower()
    else:
        logging.debug(f"Not in convert!: {low}")
        return low

convertMultiple

convertMultiple(value)

Convert a multiple tags from a select_multiple question..

Parameters:

Name Type Description Default
value str

The tags from the ODK XML file

required

Returns:

Type Description
list

The new tags

Source code in osm_merge/fieldwork/convert.py
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
def convertMultiple(
    self,
    value: str,
) -> list:
    """
    Convert a multiple tags from a select_multiple question..

    Args:
        value (str): The tags from the ODK XML file

    Returns:
        (list): The new tags
    """
    tags = dict()
    for tag in value.split(" "):
        low = tag.lower()
        if self.convertData(low):
            newtag = self.convert[low]
            if newtag.find("=") > 0:
                tmp = newtag.split("=")
                if tmp[0] in tags:
                    tags[tmp[0]] = f"{tags[tmp[0]]};{tmp[1]}"
                else:
                    tags.update({tmp[0]: tmp[1]})
        else:
            tags.update({low: "yes"})
    # logging.debug(f"\tConverted multiple to {tags}")
    return tags

parseXLS

parseXLS(xlsfile)

Parse the source XLSFile if available to look for details we need.

Source code in osm_merge/fieldwork/convert.py
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
def parseXLS(
    self,
    xlsfile: str,
):
    """
    Parse the source XLSFile if available to look for details we need.
    """
    if xlsfile is not None and len(xlsfile) > 0:
        self.entries = pd.read_excel(xlsfile, sheet_name=[0])[0]
        # There will only be a single sheet
        names = self.entries["name"]
        defaults = self.entries["default"]
        i = 0
        while i < len(self.entries):
            if type(self.entries["type"][i]) == float:
                self.types[self.entries["name"][i]] = None
            else:
                self.types[self.entries["name"][i]] = self.entries["type"][i].split(" ")[0]
            i += 1
        total = len(names)
        i = 0
        while i < total:
            entry = defaults[i]
            if str(entry) != "nan":
                pat = re.compile("..last-saved.*")
                if pat.match(entry):
                    name = entry.split("#")[1][:-1]
                    self.saved[name] = None
                else:
                    self.defaults[names[i]] = entry
            i += 1
    return True

dump

dump()

Dump internal data structures, for debugging purposes only.

Source code in osm_merge/fieldwork/convert.py
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
def dump(self):
    """Dump internal data structures, for debugging purposes only."""
    print("YAML file: %s" % self.filespec)
    print("Convert section")
    for key, val in self.convert.items():
        if type(val) is list:
            print("\tTag %s is" % key)
            for data in val:
                print("\t\t%r" % data)
        else:
            print("\tTag %s is %s" % (key, val))

    print("Ignore Section")
    for item in self.ignore:
        print(f"\tIgnoring tag {item}")

options: show_source: false heading_level: 3