Ejemplo n.º 1
0
    def test_species_diameter_and_height(self):
        s1_gsc = Species(instance=self.instance, genus='g1', species='s1',
                         cultivar='c1', max_height=30, max_diameter=19)
        s1_gs = Species(instance=self.instance, genus='g1', species='s1',
                        cultivar='', max_height=22, max_diameter=12)
        s1_gsc.save_with_system_user_bypass_auth()
        s1_gs.save_with_system_user_bypass_auth()

        row = {'point x': '16',
               'point y': '20',
               'genus': 'g1',
               'species': 's1',
               'diameter': '15',
               'tree height': '18'}

        i = self.mkrow(row)
        i.validate_row()

        self.assertHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertNotHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)

        row['tree height'] = 25
        i = self.mkrow(row)
        i.validate_row()

        self.assertHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)

        row['cultivar'] = 'c1'
        i = self.mkrow(row)
        i.validate_row()

        self.assertNotHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertNotHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)
Ejemplo n.º 2
0
    def test_species_diameter_and_height(self):
        s1_gsc = Species(
            instance=self.instance, genus="g1", species="s1", cultivar="c1", max_height=30, max_diameter=19
        )
        s1_gs = Species(instance=self.instance, genus="g1", species="s1", cultivar="", max_height=22, max_diameter=12)
        s1_gsc.save_with_system_user_bypass_auth()
        s1_gs.save_with_system_user_bypass_auth()

        row = {"point x": "16", "point y": "20", "genus": "g1", "species": "s1", "diameter": "15", "tree height": "18"}

        i = self.mkrow(row)
        i.validate_row()

        self.assertHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertNotHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)

        row["tree height"] = 25
        i = self.mkrow(row)
        i.validate_row()

        self.assertHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)

        row["cultivar"] = "c1"
        i = self.mkrow(row)
        i.validate_row()

        self.assertNotHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertNotHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)
Ejemplo n.º 3
0
    def test_species_diameter_and_height(self):
        s1_gsc = Species(instance=self.instance, genus='g1', species='s1',
                         cultivar='c1', max_height=30, max_diameter=19)
        s1_gs = Species(instance=self.instance, genus='g1', species='s1',
                        cultivar='', max_height=22, max_diameter=12)
        s1_gsc.save_with_system_user_bypass_auth()
        s1_gs.save_with_system_user_bypass_auth()

        row = {'point x': '16',
               'point y': '20',
               'genus': 'g1',
               'species': 's1',
               'diameter': '15',
               'tree height': '18'}

        i = self.mkrow(row)
        i.validate_row()

        self.assertHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertNotHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)

        row['tree height'] = 25
        i = self.mkrow(row)
        i.validate_row()

        self.assertHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)

        row['cultivar'] = 'c1'
        i = self.mkrow(row)
        i.validate_row()

        self.assertNotHasError(i, errors.SPECIES_DBH_TOO_HIGH)
        self.assertNotHasError(i, errors.SPECIES_HEIGHT_TOO_HIGH)
Ejemplo n.º 4
0
    def test_faulty_data1(self):
        s1_g = Species(instance=self.instance, genus="g1", species="", cultivar="", max_diameter=50.0, max_height=100.0)
        s1_g.save_with_system_user_bypass_auth()

        # TODO: READONLY restore when implemented
        # csv = """
        # | point x | point y | diameter | read only | genus | tree height |
        # | -34.2   | 24.2    | q12      | true      |       |             |
        # | 323     | 23.2    | 14       | falseo    |       |             |
        # | 32.1    | 22.4    | 15       | true      |       |             |
        # | 33.2    | 19.1    | 32       | true      |       |             |
        # | 33.2    | q19.1   | -33.3    | true      | gfail |             |
        # | 32.1    | 12.1    |          | false     | g1    | 200         |
        # | 32.1    | 12.1    | 300      | false     | g1    |             |
        # """
        csv = """
        | point x | point y | diameter | genus | tree height |
        | -34.2   | 24.2    | q12      |       |             |
        | 323     | 23.2    | 14       |       |             |
        | 32.1    | 22.4    | 15       |       |             |
        | 33.2    | 19.1    | 32       |       |             |
        | 33.2    | q19.1   | -33.3    | gfail |             |
        | 32.1    | 12.1    |          | g1    | 200         |
        | 32.1    | 12.1    | 300      | g1    |             |
        """

        gflds = [fields.trees.POINT_X, fields.trees.POINT_Y]
        sflds = [
            fields.trees.GENUS,
            fields.trees.SPECIES,
            fields.trees.CULTIVAR,
            fields.trees.OTHER_PART_OF_NAME,
            fields.trees.COMMON_NAME,
        ]

        j = self.run_through_process_views(csv)
        ierrors = self.extract_errors(j)
        self.assertEqual(ierrors["0"], [(errors.FLOAT_ERROR[0], [fields.trees.DIAMETER], None)])

        # TODO: READONLY restore when implemented
        # self.assertEqual(ierrors['1'],
        #                  [(errors.BOOL_ERROR[0],
        #                    [fields.trees.READ_ONLY], None),
        #                   (errors.INVALID_GEOM[0], gflds, None)])
        self.assertEqual(ierrors["1"], [(errors.INVALID_GEOM[0], gflds, None)])

        self.assertNotIn("2", ierrors)
        self.assertNotIn("3", ierrors)
        self.assertEqual(
            ierrors["4"],
            [
                (errors.POS_FLOAT_ERROR[0], [fields.trees.DIAMETER], None),
                (errors.FLOAT_ERROR[0], [fields.trees.POINT_Y], None),
                (errors.MISSING_FIELD[0], gflds, None),
                (errors.INVALID_SPECIES[0], sflds, "gfail"),
            ],
        )
        self.assertEqual(ierrors["5"], [(errors.SPECIES_HEIGHT_TOO_HIGH[0], [fields.trees.TREE_HEIGHT], 100.0)])
        self.assertEqual(ierrors["6"], [(errors.SPECIES_DBH_TOO_HIGH[0], [fields.trees.DIAMETER], 50.0)])
Ejemplo n.º 5
0
    def test_faulty_data1(self):
        s1_g = Species(instance=self.instance, genus='g1', species='',
                       cultivar='', max_diameter=50.0, max_height=100.0)
        s1_g.save_with_system_user_bypass_auth()

        csv = """
        | point x | point y | diameter | read only | genus | tree height |
        | -34.2   | 24.2    | q12      | true      |       |             |
        | 323     | 23.2    | 14       | falseo    |       |             |
        | 32.1    | 22.4    | 15       | true      |       |             |
        | 33.2    | 19.1    | 32       | true      |       |             |
        | 33.2    | q19.1   | -33.3    | true      | gfail |             |
        | 32.1    | 12.1    |          | false     | g1    | 200         |
        | 32.1    | 12.1    | 300      | false     | g1    |             |
        """

        gflds = [fields.trees.POINT_X, fields.trees.POINT_Y]
        sflds = [fields.trees.GENUS, fields.trees.SPECIES,
                 fields.trees.CULTIVAR]

        j = self.run_through_process_views(csv)
        ierrors = self.extract_errors(j)
        self.assertEqual(ierrors['0'],
                         [(errors.FLOAT_ERROR[0],
                           [fields.trees.DIAMETER], None)])

        self.assertEqual(ierrors['1'],
                         [(errors.BOOL_ERROR[0],
                           [fields.trees.READ_ONLY], None),
                          (errors.INVALID_GEOM[0], gflds, None)])
        self.assertNotIn('2', ierrors)
        self.assertNotIn('3', ierrors)
        self.assertEqual(ierrors['4'],
                         [(errors.POS_FLOAT_ERROR[0],
                           [fields.trees.DIAMETER], None),
                          (errors.FLOAT_ERROR[0],
                           [fields.trees.POINT_Y], None),
                          (errors.MISSING_FIELD[0], gflds, None),
                          (errors.INVALID_SPECIES[0], sflds, 'gfail')])
        self.assertEqual(ierrors['5'],
                         [(errors.SPECIES_HEIGHT_TOO_HIGH[0],
                           [fields.trees.TREE_HEIGHT], 100.0)])
        self.assertEqual(ierrors['6'],
                         [(errors.SPECIES_DBH_TOO_HIGH[0],
                           [fields.trees.DIAMETER], 50.0)])
Ejemplo n.º 6
0
Archivo: tests.py Proyecto: gapb/OTM2
    def test_common_name_matching(self):
        apple = Species(instance=self.instance,
                        genus='malus',
                        common_name='Apple')
        apple.save_with_system_user_bypass_auth()
        csv = """
        | point x | point y | genus | common name |
        | 45.59   | 31.1    | malus | apple       |
        | 45.58   | 33.9    | malus | crab apple  |
        | 45.58   | 33.9    | malus |             |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        rows = ie.treeimportrow_set.order_by('idx').all()
        tree1 = rows[0].plot.current_tree()
        tree3 = rows[2].plot.current_tree()

        self.assertEqual(tree1.species.pk, apple.pk)
        self.assertIsNone(rows[1].plot)
        self.assertEqual(tree3.species.pk, apple.pk)

        # If we add a species, there will be more than one match for "malus"
        csv = """
        | point x | point y | genus | common name |
        | 45.49   | 31.1    | malus | apple       |
        | 45.48   | 33.9    | malus | crab apple  |
        | 45.48   | 33.9    | malus |             |
        """
        crab_apple = Species(instance=self.instance,
                             genus='malus',
                             common_name='Crab Apple')
        crab_apple.save_with_system_user_bypass_auth()

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        rows = ie.treeimportrow_set.order_by('idx').all()
        tree1 = rows[0].plot.current_tree()
        tree2 = rows[1].plot.current_tree()

        self.assertEqual(tree1.species.pk, apple.pk)
        self.assertEqual(tree2.species.pk, crab_apple.pk)
        self.assertIsNone(rows[2].plot)
Ejemplo n.º 7
0
    def test_common_name_matching(self):
        apple = Species(instance=self.instance, genus='malus',
                        common_name='Apple')
        apple.save_with_system_user_bypass_auth()
        csv = """
        | point x | point y | genus | common name |
        | 45.59   | 31.1    | malus | apple       |
        | 45.58   | 33.9    | malus | crab apple  |
        | 45.58   | 33.9    | malus |             |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        rows = ie.treeimportrow_set.order_by('idx').all()
        tree1 = rows[0].plot.current_tree()
        tree3 = rows[2].plot.current_tree()

        self.assertEqual(tree1.species.pk, apple.pk)
        self.assertIsNone(rows[1].plot)
        self.assertEqual(tree3.species.pk, apple.pk)

        # If we add a species, there will be more than one match for "malus"
        csv = """
        | point x | point y | genus | common name |
        | 45.49   | 31.1    | malus | apple       |
        | 45.48   | 33.9    | malus | crab apple  |
        | 45.48   | 33.9    | malus |             |
        """
        crab_apple = Species(instance=self.instance, genus='malus',
                             common_name='Crab Apple')
        crab_apple.save_with_system_user_bypass_auth()

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        rows = ie.treeimportrow_set.order_by('idx').all()
        tree1 = rows[0].plot.current_tree()
        tree2 = rows[1].plot.current_tree()

        self.assertEqual(tree1.species.pk, apple.pk)
        self.assertEqual(tree2.species.pk, crab_apple.pk)
        self.assertIsNone(rows[2].plot)
Ejemplo n.º 8
0
    def test_all_tree_data(self):
        s1_gsc = Species(instance=self.instance, genus='g1', species='s1',
                         cultivar='c1')
        s1_gsc.save_with_system_user_bypass_auth()

        csv = """
        | point x | point y | diameter | tree height |
        | 45.53   | 31.1    | 23.1     | 90.1        |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        tree = ie.treeimportrow_set.all()[0].plot.current_tree()

        self.assertEqual(tree.diameter, 23.1)
        self.assertEqual(tree.height, 90.1)

        csv = """
        | point x | point y | canopy height | genus | species | cultivar |
        | 45.59   | 31.1    | 112           |       |         |          |
        | 45.58   | 33.9    |               | g1    | s1      | c1       |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        rows = ie.treeimportrow_set.order_by('idx').all()
        tree1 = rows[0].plot.current_tree()
        tree2 = rows[1].plot.current_tree()

        self.assertEqual(tree1.canopy_height, 112)
        self.assertIsNone(tree1.species)

        self.assertEqual(tree2.species.pk, s1_gsc.pk)

        # TODO: READONLY restore when implemented
        # csv = """
        # | point x | point y | date planted | read only |
        # | 25.00   | 25.00   | 2012-02-03   | true      |
        # """
        csv = """
        | point x | point y | date planted |
        | 25.00   | 25.00   | 2012-02-03   |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        tree = ie.treeimportrow_set.all()[0].plot.current_tree()

        dateplanted = date(2012, 2, 3)

        self.assertEqual(tree.date_planted, dateplanted)
        # TODO: READONLY restore when implemented
        # self.assertEqual(tree.readonly, True)

        psycopg2.extras.register_hstore(connection.cursor(), globally=True)

        UserDefinedFieldDefinition.objects.create(
            model_type='Plot',
            name='Flatness',
            datatype=json.dumps({'type': 'choice',
                                 'choices': ['very', 'hardly', 'not']}),
            iscollection=False,
            instance=self.instance,
        )

        UserDefinedFieldDefinition.objects.create(
            model_type='Tree',
            name='Cuteness',
            datatype=json.dumps({'type': 'choice',
                                 'choices': ['lots', 'not much', 'none']}),
            iscollection=False,
            instance=self.instance,
        )

        csv = """
        | point x | point y | tree: cuteness | plot: flatness |
        | 26.00   | 26.00   | not much       | very           |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        plot = ie.treeimportrow_set.all()[0].plot
        tree = plot.current_tree()

        self.assertEqual(plot.udfs['Flatness'], 'very')
        self.assertEqual(tree.udfs['Cuteness'], 'not much')
Ejemplo n.º 9
0
    def commit_row(self):
        is_valid = self.validate_row()

        if not is_valid or not self.merged:
            return  # not ready to commit

        if self.status == SpeciesImportRow.SUCCESS:
            return  # nothing changed so no need to commit

        # Get our data
        data = self.cleaned

        species_edited = False

        # Initially grab species from row if it exists and edit it
        species = self.species

        # If not specified create a new one
        if species is None:
            species = Species(instance=self.import_event.instance)

        # Convert units
        self.convert_units(data, {
            fields.species.MAX_DIAMETER:
            self.import_event.max_diameter_conversion_factor,

            fields.species.MAX_HEIGHT:
            self.import_event.max_tree_height_conversion_factor
        })

        for modelkey, datakey in SpeciesImportRow.SPECIES_MAP.iteritems():
            importdata = data.get(datakey, None)

            if importdata is not None:
                species_edited = True
                setattr(species, modelkey, importdata)

        # Set OTM code if missing and available
        if not species.otm_code:
            species_dict = species_for_scientific_name(
                species.genus, species.species, species.cultivar,
                species.other_part_of_name)
            if species_dict:
                species_edited = True
                species.otm_code = species_dict['otm_code']

        if species_edited:
            species.save_with_system_user_bypass_auth()

        # Make i-Tree code override(s) if necessary
        if fields.species.ITREE_PAIRS in data:
            for region_code, itree_code in data[fields.species.ITREE_PAIRS]:

                if itree_code != species.get_itree_code(region_code):

                    override = ITreeCodeOverride.objects.get_or_create(
                        instance_species=species,
                        region=ITreeRegion.objects.get(code=region_code),
                    )[0]
                    override.itree_code = itree_code
                    override.save_with_user(User.system_user())

        self.species = species
        self.status = SpeciesImportRow.SUCCESS
        self.save()
Ejemplo n.º 10
0
Archivo: tests.py Proyecto: gapb/OTM2
    def test_all_tree_data(self):
        s1_gsc = Species(instance=self.instance,
                         genus='g1',
                         species='s1',
                         cultivar='c1')
        s1_gsc.save_with_system_user_bypass_auth()

        csv = """
        | point x | point y | diameter | tree height |
        | 45.53   | 31.1    | 23.1     | 90.1        |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        tree = ie.treeimportrow_set.all()[0].plot.current_tree()

        self.assertEqual(tree.diameter, 23.1)
        self.assertEqual(tree.height, 90.1)

        csv = """
        | point x | point y | canopy height | genus | species | cultivar |
        | 45.59   | 31.1    | 112           |       |         |          |
        | 45.58   | 33.9    |               | g1    | s1      | c1       |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        rows = ie.treeimportrow_set.order_by('idx').all()
        tree1 = rows[0].plot.current_tree()
        tree2 = rows[1].plot.current_tree()

        self.assertEqual(tree1.canopy_height, 112)
        self.assertIsNone(tree1.species)

        self.assertEqual(tree2.species.pk, s1_gsc.pk)

        # TODO: READONLY restore when implemented
        # csv = """
        # | point x | point y | date planted | read only |
        # | 25.00   | 25.00   | 2012-02-03   | true      |
        # """
        csv = """
        | point x | point y | date planted |
        | 25.00   | 25.00   | 2012-02-03   |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        tree = ie.treeimportrow_set.all()[0].plot.current_tree()

        dateplanted = date(2012, 2, 3)

        self.assertEqual(tree.date_planted, dateplanted)
        # TODO: READONLY restore when implemented
        # self.assertEqual(tree.readonly, True)

        psycopg2.extras.register_hstore(connection.cursor(), globally=True)

        UserDefinedFieldDefinition.objects.create(
            model_type='Plot',
            name='Flatness',
            datatype=json.dumps({
                'type': 'choice',
                'choices': ['very', 'hardly', 'not']
            }),
            iscollection=False,
            instance=self.instance,
        )

        UserDefinedFieldDefinition.objects.create(
            model_type='Tree',
            name='Cuteness',
            datatype=json.dumps({
                'type': 'choice',
                'choices': ['lots', 'not much', 'none']
            }),
            iscollection=False,
            instance=self.instance,
        )

        csv = """
        | point x | point y | tree: cuteness | plot: flatness |
        | 26.00   | 26.00   | not much       | very           |
        """

        ieid = self.run_through_commit_views(csv)
        ie = TreeImportEvent.objects.get(pk=ieid)
        plot = ie.treeimportrow_set.all()[0].plot
        tree = plot.current_tree()

        self.assertEqual(plot.udfs['Flatness'], 'very')
        self.assertEqual(tree.udfs['Cuteness'], 'not much')
Ejemplo n.º 11
0
Archivo: tests.py Proyecto: gapb/OTM2
    def test_faulty_data1(self):
        s1_g = Species(instance=self.instance,
                       genus='g1',
                       species='',
                       cultivar='',
                       max_diameter=50.0,
                       max_height=100.0)
        s1_g.save_with_system_user_bypass_auth()

        # TODO: READONLY restore when implemented
        # csv = """
        # | point x | point y | diameter | read only | genus | tree height |
        # | -34.2   | 24.2    | q12      | true      |       |             |
        # | 323     | 23.2    | 14       | falseo    |       |             |
        # | 32.1    | 22.4    | 15       | true      |       |             |
        # | 33.2    | 19.1    | 32       | true      |       |             |
        # | 33.2    | q19.1   | -33.3    | true      | gfail |             |
        # | 32.1    | 12.1    |          | false     | g1    | 200         |
        # | 32.1    | 12.1    | 300      | false     | g1    |             |
        # """
        csv = """
        | point x | point y | diameter | genus | tree height |
        | -34.2   | 24.2    | q12      |       |             |
        | 323     | 23.2    | 14       |       |             |
        | 32.1    | 22.4    | 15       |       |             |
        | 33.2    | 19.1    | 32       |       |             |
        | 33.2    | q19.1   | -33.3    | gfail |             |
        | 32.1    | 12.1    |          | g1    | 200         |
        | 32.1    | 12.1    | 300      | g1    |             |
        """

        gflds = [fields.trees.POINT_X, fields.trees.POINT_Y]
        sflds = [
            fields.trees.GENUS, fields.trees.SPECIES, fields.trees.CULTIVAR,
            fields.trees.OTHER_PART_OF_NAME, fields.trees.COMMON_NAME
        ]

        j = self.run_through_process_views(csv)
        ierrors = self.extract_errors(j)
        self.assertEqual(
            ierrors['0'],
            [(errors.FLOAT_ERROR[0], [fields.trees.DIAMETER], None)])

        # TODO: READONLY restore when implemented
        # self.assertEqual(ierrors['1'],
        #                  [(errors.BOOL_ERROR[0],
        #                    [fields.trees.READ_ONLY], None),
        #                   (errors.INVALID_GEOM[0], gflds, None)])
        self.assertEqual(ierrors['1'], [(errors.INVALID_GEOM[0], gflds, None)])

        self.assertNotIn('2', ierrors)
        self.assertNotIn('3', ierrors)
        self.assertEqual(
            ierrors['4'],
            [(errors.POS_FLOAT_ERROR[0], [fields.trees.DIAMETER], None),
             (errors.FLOAT_ERROR[0], [fields.trees.POINT_Y], None),
             (errors.MISSING_FIELD[0], gflds, None),
             (errors.INVALID_SPECIES[0], sflds, 'gfail')])
        self.assertEqual(ierrors['5'], [(errors.SPECIES_HEIGHT_TOO_HIGH[0],
                                         [fields.trees.TREE_HEIGHT], 100.0)])
        self.assertEqual(
            ierrors['6'],
            [(errors.SPECIES_DBH_TOO_HIGH[0], [fields.trees.DIAMETER], 50.0)])
Ejemplo n.º 12
0
    def commit_row(self):
        is_valid = self.validate_row()

        if not is_valid or not self.merged:
            return  # not ready to commit

        if self.status == SpeciesImportRow.SUCCESS:
            return  # nothing changed so no need to commit

        # Get our data
        data = self.cleaned

        species_edited = False

        # Initially grab species from row if it exists and edit it
        species = self.species

        # If not specified create a new one
        if species is None:
            species = Species(instance=self.import_event.instance)

        # Convert units
        self.convert_units(
            data, {
                fields.species.MAX_DIAMETER:
                self.import_event.max_diameter_conversion_factor,
                fields.species.MAX_HEIGHT:
                self.import_event.max_tree_height_conversion_factor
            })

        for modelkey, datakey in SpeciesImportRow.SPECIES_MAP.iteritems():
            importdata = data.get(datakey, None)

            if importdata is not None:
                species_edited = True
                setattr(species, modelkey, importdata)

        # Set OTM code if missing and available
        if not species.otm_code:
            species_dict = species_for_scientific_name(
                species.genus, species.species, species.cultivar,
                species.other_part_of_name)
            if species_dict:
                species_edited = True
                species.otm_code = species_dict['otm_code']

        if species_edited:
            species.save_with_system_user_bypass_auth()

        # Make i-Tree code override(s) if necessary
        if fields.species.ITREE_PAIRS in data:
            for region_code, itree_code in data[fields.species.ITREE_PAIRS]:

                if itree_code != species.get_itree_code(region_code):

                    override = ITreeCodeOverride.objects.get_or_create(
                        instance_species=species,
                        region=ITreeRegion.objects.get(code=region_code),
                    )[0]
                    override.itree_code = itree_code
                    override.save_with_user(User.system_user())

        self.species = species
        self.status = SpeciesImportRow.SUCCESS
        self.save()