docstr: Split a price data request into chunks corresponding to individual
  bundles.
  
  Parameters
  ----------
  assets: list[TradingPair]
  data_frequency: str
  start_dt: pd.Timestamp
  end_dt: pd.Timestamp
  
  Returns
  -------
  dict[TradingPair, list[dict(str, Object]]]
docstr_tok: ["Split","a","price","data","request","into","chunks","corresponding","to","individual","bundles",".","Parameters","--","--","--","--","--","assets",":","list","[","TradingPair","]","data_frequency",":","str","start_dt",":","pd.Timestamp","end_dt",":","pd.Timestamp","Returns","--","--","--","-","dict","[","TradingPair",",","list","[","dict","(","str",",","Object","]","]","]"]
code: def prepare_chunks(self, assets, data_frequency, start_dt, end_dt):
      """
      Split a price data request into chunks corresponding to individual
      bundles.
  
      Parameters
      ----------
      assets: list[TradingPair]
      data_frequency: str
      start_dt: pd.Timestamp
      end_dt: pd.Timestamp
  
      Returns
      -------
      dict[TradingPair, list[dict(str, Object]]]
  
      """
      get_start_end = (
          get_month_start_end
          if data_frequency == "minute"
          else get_year_start_end
      )
  
      # Get a reader for the main bundle to verify if data exists
      reader = self.get_reader(data_frequency)
  
      chunks = dict()
      for asset in assets:
          try:
              # Checking if the the asset has price data in the specified
              # date range
              adj_start, adj_end = self.get_adj_dates(
                  start_dt, end_dt, [asset], data_frequency
              )
  
          except NoDataAvailableOnExchange as e:
              # If not, we continue to the next asset
              log.debug("skipping {}: {}".format(asset.symbol, e))
              continue
  
          dates = pd.date_range(
              start=get_period_label(adj_start, data_frequency),
              end=get_period_label(adj_end, data_frequency),
              freq="MS" if data_frequency == "minute" else "AS",
              tz=UTC,
          )
  
          # Adjusting the last date of the range to avoid
          # going over the asset's trading bounds
          dates.values[0] = adj_start
          dates.values[-1] = adj_end
  
          chunks[asset] = []
          for index, dt in enumerate(dates):
              period_start, period_end = get_start_end(
                  dt=dt,
                  first_day=dt if index == 0 else None,
                  last_day=dt if index == len(dates) - 1 else None,
              )
  
              # Currencies don't always start trading at midnight.
              # Checking the last minute of the day instead.
              range_start = (
                  period_start.replace(hour=23, minute=59)
                  if data_frequency == "minute"
                  else period_start
              )
  
              # Checking if the data already exists in the bundle
              # for the date range of the chunk. If not, we create
              # a chunk for ingestion.
              has_data = range_in_bundle(
                  asset, range_start, period_end, reader
              )
              if not has_data:
                  period = get_period_label(dt, data_frequency)
                  chunk = dict(
                      asset=asset,
                      period=period,
                  )
                  chunks[asset].append(chunk)
  
          # We sort the chunks by end date to ingest most recent data first
          chunks[asset].sort(
              key=lambda chunk: pd.to_datetime(chunk["period"])
          )
  
      return chunks
  
imports: import os
  import shutil
  from datetime import timedelta
  from functools import partial
  from itertools import chain
  from operator import is_not
  import numpy
  import pandas
  import pytz
  from catalyst import get_calendar
  from catalyst.assets._assets import TradingPair
  from catalyst.constants import DATE_TIME_FORMAT, AUTO_INGEST
  from catalyst.constants import LOG_LEVEL
  from catalyst.data.minute_bars import BcolzMinuteOverlappingData, BcolzMinuteBarMetadata
  from catalyst.exchange.exchange_bcolz import BcolzExchangeBarReader, BcolzExchangeBarWriter
  from catalyst.exchange.exchange_errors import EmptyValuesInBundleError, TempBundleNotFoundError, NoDataAvailableOnExchange, PricingDataNotLoadedError, DataCorruptionError, PricingDataValueError
  from catalyst.exchange.utils.bundle_utils import range_in_bundle, get_bcolz_chunk, get_df_from_arrays, get_assets
  from catalyst.exchange.utils.datetime_utils import get_start_dt, get_period_label, get_month_start_end, get_year_start_end
  from catalyst.exchange.utils.exchange_utils import get_exchange_folder, save_exchange_symbols, mixin_market_params, get_catalyst_symbol
  from catalyst.utils.cli import maybe_show_progress
  from catalyst.utils.paths import ensure_directory
  from logbook import Logger
  from pytz import UTC
  from six import itervalues
label_desc: Use image node_id 13 for calling the ExchangeBundle obj's underlying member method code with example usage: obj.prepare_chunks(assets, data_frequency, start_dt, end_dt) and returns: chunks