class_docstr: This class manages the card's state for a single card.
  - It uses the `ComponentStore` to manage the storage of the components
  - It exposes methods to add, remove and access the components.
  - It exposes a `refresh` method that will allow refreshing a card with new data
  for realtime(ish) updates.
  - The `CardComponentCollector` exposes convenience methods similar to this class for a default
  editable card. These methods include :
      - `append`
      - `extend`
      - `clear`
      - `refresh`
      - `components`
      - `__iter__`
  
  ## Usage Patterns :
  
  ```python
  current.card["mycardid"].append(component, id="comp123")
  current.card["mycardid"].extend([component])
  current.card["mycardid"].refresh(data) # refreshes the card with new data
  current.card["mycardid"].components["comp123"] # returns the component with id "comp123"
  current.card["mycardid"].components["comp123"].update()
  current.card["mycardid"].components.clear() # Wipe all the components
  del current.card["mycardid"].components["mycomponentid"] # Delete a component
  ```
class_docstr_tok: ["This","class","manages","the","card","'s","state","for","a","single","card",".","-","It","uses","the","`","ComponentStore","`","to","manage","the","storage","of","the","components","-","It","exposes","methods","to","add",",","remove","and","access","the","components",".","-","It","exposes","a","`","refresh","`","method","that","will","allow","refreshing","a","card","with","new","data","for","realtime","(","ish",")","updates",".","-","The","`","CardComponentCollector","`","exposes","convenience","methods","similar","to","this","class","for","a","default","editable","card",".","These","methods","include",":","-","`","append","`","-","`","extend","`","-","`","clear","`","-","`","refresh","`","-","`","components","`","-","`","__iter__","`","#","#","Usage","Patterns",":","``","`","python","current.card","[","``","mycardid","''","]",".append","(","component",",","id=","''","comp123","''",")","current.card","[","``","mycardid","''","]",".extend","(","[","component","]",")","current.card","[","``","mycardid","''","]",".refresh","(","data",")","#","refreshes","the","card","with","new","data","current.card","[","``","mycardid","''","]",".components","[","``","comp123","''","]","#","returns","the","component","with","id","``","comp123","''","current.card","[","``","mycardid","''","]",".components","[","``","comp123","''","]",".update","(",")","current.card","[","``","mycardid","''","]",".components.clear","(",")","#","Wipe","all","the","components","del","current.card","[","``","mycardid","''","]",".components","[","``","mycomponentid","''","]","#","Delete","a","component","``","`"]
code: def refresh(self, data=None, force=False):
      self._latest_user_data = data
      nu = time.time()
      first_render = True if self._last_render == 0 else False
  
      if nu - self._last_refresh < self._refresh_interval:
          # rate limit refreshes: silently ignore requests that
          # happen too frequently
          return
      self._last_refresh = nu
  
      # This block of code will render the card in `render_runtime` mode when:
      # 1. refresh is called with `force=True`
      # 2. Layout of the components in the card has changed. i.e. The actual elements in the component array have changed.
      # 3. The last time the card was rendered was more the minimum interval after which they should be rendered.
      last_rendered_before_minimum_interval = (
          nu - self._last_refresh
      ) > RUNTIME_CARD_RENDER_INTERVAL
      layout_has_changed = (
          self._last_layout_change
          != self.components.layout_last_changed_on
          or self._last_layout_change is None
      )
      if (
          force
          or last_rendered_before_minimum_interval
          or layout_has_changed
      ):
          self._render_seq += 1
          self._last_render = nu
          self._card_proc("render_runtime")
          # The below `if not first_render` condition is a special case for the following scenario:
          # Lets assume the case that the user is only doing `current.card.append` followed by `refresh`.
          # In this case, there will be no process executed in `refresh` mode since `layout_has_changed`
          # will always be true and as a result there will be no data update that informs the UI of the RELOAD_TOKEN change.
          # This will cause the UI to seek for the data update object but will constantly find None. So if it is not
          # the first render then we should also have a `refresh` call followed by a `render_runtime` call so
          # that the UI can always be updated with the latest data.
          if not first_render:
              # For the general case, the CardCreator's ProcessManager run's the `refresh` / `render_runtime` in a asynchronous manner.
              # Due to this when the `render_runtime` call is happening, an immediately subsequent call to `refresh` will not be able to
              # execute since the card-process manager will be busy executing the `render_runtime` call and ignore the `refresh` call.
              # Hence we need to pass the `sync=True` argument to the `refresh` call so that the `refresh` call is executed synchronously and waits for the
              # `render_runtime` call to finish.
              self._card_proc("refresh", sync=True)
          # We set self._last_layout_change so that when self._last_layout_change is not the same
          # as `self.components.layout_last_changed_on`, then the component array itself
          # has been modified. So we should force a re-render of the card.
          self._last_layout_change = (
              self.components.layout_last_changed_on
          )
      else:
          self._card_proc("refresh")
  
imports: from .card_modules import MetaflowCardComponent
  from .card_modules.basic import ErrorComponent, SectionComponent
  from .card_modules.components import UserComponent, create_component_id, StubComponent
  from .exception import ComponentOverwriteNotSupportedException
  from metaflow.metaflow_config import RUNTIME_CARD_RENDER_INTERVAL
  import uuid
  import json
  import platform
  from collections import OrderedDict
  import time
label_desc: Use image node_id 6 for calling the CardComponentManager obj's underlying member method code with example usage: obj.refresh(data, force) without return types