a
    !f                     @   s   d Z ddlZddlZddlmZ ddlmZ ddlmZ ddlmZ	 ddlm
Z edjZd	ZG d
d deZG dd deZG dd deZG dd deZG dd deZdd Zdd ZdS )z6User friendly container for Google Cloud Bigtable Row.    N)_datetime_from_microseconds)_microseconds_from_datetime)	_to_bytes)data_pb2)bigtable_pb2z>qi c                   @   s   e Zd ZdZdd ZdS )Rowa  Base representation of a Google Cloud Bigtable Row.

    This class has three subclasses corresponding to the three
    RPC methods for sending row mutations:

    * :class:`DirectRow` for ``MutateRow``
    * :class:`ConditionalRow` for ``CheckAndMutateRow``
    * :class:`AppendRow` for ``ReadModifyWriteRow``

    :type row_key: bytes
    :param row_key: The key for the current row.

    :type table: :class:`Table <gcloud.bigtable.table.Table>`
    :param table: The table that owns the row.
    c                 C   s   t || _|| _d S N)r   _row_key_tableselfrow_keytable r   T/var/www/html/python-backend/venv/lib/python3.9/site-packages/gcloud/bigtable/row.py__init__6   s    
zRow.__init__N)__name__
__module____qualname____doc__r   r   r   r   r   r   %   s   r   c                   @   s<   e Zd ZdZe Zdd ZdddZdddZdd	d
Z	dS )_SetDeleteRowa  Row helper for setting or deleting cell values.

    Implements helper methods to add mutations to set or delete cell contents:

    * :meth:`set_cell`
    * :meth:`delete`
    * :meth:`delete_cell`
    * :meth:`delete_cells`

    :type row_key: bytes
    :param row_key: The key for the current row.

    :type table: :class:`Table <gcloud.bigtable.table.Table>`
    :param table: The table that owns the row.
    c                 C   s   t dS )a  Gets the list of mutations for a given state.

        This method intended to be implemented by subclasses.

        ``state`` may not need to be used by all subclasses.

        :type state: bool
        :param state: The state that the mutation should be
                      applied in.

        :raises: :class:`NotImplementedError <exceptions.NotImplementedError>`
                 always.
        N)NotImplementedErrorr   stater   r   r   _get_mutationsO   s    z_SetDeleteRow._get_mutationsNc           	      C   sz   t |}t|tjrt|}t |}|du r2d}nt|}||d 8 }tjj||||d}tj|d}| 	|
| dS )a  Helper for :meth:`set_cell`

        Adds a mutation to set the value in a specific cell.

        ``state`` is unused by :class:`DirectRow` but is used by
        subclasses.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column.
                                 Must be of the form
                                 ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type column: bytes
        :param column: The column within the column family where the cell
                       is located.

        :type value: bytes or :class:`int`
        :param value: The value to set in the cell. If an integer is used,
                      will be interpreted as a 64-bit big-endian signed
                      integer (8 bytes).

        :type timestamp: :class:`datetime.datetime`
        :param timestamp: (Optional) The timestamp of the operation.

        :type state: bool
        :param state: (Optional) The state that is passed along to
                      :meth:`_get_mutations`.
        Ni  )family_namecolumn_qualifiertimestamp_microsvalue)set_cell)r   
isinstancesixinteger_types	_PACK_I64r   data_v2_pb2MutationZSetCellr   append)	r   column_family_idcolumnr   	timestampr   r   mutation_valmutation_pbr   r   r   	_set_cell_   s     z_SetDeleteRow._set_cellc                 C   s*   t j }t j|d}| || dS )a_  Helper for :meth:`delete`

        Adds a delete mutation (for the entire row) to the accumulated
        mutations.

        ``state`` is unused by :class:`DirectRow` but is used by
        subclasses.

        :type state: bool
        :param state: (Optional) The state that is passed along to
                      :meth:`_get_mutations`.
        )Zdelete_from_rowN)r%   r&   ZDeleteFromRowr   r'   )r   r   r+   r,   r   r   r   _delete   s    
z_SetDeleteRow._deletec                 C   s   |  |}|| ju r:tjj|d}tj|d}|| nni }|durR| |d< g }	|D ]B}
t|
}
|j||
d tjj	f i |}tj|d}|	| qZ|
|	 dS )a?  Helper for :meth:`delete_cell` and :meth:`delete_cells`.

        ``state`` is unused by :class:`DirectRow` but is used by
        subclasses.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column
                                 or columns with cells being deleted. Must be
                                 of the form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type columns: :class:`list` of :class:`str` /
                       :func:`unicode <unicode>`, or :class:`object`
        :param columns: The columns within the column family that will have
                        cells deleted. If :attr:`ALL_COLUMNS` is used then
                        the entire column family will be deleted from the row.

        :type time_range: :class:`TimestampRange`
        :param time_range: (Optional) The range of time within which cells
                           should be deleted.

        :type state: bool
        :param state: (Optional) The state that is passed along to
                      :meth:`_get_mutations`.
        )r   )Zdelete_from_familyN
time_range)r   r   )Zdelete_from_column)r   ALL_COLUMNSr%   r&   ZDeleteFromFamilyr'   to_pbr   updateZDeleteFromColumnextend)r   r(   columnsr/   r   mutations_listr+   r,   Zdelete_kwargsZ	to_appendr)   r   r   r   _delete_cells   s2    


z_SetDeleteRow._delete_cells)NN)N)NN)
r   r   r   r   objectr0   r   r-   r.   r6   r   r   r   r   r   ;   s     
3
  r   c                       s^   e Zd ZdZ fddZdd ZdddZd	d
 ZdddZdddZ	dd Z
dd Z  ZS )	DirectRowam  Google Cloud Bigtable Row for sending "direct" mutations.

    These mutations directly set or delete cell contents:

    * :meth:`set_cell`
    * :meth:`delete`
    * :meth:`delete_cell`
    * :meth:`delete_cells`

    These methods can be used directly::

       >>> row = table.row(b'row-key1')
       >>> row.set_cell(u'fam', b'col1', b'cell-val')
       >>> row.delete_cell(u'fam', b'col2')

    .. note::

        A :class:`DirectRow` accumulates mutations locally via the
        :meth:`set_cell`, :meth:`delete`, :meth:`delete_cell` and
        :meth:`delete_cells` methods. To actually send these mutations to the
        Google Cloud Bigtable API, you must call :meth:`commit`.

    :type row_key: bytes
    :param row_key: The key for the current row.

    :type table: :class:`Table <gcloud.bigtable.table.Table>`
    :param table: The table that owns the row.
    c                    s   t t| || g | _d S r   )superr8   r   _pb_mutationsr   	__class__r   r   r      s    zDirectRow.__init__c                 C   s   | j S )ag  Gets the list of mutations for a given state.

        ``state`` is unused by :class:`DirectRow` but is used by
        subclasses.

        :type state: bool
        :param state: The state that the mutation should be
                      applied in.

        :rtype: list
        :returns: The list to add new mutations to (for the current state).
        r:   r   r   r   r   r      s    zDirectRow._get_mutationsNc                 C   s   | j ||||dd dS )a  Sets a value in this row.

        The cell is determined by the ``row_key`` of this :class:`DirectRow`
        and the ``column``. The ``column`` must be in an existing
        :class:`.ColumnFamily` (as determined by ``column_family_id``).

        .. note::

            This method adds a mutation to the accumulated mutations on this
            row, but does not make an API request. To actually
            send an API request (with the mutations) to the Google Cloud
            Bigtable API, call :meth:`commit`.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column.
                                 Must be of the form
                                 ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type column: bytes
        :param column: The column within the column family where the cell
                       is located.

        :type value: bytes or :class:`int`
        :param value: The value to set in the cell. If an integer is used,
                      will be interpreted as a 64-bit big-endian signed
                      integer (8 bytes).

        :type timestamp: :class:`datetime.datetime`
        :param timestamp: (Optional) The timestamp of the operation.
        Nr*   r   r-   )r   r(   r)   r   r*   r   r   r   r      s    zDirectRow.set_cellc                 C   s   | j dd dS )aA  Deletes this row from the table.

        .. note::

            This method adds a mutation to the accumulated mutations on this
            row, but does not make an API request. To actually
            send an API request (with the mutations) to the Google Cloud
            Bigtable API, call :meth:`commit`.
        Nr   r.   r   r   r   r   delete0  s    
zDirectRow.deletec                 C   s   | j ||g|dd dS )a  Deletes cell in this row.

        .. note::

            This method adds a mutation to the accumulated mutations on this
            row, but does not make an API request. To actually
            send an API request (with the mutations) to the Google Cloud
            Bigtable API, call :meth:`commit`.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column
                                 or columns with cells being deleted. Must be
                                 of the form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type column: bytes
        :param column: The column within the column family that will have a
                       cell deleted.

        :type time_range: :class:`TimestampRange`
        :param time_range: (Optional) The range of time within which cells
                           should be deleted.
        Nr/   r   r6   )r   r(   r)   r/   r   r   r   delete_cell<  s    zDirectRow.delete_cellc                 C   s   | j |||dd dS )aW  Deletes cells in this row.

        .. note::

            This method adds a mutation to the accumulated mutations on this
            row, but does not make an API request. To actually
            send an API request (with the mutations) to the Google Cloud
            Bigtable API, call :meth:`commit`.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column
                                 or columns with cells being deleted. Must be
                                 of the form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type columns: :class:`list` of :class:`str` /
                       :func:`unicode <unicode>`, or :class:`object`
        :param columns: The columns within the column family that will have
                        cells deleted. If :attr:`ALL_COLUMNS` is used then
                        the entire column family will be deleted from the row.

        :type time_range: :class:`TimestampRange`
        :param time_range: (Optional) The range of time within which cells
                           should be deleted.
        NrD   rE   )r   r(   r4   r/   r   r   r   delete_cellsV  s    
zDirectRow.delete_cellsc                 C   sr   |  d}t|}|dkrdS |tkr6td|tf tj| jj| j|d}| jj	j
}|j||j |   dS )aX  Makes a ``MutateRow`` API request.

        If no mutations have been created in the row, no request is made.

        Mutations are applied atomically and in order, meaning that earlier
        mutations can be masked / negated by later ones. Cells already present
        in the row are left unchanged unless explicitly changed by a mutation.

        After committing the accumulated mutations, resets the local
        mutations to an empty list.

        :raises: :class:`ValueError <exceptions.ValueError>` if the number of
                 mutations exceeds the :data:`MAX_MUTATIONS`.
        Nr   z3%d total mutations exceed the maximum allowable %d.)
table_namer   Z	mutations)r   lenMAX_MUTATIONS
ValueErrormessages_v2_pb2ZMutateRowRequestr
   namer	   	_instance_client
_data_stubZ	MutateRowtimeout_secondsclear)r   r5   num_mutations
request_pbclientr   r   r   commitr  s     

zDirectRow.commitc                 C   s   | j dd= dS z?Removes all currently accumulated mutations on the current row.Nr=   rB   r   r   r   rR     s    zDirectRow.clear)N)N)N)r   r   r   r   r   r   r    rC   rF   rG   rV   rR   __classcell__r   r   r;   r   r8      s   
"

 r8   c                       s`   e Zd ZdZ fddZdd Zdd Zdd
dZdddZdddZ	dddZ
dd Z  ZS )ConditionalRowa  Google Cloud Bigtable Row for sending mutations conditionally.

    Each mutation has an associated state: :data:`True` or :data:`False`.
    When :meth:`commit`-ed, the mutations for the :data:`True`
    state will be applied if the filter matches any cells in
    the row, otherwise the :data:`False` state will be applied.

    A :class:`ConditionalRow` accumulates mutations in the same way a
    :class:`DirectRow` does:

    * :meth:`set_cell`
    * :meth:`delete`
    * :meth:`delete_cell`
    * :meth:`delete_cells`

    with the only change the extra ``state`` parameter::

       >>> row_cond = table.row(b'row-key2', filter_=row_filter)
       >>> row_cond.set_cell(u'fam', b'col', b'cell-val', state=True)
       >>> row_cond.delete_cell(u'fam', b'col', state=False)

    .. note::

        As with :class:`DirectRow`, to actually send these mutations to the
        Google Cloud Bigtable API, you must call :meth:`commit`.

    :type row_key: bytes
    :param row_key: The key for the current row.

    :type table: :class:`Table <gcloud.bigtable.table.Table>`
    :param table: The table that owns the row.

    :type filter_: :class:`.RowFilter`
    :param filter_: Filter to be used for conditional mutations.
    c                    s(   t t| || || _g | _g | _d S r   )r9   rY   r   _filter_true_pb_mutations_false_pb_mutations)r   r   r   filter_r;   r   r   r     s    zConditionalRow.__init__c                 C   s   |r
| j S | jS dS )a  Gets the list of mutations for a given state.

        Over-ridden so that the state can be used in:

        * :meth:`set_cell`
        * :meth:`delete`
        * :meth:`delete_cell`
        * :meth:`delete_cells`

        :type state: bool
        :param state: The state that the mutation should be
                      applied in.

        :rtype: list
        :returns: The list to add new mutations to (for the current state).
        Nr[   r\   r   r   r   r   r     s    zConditionalRow._get_mutationsc                 C   s   | j dd}| j dd}t|}t|}|dkr<|dkr<dS |tksL|tkr^tdt||f tj| jj| j| j	
 ||d}| jjj}|j||j}|   |jS )a  Makes a ``CheckAndMutateRow`` API request.

        If no mutations have been created in the row, no request is made.

        The mutations will be applied conditionally, based on whether the
        filter matches any cells in the :class:`ConditionalRow` or not. (Each
        method which adds a mutation has a ``state`` parameter for this
        purpose.)

        Mutations are applied atomically and in order, meaning that earlier
        mutations can be masked / negated by later ones. Cells already present
        in the row are left unchanged unless explicitly changed by a mutation.

        After committing the accumulated mutations, resets the local
        mutations.

        :rtype: bool
        :returns: Flag indicating if the filter was matched (which also
                  indicates which set of mutations were applied by the server).
        :raises: :class:`ValueError <exceptions.ValueError>` if the number of
                 mutations exceeds the :data:`MAX_MUTATIONS`.
        Tr@   Fr   NzZExceed the maximum allowable mutations (%d). Had %s true mutations and %d false mutations.)rH   r   Zpredicate_filtertrue_mutationsfalse_mutations)r   rI   rJ   rK   rL   ZCheckAndMutateRowRequestr
   rM   r	   rZ   r1   rN   rO   rP   ZCheckAndMutateRowrQ   rR   Zpredicate_matched)r   r_   r`   Znum_true_mutationsZnum_false_mutationsrT   rU   respr   r   r   rV     s8    
zConditionalRow.commitNTc                 C   s   | j |||||d dS )a  Sets a value in this row.

        The cell is determined by the ``row_key`` of this
        :class:`ConditionalRow` and the ``column``. The ``column`` must be in
        an existing :class:`.ColumnFamily` (as determined by
        ``column_family_id``).

        .. note::

            This method adds a mutation to the accumulated mutations on this
            row, but does not make an API request. To actually
            send an API request (with the mutations) to the Google Cloud
            Bigtable API, call :meth:`commit`.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column.
                                 Must be of the form
                                 ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type column: bytes
        :param column: The column within the column family where the cell
                       is located.

        :type value: bytes or :class:`int`
        :param value: The value to set in the cell. If an integer is used,
                      will be interpreted as a 64-bit big-endian signed
                      integer (8 bytes).

        :type timestamp: :class:`datetime.datetime`
        :param timestamp: (Optional) The timestamp of the operation.

        :type state: bool
        :param state: (Optional) The state that the mutation should be
                      applied in. Defaults to :data:`True`.
        r>   Nr?   )r   r(   r)   r   r*   r   r   r   r   r    
  s    %zConditionalRow.set_cellc                 C   s   | j |d dS )a  Deletes this row from the table.

        .. note::

            This method adds a mutation to the accumulated mutations on this
            row, but does not make an API request. To actually
            send an API request (with the mutations) to the Google Cloud
            Bigtable API, call :meth:`commit`.

        :type state: bool
        :param state: (Optional) The state that the mutation should be
                      applied in. Defaults to :data:`True`.
        r@   NrA   r   r   r   r   rC   2  s    zConditionalRow.deletec                 C   s   | j ||g||d dS )a  Deletes cell in this row.

        .. note::

            This method adds a mutation to the accumulated mutations on this
            row, but does not make an API request. To actually
            send an API request (with the mutations) to the Google Cloud
            Bigtable API, call :meth:`commit`.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column
                                 or columns with cells being deleted. Must be
                                 of the form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type column: bytes
        :param column: The column within the column family that will have a
                       cell deleted.

        :type time_range: :class:`TimestampRange`
        :param time_range: (Optional) The range of time within which cells
                           should be deleted.

        :type state: bool
        :param state: (Optional) The state that the mutation should be
                      applied in. Defaults to :data:`True`.
        rD   NrE   )r   r(   r)   r/   r   r   r   r   rF   B  s    zConditionalRow.delete_cellc                 C   s   | j ||||d dS )a  Deletes cells in this row.

        .. note::

            This method adds a mutation to the accumulated mutations on this
            row, but does not make an API request. To actually
            send an API request (with the mutations) to the Google Cloud
            Bigtable API, call :meth:`commit`.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column
                                 or columns with cells being deleted. Must be
                                 of the form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type columns: :class:`list` of :class:`str` /
                       :func:`unicode <unicode>`, or :class:`object`
        :param columns: The columns within the column family that will have
                        cells deleted. If :attr:`ALL_COLUMNS` is used then the
                        entire column family will be deleted from the row.

        :type time_range: :class:`TimestampRange`
        :param time_range: (Optional) The range of time within which cells
                           should be deleted.

        :type state: bool
        :param state: (Optional) The state that the mutation should be
                      applied in. Defaults to :data:`True`.
        rD   NrE   )r   r(   r4   r/   r   r   r   r   rG   a  s    
zConditionalRow.delete_cellsc                 C   s   | j dd= | jdd= dS rW   r^   rB   r   r   r   rR     s    zConditionalRow.clear)NT)T)NT)NT)r   r   r   r   r   r   rV   r    rC   rF   rG   rR   rX   r   r   r;   r   rY     s   #3  
(
  
  
"rY   c                       s@   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Z  Z	S )	AppendRowa  Google Cloud Bigtable Row for sending append mutations.

    These mutations are intended to augment the value of an existing cell
    and uses the methods:

    * :meth:`append_cell_value`
    * :meth:`increment_cell_value`

    The first works by appending bytes and the second by incrementing an
    integer (stored in the cell as 8 bytes). In either case, if the
    cell is empty, assumes the default empty value (empty string for
    bytes or and 0 for integer).

    :type row_key: bytes
    :param row_key: The key for the current row.

    :type table: :class:`Table <gcloud.bigtable.table.Table>`
    :param table: The table that owns the row.
    c                    s   t t| || g | _d S r   )r9   rb   r   _rule_pb_listr   r;   r   r   r     s    zAppendRow.__init__c                 C   s   | j dd= dS )z?Removes all currently accumulated modifications on current row.N)rc   rB   r   r   r   rR     s    zAppendRow.clearc                 C   s0   t |}t |}tj|||d}| j| dS )a  Appends a value to an existing cell.

        .. note::

            This method adds a read-modify rule protobuf to the accumulated
            read-modify rules on this row, but does not make an API
            request. To actually send an API request (with the rules) to the
            Google Cloud Bigtable API, call :meth:`commit`.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column.
                                 Must be of the form
                                 ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type column: bytes
        :param column: The column within the column family where the cell
                       is located.

        :type value: bytes
        :param value: The value to append to the existing value in the cell. If
                      the targeted cell is unset, it will be treated as
                      containing the empty string.
        )r   r   Zappend_valueNr   r%   ZReadModifyWriteRulerc   r'   )r   r(   r)   r   rule_pbr   r   r   append_cell_value  s    zAppendRow.append_cell_valuec                 C   s(   t |}tj|||d}| j| dS )a  Increments a value in an existing cell.

        Assumes the value in the cell is stored as a 64 bit integer
        serialized to bytes.

        .. note::

            This method adds a read-modify rule protobuf to the accumulated
            read-modify rules on this row, but does not make an API
            request. To actually send an API request (with the rules) to the
            Google Cloud Bigtable API, call :meth:`commit`.

        :type column_family_id: str
        :param column_family_id: The column family that contains the column.
                                 Must be of the form
                                 ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.

        :type column: bytes
        :param column: The column within the column family where the cell
                       is located.

        :type int_value: int
        :param int_value: The value to increment the existing value in the cell
                          by. If the targeted cell is unset, it will be treated
                          as containing a zero. Otherwise, the targeted cell
                          must contain an 8-byte value (interpreted as a 64-bit
                          big-endian signed integer), or the entire request
                          will fail.
        )r   r   Zincrement_amountNrd   )r   r(   r)   Z	int_valuere   r   r   r   increment_cell_value  s    zAppendRow.increment_cell_valuec                 C   sp   t | j}|dkri S |tkr.td|tf tj| jj| j| jd}| jj	j
}|j||j}|   t|S )a0  Makes a ``ReadModifyWriteRow`` API request.

        This commits modifications made by :meth:`append_cell_value` and
        :meth:`increment_cell_value`. If no modifications were made, makes
        no API request and just returns ``{}``.

        Modifies a row atomically, reading the latest existing
        timestamp / value from the specified columns and writing a new value by
        appending / incrementing. The new cell created uses either the current
        server time or the highest timestamp of a cell in that column (if it
        exceeds the server time).

        After committing the accumulated mutations, resets the local mutations.

        .. code:: python

            >>> append_row.commit()
            {
                u'col-fam-id': {
                    b'col-name1': [
                        (b'cell-val', datetime.datetime(...)),
                        (b'cell-val-newer', datetime.datetime(...)),
                    ],
                    b'col-name2': [
                        (b'altcol-cell-val', datetime.datetime(...)),
                    ],
                },
                u'col-fam-id2': {
                    b'col-name3-but-other-fam': [
                        (b'foo', datetime.datetime(...)),
                    ],
                },
            }

        :rtype: dict
        :returns: The new contents of all modified cells. Returned as a
                  dictionary of column families, each of which holds a
                  dictionary of columns. Each column contains a list of cells
                  modified. Each cell is represented with a two-tuple with the
                  value (in bytes) and the timestamp for the cell.
        :raises: :class:`ValueError <exceptions.ValueError>` if the number of
                 mutations exceeds the :data:`MAX_MUTATIONS`.
        r   z:%d total append mutations exceed the maximum allowable %d.)rH   r   rules)rI   rc   rJ   rK   rL   ZReadModifyWriteRowRequestr
   rM   r	   rN   rO   rP   ZReadModifyWriteRowrQ   rR   _parse_rmw_row_response)r   rS   rT   rU   row_responser   r   r   rV     s$    ,

zAppendRow.commit)
r   r   r   r   r   rR   rf   rg   rV   rX   r   r   r;   r   rb     s    %rb   c                 C   s*   i }| j jD ]}t|\}}|||< q|S )a8  Parses the response to a ``ReadModifyWriteRow`` request.

    :type row_response: :class:`.data_v2_pb2.Row`
    :param row_response: The response row (with only modified cells) from a
                         ``ReadModifyWriteRow`` request.

    :rtype: dict
    :returns: The new contents of all modified cells. Returned as a
              dictionary of column families, each of which holds a
              dictionary of columns. Each column contains a list of cells
              modified. Each cell is represented with a two-tuple with the
              value (in bytes) and the timestamp for the cell. For example:

              .. code:: python

                  {
                      u'col-fam-id': {
                          b'col-name1': [
                              (b'cell-val', datetime.datetime(...)),
                              (b'cell-val-newer', datetime.datetime(...)),
                          ],
                          b'col-name2': [
                              (b'altcol-cell-val', datetime.datetime(...)),
                          ],
                      },
                      u'col-fam-id2': {
                          b'col-name3-but-other-fam': [
                              (b'foo', datetime.datetime(...)),
                          ],
                      },
                  }
    )rowZfamilies_parse_family_pb)rj   resultZcolumn_familyr(   Zcurr_familyr   r   r   ri   .  s
    !
ri   c                 C   sN   i }| j D ]8}g  ||j< }|jD ]}|jt|jf}|| q"q
| j|fS )a  Parses a Family protobuf into a dictionary.

    :type family_pb: :class:`._generated.data_pb2.Family`
    :param family_pb: A protobuf

    :rtype: tuple
    :returns: A string and dictionary. The string is the name of the
              column family and the dictionary has column names (within the
              family) as keys and cell lists as values. Each cell is
              represented with a two-tuple with the value (in bytes) and the
              timestamp for the cell. For example:

              .. code:: python

                  {
                      b'col-name1': [
                          (b'cell-val', datetime.datetime(...)),
                          (b'cell-val-newer', datetime.datetime(...)),
                      ],
                      b'col-name2': [
                          (b'altcol-cell-val', datetime.datetime(...)),
                      ],
                  }
    )r4   Z	qualifiercellsr   r   r   r'   rM   )Z	family_pbrm   r)   rn   cellZval_pairr   r   r   rl   V  s    

rl   )r   structr"   Zgcloud._helpersr   r   r   Zgcloud.bigtable._generatedr   r%   r   rL   Structpackr$   rJ   r7   r   r   r8   rY   rb   ri   rl   r   r   r   r   <module>   s(    # ; s &(