3.3.6. pci.api.dsops module

Introduces higher-order functions and decorators to simplify working with Dataset.

New in version 2018.

3.3.6.1. Context managers

class pci.api.dsops.multi_dataset_open(*fargs, **kwargs)

Bases: object

A context manager that can be used to open multiple datasets in one with statement. This context manager accepts filenames or tuples containing a filename and mode (AccessMode) via variable length argument.

By default the dataset is opened as read-only. This behaviour can be modified by using the keyword argument mode (which accepts AccessMode).

The datasets are opened by calling the function default_dataset_open_func() or the callable object supplied via keyword arguments open_dataset_func. This callable object must accept the argument filename and mode and return Dataset object

This example opens ‘ortho2input.pix’ as read-only and ‘ortho2result.pix’ for read/write and transfers a metadata from ‘ortho2input.pix’ to ‘ortho2result.pix’:

from pci.api import dsops
from pci.api.datasource import AccessMode

with dsops.multi_dataset_open('ortho2input.pix',
                              ('ortho2result.pix',
                               AccessMode.eAM_WRITE)) as datasets:
    # datasets is a tuple of Dataset objects where
    #    datasets[0] is ortho2input.pix
    #    datasets[1] is ortho2result.pix (and writeable)

    # transfer a file metadata from ortho2input.pix to ortho2result.pix
    metadata_val = dsops.get_file_metadata(dataset[0], 'Sensor')
    dsops.set_file_metadata(dataset[1], 'Sensor', metadata_val)

3.3.6.2. Segments and attributes

class pci.api.dsops.Segments

Bases: object

Specifies the supported segment types to be used with the following functions: get_segment_ids(), get_all_segment_ids(), get_all_segment_id_map(), get_segment(), create_segment(), create_segment(), delete_segment()

Bitmap = 'BIT'
Vector = 'VEC'
Text = 'TEX'
Orbital = 'EPH'
LUT = 'LUT'
PCT = 'PCT'
MathModel = 'MTH'
Array = 'ARR'
GCP = 'GCP'
class pci.api.dsops.SegAttr(ids, get, get_md, create, delete)

Bases: tuple

A named tuple to store functions and/or properties to access or modify a dataset (Dataset).

  • ids - A list of segment ids

  • get - Get the segment specified by its segment id.

  • get_md - Get the segment metadata accessor specified by its segment id.

  • create - Create a new segment and return the segment id.

  • delete - Delete the segment specified by id.

pci.api.dsops.seg_type_to_attr

A dictionary that has the segment type Segments as the key and the named tuple SegAttr as the value.

The following example demonstrates how to get the create segment function for LUT and Vector segments and use it to create the segment:

from pci.api import datasource as ds
from pci.api.datasource import AccessMode
from pci.api import dsops

with ds.open_dataset('irvine.pix', AccessMode.eAM_WRITE) as dataset:
    # Get the create function for Vector segment
    vec_create_func = dsops.seg_type_to_attr[
            dsops.Segments.Vector].create(dataset)
    # Get the create function for LUT segment
    lut_create_func = dsops.seg_type_to_attr[
            dsops.Segments.LUT].create(dataset)

    # Create a Vector segment
    vec_seg_id = vec_create_func()
    # Create a Vector segment
    lut_seg_id = lut_create_func()

3.3.6.3. Decorators

pci.api.dsops.inject_dataset(*args_to_inject, **inject_kwargs)

Returns a decorator to wrap functions that require filenames to be converted to Dataset object. Call this function with the argument names or argument indexes of the argument that require this capability. The argument index starts at 0, so first argument is 0, the second is 1 and so on.

By default, the files are opened as read-only (AccessMode.eAM_READ) and this can modified by setting the keyword argument mode to either (AccessMode.eAM_READ) or (AccessMode.eAM_WRITE).The files are opened using the context manager, multi_dataset_open. The file access mode can be overridden per argument by keyword arguments and these keyword argument names are determined as follows:

For arguments with name, the mode keyword argument name is {argument_name}_mode.

For arguments without name (*args of the decorated function), the mode keyword argument name is dataset{argument_index}_mode. Examples:

If the argument name is input_dataset, then mode keyword argument name is input_dataset_mode.

If the argument does not have a name and the index of the argument is 2, then, the mode keyword argument name is dataset2_mode.

If allow_mode_kwarg is True, then the decorated function will gain the ability to change the mode per call and Keyword argument (**kwargs) will be added to the function to be decorated. This uses the same naming convention as above, so for argument name input_dataset, setting input_dataset_mode would override the mode used to open the file. For variable arguments on index 4, setting dataset4_mode would override the mode used to open the file.

The following example shows various way to to inject dataset into argument input_dataset (read-only) and output_dataset (read/write)

from pci.api import dsops
from pci.api.datasource import AccessMode

# inject_dataset using argument indexes
@dsops.inject_dataset(0, 3, output_dataset_mode=AccessMode.eAM_WRITE)
def process1(input_dataset, arg1, arg2, output_dataset):
    pass

# inject_dataset using argument index and argument name
@dsops.inject_dataset(0, 'output_dataset',
                      output_dataset_mode=AccessMode.eAM_WRITE))
def process2(input_dataset, arg1, arg2, output_dataset):
    pass

# inject_dataset using argument names and allow mode to be passed
# as a argument to the decorated function
@dsops.inject_dataset('input_dataset', 'output_dataset',
                      allow_mode_kwarg=True)
def process3(input_dataset, arg1, arg2, output_dataset):
    # The decorator will change this functions signature to
    # process3(input_dataset, arg1, arg2, output_dataset, **_kwargs)
    pass


# Call process3 and set output_dataset to be open for read/write
process3('irvine.pix', None, None, 'outputfile.pix',
         output_dataset_mode=AccessMode.eAM_WRITE)
pci.api.dsops.inject_dataset_ro(*args_to_inject, **inject_kwargs)

Read only version of inject_dataset() decorator. Using this decorator is same as doing @inject_dataset(mode=AccessMode.eAM_READ).

pci.api.dsops.inject_dataset_rw(*args_to_inject, **inject_kwargs)

Read/write version of inject_dataset() decorator. Using this decorator is same as doing @inject_dataset(mode=AccessMode.eAM_WRITE).

pci.api.dsops.inject_crs(*args_to_inject, **inject_kwargs)

Return a decorator to use with functions that take CRS objects as arguments. This decorator can inject CRS object in place of Dataset object. Call this function with the argument names or argument indexes of the argument that require this capability. The argument index starts at 0, so first argument is 0, the second is 1 and so on. This decorator can be stacked with inject_dataset().

By default the Dataset object’s CRS is injected.

This decorator adds the ability to specify type and id (CRS) of the segment to where to obtain the CRS object using get_crs(). if allow_crs_kwargs is True (default True) then the function to be decorated will gain keyword arguments, i.e **kwargs so that crs type and id can be specified. If the argument name is crs then the decorator will look for type and id in keyword arguments crs_type and crs_id, respectively. For variable arguments on index 4, decorator will look for segment id and type in keyword arguments crs4_id and crs_type.

Example:

from pci.api import dsops
from pci.api.datasource import AccessMode
from pci.api.datasource import open_dataset

# inject_crs will only inject dataset crs
@dsops.inject_crs(0)
def process1(crs, arg1):
    pass

# src_crs, dst_crs will be injected and the caller can specify
# which crs
@dsops.inject_dataset(2, 'src_crs')
@dsops.inject_crs('src_crs', 'dst_crs')
def process2(arg0, src_crs, points, dst_crs):
    # The decorator will change this functions signature to
    # process2(arg0, src_crs, points, dst_crs, **_kwargs)
    pass

# Inject the 3rd (index 2) argument and keyword argument 'acrs'
@dsops.inject_dataset(2, 'acrs', dataset2_mode=AccessMode.eAM_WRITE)
@dsops.inject_crs(2, 'acrs')
def process3(*args, **kwargs):
    acrs = kwargs.pop('acrs', None)
    pass

# process1's argument crs will accept CRS object and Dataset Object
with open_dataset('irvine.pix') as dataset:
    process1(dataset, None)
    process1(dataset.crs)

# call process2 with vector CRS
process2(5, 'irvine.pix', [(2, 5), (1, 3)], 'ortho2input.pix',
         src_crs_type=dsops.Segments.Vector, src_crs_id=2,
         dst_crs_type=Segments.MathModel,
         dst_crs_id=dsops.last_segment)

# Pass the last GCP segment's CRS  of 'testfile' as the 3rd argument
# Pass the CRS of the Vector segment 25 of 'testfile2.pix' for argument
# 'acrs'
process3("Test", None, "ortho2input.pix.pix",
         crs2_type=Segments.MathModel, crs2_id=dsops.first_segment,
         acrs="california_files.pix", acrs_type=Segments.Vector,
         acrs_id=25)
pci.api.dsops.inject_geocoding(*args_to_inject, **inject_kwargs)

Return a decorator to use with functions that take GeocodingInfo objects as arguments. This decorator can inject the GeocodingInfo object in place of Dataset object. Call this function with the argument names or argument indexes of the argument that require this capability. The argument index starts at 0, so first argument is 0, the second is 1 and so on. This decorator can be stacked with inject_dataset().

from pci.api import dsops
from pci.api.datasource import AccessMode
from pci.api.datasource import open_dataset

@dsops.inject_geocoding(1)
def process1(arg0, geocoding, arg2):
    pass

# Inject coding for arguments 'first_geocoding', 'second_geocoding'
# and argument at index 3 (first argument in (*args)
@dsops.inject_dataset('first_geocoding', 'second_geocoding', 3)
@dsops.inject_geocoding('first_geocoding', 'second_geocoding', 3)
def process2(arg0, first_geocoding, second_geocoding, *args):
    pass
pci.api.dsops.inject_segment(*args_to_inject, **inject_kwargs)

Return a decorator to use with functions that take segment objects (e.g: VectorIO, EphemerisData, etc.) as arguments. This decorator can inject any segment object in place of Dataset object. Call this function with the argument names or argument indexes of the argument that require this capability. The argument index starts at 0, so first argument is 0, the second is 1 and so on. This decorator can be stacked with inject_dataset().

To set the default segment type and id for all the arguments, set the following keyword arguments, segtype and segid respectively.

This decorator adds the ability to specify type and id of the segment per argument. If the argument name is seg then the decorator will look for type and id in keyword arguments seg_type and seg_id, respectively. For variable arguments on index 4, decorator will look for segment id and type in keyword arguments seg4_id and seg_type. If allow_segment_kwargs is True (default True) then the function to be decorated will gain keyword arguments, i.e. **kwargs so that segment id can be overridden by the caller of the decorated function. The segment type can only be overridden if it is not specified in the decorator.

Example:

from pci.api import dsops

# If the argument segment is a filename or Dataset object, then file's
# or Dataset's last Vector segment is injected.
@dsops.inject_dataset(0)
@dsops.inject_segment(0, segtype=dsops.Segments.Vector,
                      segid=dsops.last_segment)
def process_vector(segment, arg1):
    pass

# The caller can specify first_seg's and second_seg's segment type and
# id. If no segment type is specified then it is assumed to be
# MathModel segment.
@dsops.inject_dataset(0, 1)
@dsops.inject_segment(0, 1, segtype=dsops.Segments.MathModel)
def process_segments(first_seg, second_seg):
    # The decorator will change this functions signature to
    # process_segments(first_seg, second_seg, **_kwargs)
    pass

# The caller can specify first_seg's and second_seg's segment type and
# id. If no segment type is specified then first_segment is MathModel
# segment and second_seg is LUT segment. If no segment id specified
# then first_seg is the first segment of its type.
@dsops.inject_dataset(0, 1)
@dsops.inject_segment('first_seg', 'second_seg',
                      first_seg_type=dsops.Segments.MathModel,
                      first_seg_id=dsops.first_segment)
def process_segments2(first_seg, second_seg):
    # The decorator will change this functions signature to
    # process_segments2(first_seg, second_seg, **_kwargs)
    pass

# The function process_vector will receive the last vector segment
# in argument segment. Since the segment type is specified in the
# decorator the segment type cannot be overridden in the call.
process_vector('california_files.pix', 4)

# Call process_segments and pass last MathModel segment for the
# argument first_seg and GCP segment 2 for argument second_seg of file
# testfile1.pix. Since the segment type of both arguments are specified
# in the decorator the segment type cannot be overridden in the call.
process_segments('ortho2input.pix', 'ortho2input.pix',
                 first_seg_id=dsops.last_segment,
                 second_seg_id=2)

# Call process_segments2 and pass first MathModel segment for the
# argument first_seg and last LUT segment for the argument second_seg
# of file testfile1.pix. Since the segment type for argument first_seg
# is specified in the decorator the segment type for that argument
# cannot be overridden in the call.
process_segments2('ortho2input.pix', 'irvine.pix',
                  second_seg_id=dsops.last_segment,
                  second_seg_type=dsops.Segments.LUT)

3.3.6.4. Dataset operations

pci.api.dsops.open_dataset_func(mode=pci.api.datasource.AccessMode.eAM_READ, frmt=None)

Generate a function that opens a file and presets access mode to mode and format to frmt. If frmt is None then use open_dataset, otherwise use open_dataset_format.

pci.api.dsops.default_dataset_open_func(filename, mode=pci.api.datasource.AccessMode.eAM_READ)

The default function to use when opening files in multi_dataset_open.

pci.api.dsops.get_mapunits(crs)

Get the map units from CRS, Dataset or filename. If crs is not a CRS instance then CRS object is determined using keyword arguments crs_type and crs_id.

pci.api.dsops.get_crs(dataset, segtype=None, segid=None)

Returns the crs of the dataset or specified segment. If segtype is None, then the crs of the dataset is returned, otherwise return the crs of the segment specified by segtype (Segments) and segid. Only the following segment types are supported: GCP, Vector and MathModel. The parameter dataset can be Dataset object or filename. The argument segid can be the segment id or function that returns the segment id given the list of all segment ids.

pci.api.dsops.get_geocoding(dataset)

Return the geocoding of the dataset. The dataset is either a filename or Dataset object. The parameter dataset can be Dataset object or filename.

pci.api.dsops.determine_segid(dataset, segtype, segid)

Determine the segment id by evaluating segid. If segid is callable, the result of calling segid is returned, otherwise segid is returned. The callable segid is called with the list of ids for segment type segtype in dataset dataset.

pci.api.dsops.get_segment_ids(dataset, segtype)

Get the list of segment ids for type segtype from dataset. The parameter dataset can be Dataset object or filename.

pci.api.dsops.get_all_segment_ids(dataset, segtypes)

Get single sorted list of all the ids for the list of segments specified by segtypes in dataset. The parameter dataset can be Dataset object or filename.

pci.api.dsops.get_all_segment_id_map(dataset, segtypes, include_empty=False)

Get a dictionary of segment type (key) and segment ids (value) for the list of segments specified by segtypes in dataset. If include_empty is False, then empty lists are excluded. The parameter dataset can be Dataset object or filename.

pci.api.dsops.get_segment(dataset, segtype, segid)

Get the object that is associated with segtype for the segment segid in the dataset. The parameter dataset must be an open Dataset object. The argument segid can be the segment id or function that returns the segment id given the list of all segment ids. If segtype == Segments.Bitmap, then segid can also be a list of bitmap segment ids.

For example, if segtype == Segments.Vector then an instance of VectorIO is returned

The following example code will get the vector segment 28 in the file irvine.pix:

from pci.api import dsops

testfile = 'irvine.pix'
with ds.open_dataset(testfile) as dataset:
    vector = dsops.get_segment(dataset, dsops.Segments.Vector, 28)
    last_vector = dsops.get_segment(dataset,
                                    dsops.Segments.Vector,
                                    dsops.last_segment)
pci.api.dsops.get_segment_md(dataset, segtype, segid)

Get the object that is used to access the metadata for the segment segid of type segtype in the dataset. The parameter dataset must be a Dataset object. The argument segid can be the segment id or function that returns the segment id given the list of all segment ids.

For example, if segtype == Segments.Bitmap then an instance of MetadataIO is returned

The following example code will get the vector metadata I/O object for segment 28 in the file irvine.pix:

from pci.api import dsops

with ds.open_dataset('irvine.pix') as dataset:
    vector = dsops.get_segment_md(dataset,
                                  dsops.Segments.Vector, 28)
    last_vector = dsops.get_segment_md(dataset,
                                       dsops.Segments.Vector,
                                       dsops.last_segment)
pci.api.dsops.create_segment(dataset, segtype, *args, **kwargs)

Create a segment of type segtype in the dataset by passing the arguments args and kwargs to the create function. The parameter dataset can be Dataset object or filename. Returns the ID of the new segment. If creation is not supported for the segment type segtype then NotImplementedError is raised.

The following example will create an array segment in the file irvine.pix:

from pci.api import dsops

testfile = 'irvine.pix'
array_seg_id = dsops.create_segment(testfile, dsops.Segments.Array)
pci.api.dsops.delete_segment(dataset, segtype, segid)

Delete the segment specified by segment id segid of segment type segtype in the dataset. The parameter dataset can be Dataset object or filename. If deletion is not supported for the segment type segtype then NotImplementedError is raised.

The following example will delete the LUT segment number 3 in the file irvine.pix:

from pci.api import dsops

testfile = 'irvine.pix'
array_seg_id = dsops.delete_segment(testfile,
                                    dsops.Segments.LUT,
                                    3)
pci.api.dsops.last_segment(ids)

Return the last index of ids or None.

Can be used with get_crs()

pci.api.dsops.first_segment(ids)

Return the first index of ids or None

Can be used with get_crs()

pci.api.dsops.get_raster_size(dataset)

Get the raster size (in pixels) of the dataset as a tuple of (x-size, y-size). The parameter dataset can be Dataset object or filename.

pci.api.dsops.set_file_metadata(dataset, key, value)

Associates the specified value with key in the file level metadata in dataset. The parameter dataset can be Dataset object or filename.

The following example will set the file metadata key=’Filename’ and value=’irvine’ in the file irvine.pix:

from pci.api import dsops

testfile = 'irvine.pix'
dsops.set_file_metadata(testfile, 'TestName', 'dsops')
pci.api.dsops.get_file_metadata(dataset, key)

Retrieve the file level metadata value for key from the dataset. The parameter dataset can be Dataset object or filename.

The following example will get the file metadata for key=’Filename’ in the file irvine.pix:

from pci.api import dsops

testfile = 'irvine.pix'
value = dsops.get_file_metadata(testfile, 'TestName')
pci.api.dsops.get_all_shape_ids(vector)

Get all shape ids from vector (VectorIO, Dataset or filename. If vector is not VectorIO instance then VectorIO is determined using keyword argument vector_id.

pci.api.dsops.get_channel_data_types(dataset)

Get channel info which is a list containing a tuple; channel number and data type [(channel_num, DataType)]. The parameter dataset can be Dataset object or filename.

Example:

[(1, DT_16U), (2, DT_16U))]
pci.api.dsops.lssegids(dataset, include_empty=False)

List all the segments ids in the dataset as a dictionary where segment type is the key and the list of segments is the value. If include_empty is False, then empty lists are excluded. The parameter dataset can be Dataset object or filename.

pci.api.dsops.get_history_events(history_obj)

Get the a HistoryEventVec of History Events associated with history_obj, which may be a HistoryIO, a Dataset or a filename.

pci.api.dsops.copy_history(src, dst)

Copy all history from one history access object to another. Both src and dst represent history access objects that may be a HistoryIO, a Dataset or a filename.

3.3.6.5. Exceptions

exception pci.api.dsops.InvalidSegment

Bases: Exception

Raised when segment type is not found in Segments