Example #1
0
    def write(self):
        ocgis_lh('starting write method',self._log,logging.DEBUG)
        
        unique_geometry_store = []

        # indicates if user geometries should be written to file
        write_ugeom = False
        
        try:
            build = True

            for coll in iter(self.colls):
                if build:

                    # write the user geometries if configured and there is one present on the incoming collection.
                    if self._add_ugeom and coll.geoms.values()[0] is not None:
                        write_ugeom = True

                    f = self._build_(coll)
                    if write_ugeom:
                        ugid_shp_name = self.prefix + '_ugid.shp'
                        ugid_csv_name = self.prefix + '_ugid.csv'
                        
                        if self._add_ugeom_nest:
                            fiona_path = os.path.join(self._get_or_create_shp_folder_(),ugid_shp_name)
                            csv_path = os.path.join(self._get_or_create_shp_folder_(),ugid_csv_name)
                        else:
                            fiona_path = os.path.join(self.outdir,ugid_shp_name)
                            csv_path = os.path.join(self.outdir,ugid_csv_name)

                        if coll.meta is None:
                            # convert the collection properties to fiona properties
                            from fiona_ import FionaConverter
                            fiona_properties = {}
                            for k, v in coll.properties.values()[0].iteritems():
                                fiona_properties[k] = FionaConverter.get_field_type(type(v))

                            fiona_schema = {'geometry':'MultiPolygon',
                                            'properties':fiona_properties}
                            fiona_meta = {'schema':fiona_schema,'driver':'ESRI Shapefile'}
                        else:
                            fiona_meta = coll.meta
                            
                        ## always use the CRS from the collection. shapefile metadata
                        ## will always be WGS84, but it may be overloaded in the
                        ## operations.
                        fiona_meta['crs'] = coll.crs.value
                        
                        ## always upper for the properties definition as this happens
                        ## for each record.
                        fiona_meta['schema']['properties'] = {k.upper():v for k,v in fiona_meta['schema']['properties'].iteritems()}
                        
                        ## selection geometries will always come out as MultiPolygon
                        ## regardless if they began as points. points are buffered
                        ## during the subsetting process.
                        fiona_meta['schema']['geometry'] = 'MultiPolygon'

                        fiona_object = fiona.open(fiona_path,'w',**fiona_meta)
                        csv_file = open(csv_path,'w')
                        
                        from ocgis.conv.csv_ import OcgDialect
                        csv_object = DictWriter(csv_file,fiona_meta['schema']['properties'].keys(),dialect=OcgDialect)
                        csv_object.writeheader()
                        
                    build = False
                self._write_coll_(f,coll)
                if write_ugeom:
                    ## write the overview geometries to disk
                    r_geom = coll.geoms.values()[0]
                    if isinstance(r_geom,Polygon):
                        r_geom = MultiPolygon([r_geom])
                    ## see if this geometry is in the unique geometry store
                    should_append = self._get_should_append_to_unique_geometry_store_(
                     unique_geometry_store,
                     r_geom,
                     coll.properties.values()[0]['UGID'])
                    if should_append:
                        unique_geometry_store.append({'geom':r_geom,
                                                      'ugid':coll.properties.values()[0]['UGID']})
                    
                        ## if it is unique write the geometry to the output files
                        to_write = {'geometry':mapping(r_geom),
                                    'properties':{k.upper():v for k,v in coll.properties.values()[0].iteritems()}}
                        fiona_object.write(to_write)
                        
                        ## write the geometry attributes to the corresponding shapefile
                        for row in coll.properties.itervalues():
                            csv_object.writerow({k.upper():v for k,v in row.iteritems()})
                    
        finally:
            
            ## errors are masked if the processing failed and file objects, etc.
            ## were not properly created. if there are UnboundLocalErrors pass
            ## them through to capture the error that lead to the objects not
            ## being created.
            
            try:
                try:
                    self._finalize_(f)
                except UnboundLocalError:
                    pass
            except Exception as e:
                ## this the exception we want to log
                ocgis_lh(exc=e,logger=self._log)
            finally:
                if write_ugeom:
                    try:
                        fiona_object.close()
                    except UnboundLocalError:
                        pass
                    try:
                        csv_file.close()
                    except UnboundLocalError:
                        pass
        
        ## the metadata and dataset descriptor files may only be written if
        ## OCGIS operations are present.
        if self.ops is not None and self.add_auxiliary_files == True:
            ## added OCGIS metadata output if requested.
            if self.add_meta:
                ocgis_lh('adding OCGIS metadata file','conv',logging.DEBUG)
                lines = MetaConverter(self.ops).write()
                out_path = os.path.join(self.outdir,self.prefix+'_'+MetaConverter._meta_filename)
                with open(out_path,'w') as f:
                    f.write(lines)
            
            ## add the dataset descriptor file if specified and OCGIS operations
            ## are present.
            if self._add_did_file:
                ocgis_lh('writing dataset description (DID) file','conv',logging.DEBUG)
                from ocgis.conv.csv_ import OcgDialect
                
                headers = ['DID','VARIABLE','ALIAS','URI','STANDARD_NAME','UNITS','LONG_NAME']
                out_path = os.path.join(self.outdir,self.prefix+'_did.csv')
                with open(out_path,'w') as f:
                    writer = csv.writer(f,dialect=OcgDialect)
                    writer.writerow(headers)
                    for rd in self.ops.dataset.itervalues():
                        for d in rd:
                            row = [rd.did,d['variable'],d['alias'],rd.uri]
                            ref_variable = rd.source_metadata['variables'][d['variable']]['attrs']
                            row.append(ref_variable.get('standard_name',None))
                            row.append(ref_variable.get('units',None))
                            row.append(ref_variable.get('long_name',None))
                            writer.writerow(row)
                
            ## add source metadata if requested
            if self._add_source_meta:
                ocgis_lh('writing source metadata file','conv',logging.DEBUG)
                out_path = os.path.join(self.outdir,self.prefix+'_source_metadata.txt')
                to_write = []
                for rd in self.ops.dataset.itervalues():
                    ip = Inspect(meta=rd.source_metadata, uri=rd.uri)
                    to_write += ip.get_report_no_variable()
                with open(out_path,'w') as f:
                    f.writelines('\n'.join(to_write))
        
        ## return the internal path unless overloaded by subclasses.
        ret = self._get_return_()
        
        return(ret)