Repository: openaddresses/machine
Pull request #672 (2017-10-24 03:21:31)

add condition to postfixed_street for optional units
This PR aims to handle sources where units may be embedded in a single address field and makes 2 modifications:

- adds a function named `postfixed_unit` 
- adds an optional boolean flag named `may_contain_units` to the `postfixed_street` function

A number of sources like [Thurston County, WA](https://github.com/openaddresses/openaddresses/blob/master/sources/us/wa/thurston.json#L26) implement highly similar regex patterns to extract common unit formats from fields that contains streets.  This PR adds convenience functions to reduce copy/pasting of these patterns.  These unit designators are the tokens (the most common I've seen):

- Unit
- Apartment
- Apt
- Suite
- Ste
- Building
- Bldg
- Lot
- `#`

Much like `prefixed_number` and `postfixed_street`, `postfixed_unit` is specified as:

```
{
    "function": "postfixed_unit",
    "field": "ADDRESS"
}
```

This function would extract `Unit 3` and `Apartment B-3` from `123 Main Street Unit 3` and `123 Main Street Apartment B-3`, respectively.  It doesn't aim to handle every unit scenario but aims to grab the lion's share without introducing error-prone edge cases.  

Additionally, `postfixed_street` has been given an optional conform flag named `may_contain_units` which defaults to `false`.  The inclusion of this flag drives which regex to use when parsing a street.  For example, this conform ignores potential units:

```
{
    "function": "postfixed_street",
    "field": "ADDRESS"
}
```

and would parse the street as `Main Street` from `123 Main Street` and `Main Street Unit 3` from `123 Main Street Unit 3`.  With the inclusion of `may_contain_units`:

```
{
    "function": "postfixed_street",
    "field": "ADDRESS",
    "may_contain_units": true
}
```

the function would parse the street as `Main Street` from both `123 Main Street` and `123 Main Street Unit 3`.  

The downside of this approach is with this flag enabled, the street and unit extracted from `123 Main Unit Street` would be `Main` and `Unit Street`, respectively.  This situations are pretty rare, so `postfixed_unit` and the `may_contain_units` flag for `postfixed_street` should be used after examination of the data to ensure appropriate usage.  



Patch:
diff --git a/openaddr/conform.py b/openaddr/conform.py
index 5b1cc30..b1ea5fd 100644
--- a/openaddr/conform.py
+++ b/openaddr/conform.py
@@ -110,6 +110,40 @@ prefixed_number_pattern = re.compile("^\s*(\d+(?:[ -]\d/\d)?|\d+-\d+|\d+-?[A-Z])
 # like prefixed_number_pattern, this regex can be optimized but this is cleaner
 postfixed_street_pattern = re.compile("^(?:\s*(?:\d+(?:[ -]\d/\d)?|\d+-\d+|\d+-?[A-Z])\s+)?(.*)", re.IGNORECASE)
 
+# extracts:
+# - 'Main Street' from '123 Main Street Unit 3'
+# - 'Main Street' from '123 Main Street Apartment 3'
+# - 'Main Street' from '123 Main Street Apt 3'
+# - 'Main Street' from '123 Main Street Apt. 3'
+# - 'Main Street' from '123 Main Street Suite 3'
+# - 'Main Street' from '123 Main Street Ste 3'
+# - 'Main Street' from '123 Main Street Ste. 3'
+# - 'Main Street' from '123 Main Street Building 3'
+# - 'Main Street' from '123 Main Street Bldg 3'
+# - 'Main Street' from '123 Main Street Bldg. 3'
+# - 'Main Street' from '123 Main Street Lot 3'
+# - 'Main Street' from '123 Main Street #3'
+# - 'Main Street' from '123 Main Street # 3'
+# This regex contains 3 groups: optional house number, street, optional unit
+# only street is a matching group, house number and unit are non-matching
+postfixed_street_with_units_pattern = re.compile("^(?:\s*(?:\d+(?:[ -]\d/\d)?|\d+-\d+|\d+-?[A-Z])\s+)?(.+?)(?:\s+(?:(?:UNIT|APARTMENT|APT\.?|SUITE|STE\.?|BUILDING|BLDG\.?|LOT)\s+|#).+)?$", re.IGNORECASE)
+
+# extracts:
+# - 'Unit 3' from 'Main Street Unit 3'
+# - 'Apartment 3' from 'Main Street Apartment 3'
+# - 'Apt 3' from 'Main Street Apt 3'
+# - 'Apt. 3' from 'Main Street Apt. 3'
+# - 'Suite 3' from 'Main Street Suite 3'
+# - 'Ste 3' from 'Main Street Ste 3'
+# - 'Ste. 3' from 'Main Street Ste. 3'
+# - 'Building 3' from 'Main Street Building 3'
+# - 'Bldg 3' from 'Main Street Bldg 3'
+# - 'Bldg. 3' from 'Main Street Bldg. 3'
+# - 'Lot 3' from 'Main Street Lot 3'
+# - '#3' from 'Main Street #3'
+# - '# 3' from 'Main Street # 3'
+postfixed_unit_pattern = re.compile("\s((?:(?:UNIT|APARTMENT|APT\.?|SUITE|STE\.?|BUILDING|BLDG\.?|LOT)\s+|#).+)$", re.IGNORECASE)
+
 def mkdirsp(path):
     try:
         os.makedirs(path)
@@ -914,6 +948,8 @@ def row_function(sd, row, key, fxn):
         row = row_fxn_prefixed_number(sd, row, key, fxn)
     elif function == "postfixed_street":
         row = row_fxn_postfixed_street(sd, row, key, fxn)
+    elif function == "postfixed_unit":
+        row = row_fxn_postfixed_unit(sd, row, key, fxn)
     elif function == "remove_prefix":
         row = row_fxn_remove_prefix(sd, row, key, fxn)
     elif function == "remove_postfix":
@@ -1026,7 +1062,21 @@ def row_fxn_prefixed_number(sd, row, key, fxn):
 def row_fxn_postfixed_street(sd, row, key, fxn):
     "Extract 'Maple St' from '123 Maple St'"
 
-    match = postfixed_street_pattern.search(row[fxn["field"]])
+    may_contain_units = fxn.get('may_contain_units', False)
+
+    if may_contain_units:
+        match = postfixed_street_with_units_pattern.search(row[fxn["field"]])
+    else:
+        match = postfixed_street_pattern.search(row[fxn["field"]])
+    
+    row[var_types[key]] = ''.join(match.groups()) if match else '';
+
+    return row
+
+def row_fxn_postfixed_unit(sd, row, key, fxn):
+    "Extract 'Suite 300' from '123 Maple St Suite 300'"
+
+    match = postfixed_unit_pattern.search(row[fxn["field"]])
     row[var_types[key]] = ''.join(match.groups()) if match else '';
 
     return row


Test patch:
diff --git a/openaddr/tests/conform.py b/openaddr/tests/conform.py
index 9ecdec9..deb3244 100644
--- a/openaddr/tests/conform.py
+++ b/openaddr/tests/conform.py
@@ -18,6 +18,7 @@ from ..conform import (
     row_fxn_regexp, row_smash_case, row_round_lat_lon, row_merge,
     row_extract_and_reproject, row_convert_to_out, row_fxn_join, row_fxn_format,
     row_fxn_prefixed_number, row_fxn_postfixed_street,
+    row_fxn_postfixed_unit,
     row_fxn_remove_prefix, row_fxn_remove_postfix, row_fxn_chain,
     row_canonicalize_unit_and_number, conform_smash_case, conform_cli,
     convert_regexp_replace, conform_license,
@@ -348,7 +349,7 @@ class TestConformTransforms (unittest.TestCase):
         r = row_extract_and_reproject(d, {"LONG_WGS84": "-21,77", "LAT_WGS84": "64,11"})
         self.assertEqual({Y_FIELDNAME: "64.11", X_FIELDNAME: "-21.77"}, r)
 
-    def test_row_fxn_prefixed_number_and_postfixed_street(self):
+    def test_row_fxn_prefixed_number_and_postfixed_street_no_units(self):
         "Regex prefixed_number and postfix_street - both fields present"
         c = { "conform": {
             "number": {
@@ -710,6 +711,494 @@ class TestConformTransforms (unittest.TestCase):
         d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
         self.assertEqual(e, d)        
 
+        "contains unit but may_contain_units is not present"
+        c = { "conform": {
+            "number": {
+                "function": "prefixed_number",
+                "field": "ADDRESS"
+            },
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST UNIT 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:number": "123", "OA:street": "MAPLE ST UNIT 3" })
+        
+        d = row_fxn_prefixed_number(c, d, "number", c["conform"]["number"])
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "contains unit but may_contain_units is explicitly false"
+        c = { "conform": {
+            "number": {
+                "function": "prefixed_number",
+                "field": "ADDRESS"
+            },
+            "street": {
+                "function": "postfixed_street",
+                "may_contain_units": False,
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST UNIT 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:number": "123", "OA:street": "MAPLE ST UNIT 3" })
+        
+        d = row_fxn_prefixed_number(c, d, "number", c["conform"]["number"])
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+    def test_row_fxn_prefixed_number_and_postfixed_street_may_contain_units(self):
+        "UNIT-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST UNIT 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "APARTMENT-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST APARTMENT 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "APT-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST APT 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "APT.-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST APT. 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "SUITE-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST SUITE 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "STE-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST STE 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "STE.-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST STE. 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "BUILDING-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST BUILDING 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "BLDG-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST BLDG 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "BLDG.-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST BLDG. 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "LOT-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST LOT 3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "#-style unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST #3" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+        "no unit"
+        c = { "conform": {
+            "street": {
+                "function": "postfixed_street",
+                "field": "ADDRESS",
+                "may_contain_units": True
+            }
+        } }
+        d = { "ADDRESS": "123 MAPLE ST" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:street": "MAPLE ST" })
+
+        d = row_fxn_postfixed_street(c, d, "street", c["conform"]["street"])
+        self.assertEqual(e, d)        
+
+    def test_row_fxn_postfixed_unit(self): 
+        "postfixed_unit - UNIT-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Unit 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Unit 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+
+        "postfixed_unit - UNIT is word ending"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street runit 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+                
+        "postfixed_unit - APARTMENT-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Apartment 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Apartment 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - APT-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Apt 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Apt 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - APT is word ending"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street rapt 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - APT.-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Apt. 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Apt. 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - SUITE-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Suite 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Suite 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+
+        "postfixed_unit - STE-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Ste 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Ste 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+                
+        "postfixed_unit - STE is word ending"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Haste 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - STE.-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Ste. 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Ste. 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - BUILDING-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Building 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Building 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+
+        "postfixed_unit - BLDG-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Bldg 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Bldg 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - BLDG.-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Bldg. 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Bldg. 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - LOT-style"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street Lot 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "Lot 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+                
+        "postfixed_unit - LOT is word ending"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street alot 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - #-style with spaces"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street # 300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "# 300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+        
+        "postfixed_unit - #-style without spaces"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street #300" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "#300" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+
+        "postfixed_unit - no unit"
+        c = { "conform": {
+            "unit": {
+                "function": "postfixed_unit",
+                "field": "ADDRESS"
+            }
+        } }
+        d = { "ADDRESS": "Main Street" }
+        e = copy.deepcopy(d)
+        e.update({ "OA:unit": "" })
+        
+        d = row_fxn_postfixed_unit(c, d, "unit", c["conform"]["unit"])
+        self.assertEqual(e, d)        
+
     def test_row_fxn_remove_prefix(self):
         "remove_prefix - field_to_remove is a prefix"
         c = { "conform": {