def read_gds(self,
                 infile,
                 units='skip',
                 rename={},
                 layers={},
                 datatypes={},
                 texttypes={}):
        """
        Read a GDSII file into this library.

        Parameters
        ----------
        infile : file or string
            GDSII stream file (or path) to be imported.  It must be
            opened for reading in binary format.
        units : {'convert', 'import', 'skip'}
            Controls how to scale and use the units in the imported
            file.  ``'convert'``: the imported geometry is scaled to
            this library units. ``'import'``: the unit and precision in
            this library are replaced by those from the imported file.
            ``'skip'``: the imported geometry is not scaled and units
            are not replaced; the geometry is imported in the *user
            units* of the file.
        rename : dictionary
            Dictionary used to rename the imported cells.  Keys and
            values must be strings.
        layers : dictionary
            Dictionary used to convert the layers in the imported cells.
            Keys and values must be integers.
        datatypes : dictionary
            Dictionary used to convert the datatypes in the imported
            cells.  Keys and values must be integers.
        texttypes : dictionary
            Dictionary used to convert the text types in the imported
            cells.  Keys and values must be integers.

        Returns
        -------
        out : ``GdsLibrary``
            This object.

        Notes
        -----
        Not all features from the GDSII specification are currently
        supported.  A warning will be produced if any unsuported
        features are found in the imported file.
        """
        self._references = []
        if isinstance(infile, basestring):
            infile = open(infile, 'rb')
            close = True
        else:
            close = False
        emitted_warnings = []
        record = self._read_record(infile)
        kwargs = {}
        create_element = None
        factor = 1
        cell = None
        while record is not None:
            # LAYER
            if record[0] == 0x0d:
                kwargs['layer'] = layers.get(record[1][0], record[1][0])
            # DATATYPE
            elif record[0] == 0x0e:
                kwargs['datatype'] = datatypes.get(record[1][0], record[1][0])
            # TEXTTYPE
            elif record[0] == 0x16:
                kwargs['texttype'] = texttypes.get(record[1][0], record[1][0])
            # XY
            elif record[0] == 0x10:
                kwargs['xy'] = factor * record[1]
            # WIDTH
            elif record[0] == 0x0f:
                kwargs['width'] = factor * abs(record[1][0])
                if record[1][0] < 0 and record[0] not in emitted_warnings:
                    warnings.warn(
                        "[GDSPY] Paths with absolute width value are not "
                        "supported.  Scaling these paths will also scale "
                        "their width.",
                        stacklevel=2)
                    emitted_warnings.append(record[0])
            # ENDEL
            elif record[0] == 0x11:
                if create_element is not None:
                    cell.add(create_element(**kwargs))
                    create_element = None
                kwargs = {}
            # BOUNDARY
            elif record[0] == 0x08:
                create_element = self._create_polygon
            # PATH
            elif record[0] == 0x09:
                create_element = self._create_path
            # TEXT
            elif record[0] == 0x0c:
                create_element = self._create_label
            # SNAME
            elif record[0] == 0x12:
                kwargs['ref_cell'] = rename.get(record[1], record[1])
            # COLROW
            elif record[0] == 0x13:
                kwargs['columns'] = record[1][0]
                kwargs['rows'] = record[1][1]
            # STRANS
            elif record[0] == 0x1a:
                kwargs['x_reflection'] = ((int(record[1][0]) & 0x8000) > 0)
                if (int(record[1][0]) &
                        0x0006) and record[0] not in emitted_warnings:
                    warnings.warn(
                        "[GDSPY] Absolute magnification or rotation of "
                        "references is not supported.  Transformations will "
                        "be interpreted as relative.",
                        stacklevel=2)
                    emitted_warnings.append(record[0])
            # MAG
            elif record[0] == 0x1b:
                kwargs['magnification'] = record[1][0]
            # ANGLE
            elif record[0] == 0x1c:
                kwargs['rotation'] = record[1][0]
            # SREF
            elif record[0] == 0x0a:
                create_element = self._create_reference
            # AREF
            elif record[0] == 0x0b:
                create_element = self._create_array
            # STRNAME
            elif record[0] == 0x06:
                name = rename.get(record[1], record[1])
                cell = Cell(name, exclude_from_current=True)
                self.cell_dict[name] = cell
            # STRING
            elif record[0] == 0x19:
                kwargs['text'] = record[1]
            # ENDSTR
            elif record[0] == 0x07:
                cell = None
            # UNITS
            elif record[0] == 0x03:
                if units == 'skip':
                    factor = record[1][0]
                elif units == 'import':
                    self.unit = record[1][1] / record[1][0]
                    self.precision = record[1][1]
                    factor = record[1][0]
                elif units == 'convert':
                    factor = record[1][1] / self.unit
                else:
                    raise ValueError("[GDSPY] units must be one of 'convert', "
                                     "'import' or 'skip'.")
            # LIBNAME
            elif record[0] == 0x02:
                self.name = record[1]
            # PRESENTATION
            elif record[0] == 0x17:
                kwargs['anchor'] = GdsLibrary._import_anchors[int(record[1][0])
                                                              & 0x000f]
            # PATHTYPE
            elif record[0] == 0x21:
                if record[1][0] > 2:
                    if 0x21 not in emitted_warnings:
                        warnings.warn(
                            "[GDSPY] Path ends with custom size are not "
                            "supported.",
                            RuntimeWarning,
                            stacklevel=2)
                        emitted_warnings.append(0x21)
                else:
                    kwargs['ends'] = record[1][0]
            # ENDLIB
            elif record[0] == 0x04:
                for ref in self._references:
                    if ref.ref_cell in self.cell_dict:
                        ref.ref_cell = self.cell_dict[ref.ref_cell]
                    elif ref.ref_cell in current_library.cell_dict:
                        ref.ref_cell = current_library.cell_dict[ref.ref_cell]
            # Not supported
            elif (record[0] not in emitted_warnings and
                  record[0] not in GdsLibrary._unused_records):
                warnings.warn(
                    "[GDSPY] Record type {0} ({1:02X}) is not "
                    "supported.".format(GdsLibrary._record_name[record[0]],
                                        record[0]),
                    RuntimeWarning,
                    stacklevel=2)
                emitted_warnings.append(record[0])
            record = self._read_record(infile)
        if close:
            infile.close()
        return self
Read a GDSII file into this library.

        Parameters
        ----------
        infile : file or string
            GDSII stream file (or path) to be imported.  It must be
            opened for reading in binary format.
        units : {'convert', 'import', 'skip'}
            Controls how to scale and use the units in the imported
            file.  ``'convert'``: the imported geometry is scaled to
            this library units. ``'import'``: the unit and precision in
            this library are replaced by those from the imported file.
            ``'skip'``: the imported geometry is not scaled and units
            are not replaced; the geometry is imported in the *user
            units* of the file.
        rename : dictionary
            Dictionary used to rename the imported cells.  Keys and
            values must be strings.
        layers : dictionary
            Dictionary used to convert the layers in the imported cells.
            Keys and values must be integers.
        datatypes : dictionary
            Dictionary used to convert the datatypes in the imported
            cells.  Keys and values must be integers.
        texttypes : dictionary
            Dictionary used to convert the text types in the imported
            cells.  Keys and values must be integers.

        Returns
        -------
        out : ``GdsLibrary``
            This object.

        Notes
        -----
        Not all features from the GDSII specification are currently
        supported.  A warning will be produced if any unsuported
        features are found in the imported file.