Example #1
0
    def parse(self, value):
        if type(value) in [list, tuple]:
            if all([isinstance(element, dict) for element in value]):
                for ii, element in enumerate(value, start=1):
                    if 'geom' not in element:
                        ocgis_lh(exc=DefinitionValidationError(self, 'Geometry dictionaries must have a "geom" key.'))
                    if 'properties' not in element:
                        element['properties'] = {self._ugid_key: ii}
                    crs = element.get('crs', constants.UNINITIALIZED)
                    if 'crs' not in element:
                        ocgis_lh(msg='No CRS in geometry dictionary - assuming WGS84.', level=logging.WARN)
                ret = Field.from_records(value, crs=crs, uid=self.geom_uid, union=self.union,
                                         data_model=self.data_model)
            else:
                if len(value) == 2:
                    geom = Point(value[0], value[1])
                elif len(value) == 4:
                    minx, miny, maxx, maxy = value
                    geom = Polygon(((minx, miny), (minx, maxy), (maxx, maxy), (maxx, miny)))
                if not geom.is_valid:
                    raise DefinitionValidationError(self, 'Parsed geometry is not valid.')
                ret = [{'geom': geom, 'properties': {self._ugid_key: 1}}]
                ret = Field.from_records(ret, uid=self.geom_uid, union=self.union, data_model=self.data_model)
                self._bounds = geom.bounds
        elif isinstance(value, GeomCabinetIterator):
            self._shp_key = value.key or value.path
            # Always yield fields.
            value.as_field = True
            ret = value
        elif isinstance(value, BaseGeometry):
            ret = [{'geom': value, 'properties': {self._ugid_key: 1}}]
            ret = Field.from_records(ret, uid=self.geom_uid, union=self.union, data_model=self.data_model)
        elif value is None:
            ret = value
        elif isinstance(value, Field):
            ret = value
        elif isinstance(value, GeometryVariable):
            if value.ugid is None:
                msg = 'Geometry variables must have an associated "UGID".'
                raise DefinitionValidationError(self, msg)
            ret = Field(geom=value, crs=value.crs)
        else:
            raise NotImplementedError(type(value))

        # Convert to singular field if this is a field object.
        if isinstance(ret, Field):
            ret = tuple(self._iter_singular_fields_(ret))

        return ret
Example #2
0
 def test_from_records(self):
     gci = GeomCabinetIterator(path=self.path_state_boundaries)
     actual = Field.from_records(gci, data_model='NETCDF3_CLASSIC')
     desired = {'UGID': np.int32,
                'ID': np.int32}
     for v in desired.keys():
         self.assertEqual(actual[v].get_value().dtype, desired[v])
Example #3
0
 def _run_():
     env.SUPPRESS_WARNINGS = False
     ocgis_lh.configure(to_stream=True)
     records = [{
         'geom': Point(1, 2),
         'properties': {
             'a_list': [1, 2, 3]
         }
     }]
     actual = Field.from_records(records)
     self.assertNotIn("a_list", actual.keys())
     env.SUPPRESS_WARNINGS = True
Example #4
0
    def test_from_records(self):
        gci = GeomCabinetIterator(path=self.path_state_boundaries)
        actual = Field.from_records(gci, data_model='NETCDF3_CLASSIC')
        desired = {'UGID': np.int32, 'ID': np.int32}
        for v in desired.keys():
            self.assertEqual(actual[v].get_value().dtype, desired[v])

        # Test strictness with list/tuple

        def _run_():
            env.SUPPRESS_WARNINGS = False
            ocgis_lh.configure(to_stream=True)
            records = [{
                'geom': Point(1, 2),
                'properties': {
                    'a_list': [1, 2, 3]
                }
            }]
            actual = Field.from_records(records)
            self.assertNotIn("a_list", actual.keys())
            env.SUPPRESS_WARNINGS = True

        self.assertWarns(OcgWarning, _run_)
Example #5
0
    def iter_geoms(self,
                   key=None,
                   select_uid=None,
                   path=None,
                   load_geoms=True,
                   as_field=False,
                   uid=None,
                   select_sql_where=None,
                   slc=None,
                   union=False,
                   data_model=None,
                   driver_kwargs=None):
        """
        See documentation for :class:`~ocgis.GeomCabinetIterator`.
        """

        # Get the path to the output shapefile.
        shp_path = self._get_path_by_key_or_direct_path_(key=key, path=path)

        # Get the source metadata.
        meta = self.get_meta(path=shp_path, driver_kwargs=driver_kwargs)

        if union:
            gic = GeomCabinetIterator(key=key,
                                      select_uid=select_uid,
                                      path=path,
                                      load_geoms=load_geoms,
                                      as_field=False,
                                      uid=uid,
                                      select_sql_where=select_sql_where,
                                      slc=slc,
                                      union=False,
                                      data_model=data_model,
                                      driver_kwargs=driver_kwargs)
            yld = Field.from_records(gic,
                                     meta['schema'],
                                     crs=meta['crs'],
                                     uid=uid,
                                     union=True,
                                     data_model=data_model)
            yield yld
        else:
            if slc is not None and (select_uid is not None
                                    or select_sql_where is not None):
                exc = ValueError(
                    'Slice is not allowed with other select statements.')
                ocgis_lh(exc=exc, logger='geom_cabinet')

            # Format the slice for iteration. We will get the features by index if a slice is provided.
            if slc is not None:
                slc = get_index_slice_for_iteration(slc)

            # Open the target geometry file.
            ds = ogr.Open(shp_path)
            try:
                # Return the features iterator.
                features = self._get_features_object_(
                    ds,
                    uid=uid,
                    select_uid=select_uid,
                    select_sql_where=select_sql_where,
                    driver_kwargs=driver_kwargs)

                # Using slicing, we will select the features individually from the object.
                if slc is None:
                    itr = features
                else:
                    # The geodatabase API requires iterations to get the given location.
                    if self.get_gdal_driver(
                            shp_path) == 'OpenFileGDB' or isinstance(
                                slc, slice):

                        def _o_itr_(features_object, slice_start, slice_stop):
                            for ctr2, fb in enumerate(features_object):
                                # ... iterate until start is reached.
                                if ctr2 < slice_start:
                                    continue
                                # ... stop if we have reached the stop.
                                elif ctr2 == slice_stop:
                                    return
                                yield fb

                        itr = _o_itr_(features, slc.start, slc.stop)
                    else:
                        # Convert the slice index to an integer to avoid type conflict in GDAL layer.
                        itr = (features.GetFeature(int(idx)) for idx in slc)

                # Convert feature objects to record dictionaries.
                for ctr, feature in enumerate(itr):
                    if load_geoms:
                        yld = {
                            'geom': wkb.loads(feature.geometry().ExportToWkb())
                        }
                    else:
                        yld = {}
                    items = feature.items()
                    properties = OrderedDict([(key, items[key])
                                              for key in feature.keys()])
                    yld.update({'properties': properties, 'meta': meta})

                    if ctr == 0:
                        uid, add_uid = get_uid_from_properties(properties, uid)
                        # The properties schema needs to be updated to account for the adding of a unique identifier.
                        if add_uid:
                            meta['schema']['properties'][uid] = 'int'

                    # Add the unique identifier if required
                    if add_uid:
                        properties[uid] = feature.GetFID()
                    # Ensure the unique identifier is an integer
                    else:
                        properties[uid] = int(properties[uid])

                    if as_field:
                        yld = Field.from_records([yld],
                                                 schema=meta['schema'],
                                                 crs=yld['meta']['crs'],
                                                 uid=uid,
                                                 data_model=data_model)

                    yield yld
                try:
                    assert ctr >= 0
                except UnboundLocalError:
                    # occurs if there were not feature returned by the iterator. raise a more clear exception.
                    msg = 'No features returned from target data source. Were features appropriately selected?'
                    raise ValueError(msg)
            finally:
                # Close or destroy the data source object if it actually exists.
                if ds is not None:
                    ds.Destroy()
                    ds = None
Example #6
0
    def parse(self, value):
        if type(value) in [list, tuple]:
            if all([isinstance(element, dict) for element in value]):
                for ii, element in enumerate(value, start=1):
                    if 'geom' not in element:
                        ocgis_lh(exc=DefinitionValidationError(
                            self,
                            'Geometry dictionaries must have a "geom" key.'))
                    if 'properties' not in element:
                        element['properties'] = {self._ugid_key: ii}
                    crs = element.get('crs', constants.UNINITIALIZED)
                    if 'crs' not in element:
                        ocgis_lh(
                            msg=
                            'No CRS in geometry dictionary - assuming WGS84.',
                            level=logging.WARN)
                ret = Field.from_records(value,
                                         crs=crs,
                                         uid=self.geom_uid,
                                         union=self.union,
                                         data_model=self.data_model)
            else:
                if len(value) == 2:
                    geom = Point(value[0], value[1])
                elif len(value) == 4:
                    minx, miny, maxx, maxy = value
                    geom = Polygon(((minx, miny), (minx, maxy), (maxx, maxy),
                                    (maxx, miny)))
                if not geom.is_valid:
                    raise DefinitionValidationError(
                        self, 'Parsed geometry is not valid.')
                ret = [{'geom': geom, 'properties': {self._ugid_key: 1}}]
                ret = Field.from_records(ret,
                                         uid=self.geom_uid,
                                         union=self.union,
                                         data_model=self.data_model)
                self._bounds = geom.bounds
        elif isinstance(value, GeomCabinetIterator):
            self._shp_key = value.key or value.path
            # Always yield fields.
            value.as_field = True
            ret = value
        elif isinstance(value, BaseGeometry):
            ret = [{'geom': value, 'properties': {self._ugid_key: 1}}]
            ret = Field.from_records(ret,
                                     uid=self.geom_uid,
                                     union=self.union,
                                     data_model=self.data_model)
        elif value is None:
            ret = value
        elif isinstance(value, Field):
            ret = value
        elif isinstance(value, GeometryVariable):
            if value.ugid is None:
                msg = 'Geometry variables must have an associated "UGID".'
                raise DefinitionValidationError(self, msg)
            ret = Field(geom=value, crs=value.crs)
        else:
            raise NotImplementedError(type(value))

        # Convert to singular field if this is a field object.
        if isinstance(ret, Field):
            ret = tuple(self._iter_singular_fields_(ret))

        return ret