<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def read_rows( self, table_name, app_profile_id=None, rows=None, filter_=None, rows_limit=None, retry=google.api_core.gapic_v1.method.DEFAULT, timeout=google.api_core.gapic_v1.method.DEFAULT, metadata=None, ):
 """ Streams back the contents of all requested rows in key order, optionally applying the same Reader filter to each. Depending on their size, rows and cells may be broken up across multiple responses, but atomicity of each row will still be preserved. See the ReadRowsResponse documentation for details. Example: Args: table_name (str):
 The unique name of the table from which to read. Values are of the form ``projects/<project>/instances/<instance>/tables/<table>``. app_profile_id (str):
 This value specifies routing for replication. If not specified, the "default" application profile will be used. rows (Union[dict, ~google.cloud.bigtable_v2.types.RowSet]):
 The row keys and/or ranges to read. If not specified, reads from all rows. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.bigtable_v2.types.RowSet` filter_ (Union[dict, ~google.cloud.bigtable_v2.types.RowFilter]):
 The filter to apply to the contents of the specified row(s). If unset, reads the entirety of each row. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.bigtable_v2.types.RowFilter` rows_limit (long):
 The read will terminate after committing to N rows' worth of results. The default (zero) is to return all results. retry (Optional[google.api_core.retry.Retry]):
 A retry object used to retry requests. If ``None`` is specified, requests will not be retried. timeout (Optional[float]):
 The amount of time, in seconds, to wait for the request to complete. Note that if ``retry`` is specified, the timeout applies to each individual attempt. metadata (Optional[Sequence[Tuple[str, str]]]):
 Additional metadata that is provided to the method. Returns: Iterable[~google.cloud.bigtable_v2.types.ReadRowsResponse]. Raises: google.api_core.exceptions.GoogleAPICallError: If the request failed for any reason. google.api_core.exceptions.RetryError: If the request failed due to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """

        # Wrap the transport method to add retry and timeout logic.
        if "read_rows" not in self._inner_api_calls:
            self._inner_api_calls[
                "read_rows"
            ] = google.api_core.gapic_v1.method.wrap_method(
                self.transport.read_rows,
                default_retry=self._method_configs["ReadRows"].retry,
                default_timeout=self._method_configs["ReadRows"].timeout,
                client_info=self._client_info,
            )

        request = bigtable_pb2.ReadRowsRequest(
            table_name=table_name,
            app_profile_id=app_profile_id,
            rows=rows,
            filter=filter_,
            rows_limit=rows_limit,
        )
        if metadata is None:
            metadata = []
        metadata = list(metadata)
        try:
            routing_header = [("table_name", table_name)]
        except AttributeError:
            pass
        else:
            routing_metadata = google.api_core.gapic_v1.routing_header.to_grpc_metadata(
                routing_header
            )
            metadata.append(routing_metadata)

        return self._inner_api_calls["read_rows"](
            request, retry=retry, timeout=timeout, metadata=metadata
        )