nodes: 0, module; 1, function_definition; 2, function_name:wait; 3, parameters; 4, block; 5, identifier:self; 6, identifier:condition_or_value; 7, default_parameter; 8, expression_statement; 9, if_statement; 10, expression_statement; 11, expression_statement; 12, expression_statement; 13, if_statement; 14, function_definition; 15, expression_statement; 16, comment:# Handle case where sensor is already at the desired value; 17, expression_statement; 18, if_statement; 19, identifier:timeout; 20, None; 21, comment:"""Wait for the sensor to satisfy a condition.
  
          Parameters
          ----------
          condition_or_value : obj or callable, or seq of objs or callables
              If obj, sensor.value is compared with obj. If callable,
              condition_or_value(reading) is called, and must return True if its
              condition is satisfied. Since the reading is passed in, the value,
              status, timestamp or received_timestamp attributes can all be used
              in the check.
              TODO: Sequences of conditions (use SensorTransitionWaiter thingum?)
          timeout : float or None
              The timeout in seconds (None means wait forever)
  
          Returns
          -------
          This command returns a tornado Future that resolves with True when the
          sensor value satisfies the condition. It will never resolve with False;
          if a timeout is given a TimeoutError happens instead.
  
          Raises
          ------
          :class:`KATCPSensorError`
              If the sensor does not have a strategy set
          :class:`tornado.gen.TimeoutError`
              If the sensor condition still fails after a stated timeout period
  
          """; 22, parenthesized_expression; 23, block; 24, assignment; 25, assignment; 26, assignment; 27, comparison_operator:self.sampling_strategy == ('none', ); 28, block; 29, function_name:handle_update; 30, parameters; 31, comment:# This handler is called whenever a sensor update is received; 32, block; 33, call; 34, call; 35, identifier:timeout; 36, block; 37, else_clause; 38, boolean_operator; 39, raise_statement; 40, identifier:condition_test; 41, parenthesized_expression; 42, identifier:ioloop; 43, call; 44, identifier:f; 45, call; 46, attribute; 47, tuple; 48, raise_statement; 49, identifier:sensor; 50, identifier:reading; 51, try_statement; 52, attribute; 53, argument_list; 54, attribute; 55, argument_list; 56, expression_statement; 57, expression_statement; 58, comment:# Make sure we stop listening if the wait times out to prevent a; 59, comment:# buildup of listeners; 60, expression_statement; 61, return_statement; 62, block; 63, call; 64, not_operator; 65, call; 66, conditional_expression:condition_or_value if callable(condition_or_value)
                            else lambda s: s.value == condition_or_value; 67, attribute; 68, argument_list; 69, identifier:Future; 70, argument_list; 71, identifier:self; 72, identifier:sampling_strategy; 73, string; 74, call; 75, block; 76, except_clause; 77, identifier:self; 78, identifier:register_listener; 79, identifier:handle_update; 80, keyword_argument; 81, identifier:ioloop; 82, identifier:add_callback; 83, identifier:handle_update; 84, identifier:self; 85, attribute; 86, assignment; 87, assignment; 88, call; 89, identifier:timeout_f; 90, return_statement; 91, identifier:isinstance; 92, argument_list; 93, call; 94, identifier:NotImplementedError; 95, argument_list; 96, identifier:condition_or_value; 97, call; 98, lambda; 99, attribute; 100, identifier:current; 101, string_content:none; 102, identifier:KATCPSensorError; 103, argument_list; 104, assert_statement; 105, if_statement; 106, identifier:Exception; 107, block; 108, identifier:reading; 109, True; 110, identifier:self; 111, identifier:_reading; 112, identifier:to; 113, binary_operator:ioloop.time() + timeout; 114, identifier:timeout_f; 115, call; 116, attribute; 117, argument_list; 118, identifier:f; 119, identifier:condition_or_value; 120, attribute; 121, identifier:isinstance; 122, argument_list; 123, string; 124, identifier:callable; 125, argument_list; 126, lambda_parameters; 127, comparison_operator:s.value == condition_or_value; 128, attribute; 129, identifier:IOLoop; 130, string; 131, comparison_operator:sensor is self; 132, call; 133, block; 134, expression_statement; 135, expression_statement; 136, call; 137, identifier:timeout; 138, identifier:with_timeout; 139, argument_list; 140, identifier:timeout_f; 141, identifier:add_done_callback; 142, lambda; 143, identifier:collections; 144, identifier:Sequence; 145, identifier:condition_or_value; 146, identifier:basestring; 147, string_content:Currently only single conditions are supported; 148, identifier:condition_or_value; 149, identifier:s; 150, attribute; 151, identifier:condition_or_value; 152, identifier:tornado; 153, identifier:ioloop; 154, string_content:Cannot wait on a sensor that does not have a strategy set; 155, identifier:sensor; 156, identifier:self; 157, identifier:condition_test; 158, argument_list; 159, expression_statement; 160, comment:# Try and be idempotent if called multiple times after the; 161, comment:# condition is matched. This should not happen unless the; 162, comment:# sensor object is being updated in a thread outside of the; 163, comment:# ioloop.; 164, if_statement; 165, call; 166, call; 167, attribute; 168, argument_list; 169, identifier:to; 170, identifier:f; 171, lambda_parameters; 172, call; 173, identifier:s; 174, identifier:value; 175, identifier:reading; 176, call; 177, not_operator; 178, block; 179, attribute; 180, argument_list; 181, attribute; 182, argument_list; 183, identifier:ioloop; 184, identifier:time; 185, identifier:f; 186, attribute; 187, argument_list; 188, attribute; 189, argument_list; 190, call; 191, expression_statement; 192, identifier:f; 193, identifier:set_exc_info; 194, call; 195, identifier:self; 196, identifier:unregister_listener; 197, identifier:handle_update; 198, identifier:self; 199, identifier:unregister_listener; 200, identifier:handle_update; 201, identifier:self; 202, identifier:unregister_listener; 203, identifier:handle_update; 204, attribute; 205, argument_list; 206, call; 207, attribute; 208, argument_list; 209, identifier:f; 210, identifier:done; 211, attribute; 212, argument_list; 213, identifier:sys; 214, identifier:exc_info; 215, identifier:ioloop; 216, identifier:add_callback; 217, attribute; 218, True; 219, identifier:f; 220, identifier:set_result
code: def wait(self, condition_or_value, timeout=None):
          """Wait for the sensor to satisfy a condition.
  
          Parameters
          ----------
          condition_or_value : obj or callable, or seq of objs or callables
              If obj, sensor.value is compared with obj. If callable,
              condition_or_value(reading) is called, and must return True if its
              condition is satisfied. Since the reading is passed in, the value,
              status, timestamp or received_timestamp attributes can all be used
              in the check.
              TODO: Sequences of conditions (use SensorTransitionWaiter thingum?)
          timeout : float or None
              The timeout in seconds (None means wait forever)
  
          Returns
          -------
          This command returns a tornado Future that resolves with True when the
          sensor value satisfies the condition. It will never resolve with False;
          if a timeout is given a TimeoutError happens instead.
  
          Raises
          ------
          :class:`KATCPSensorError`
              If the sensor does not have a strategy set
          :class:`tornado.gen.TimeoutError`
              If the sensor condition still fails after a stated timeout period
  
          """
          if (isinstance(condition_or_value, collections.Sequence) and not
                  isinstance(condition_or_value, basestring)):
              raise NotImplementedError(
                  'Currently only single conditions are supported')
          condition_test = (condition_or_value if callable(condition_or_value)
                            else lambda s: s.value == condition_or_value)
  
          ioloop = tornado.ioloop.IOLoop.current()
          f = Future()
          if self.sampling_strategy == ('none', ):
              raise KATCPSensorError(
                  'Cannot wait on a sensor that does not have a strategy set')
  
          def handle_update(sensor, reading):
              # This handler is called whenever a sensor update is received
              try:
                  assert sensor is self
                  if condition_test(reading):
                      self.unregister_listener(handle_update)
                      # Try and be idempotent if called multiple times after the
                      # condition is matched. This should not happen unless the
                      # sensor object is being updated in a thread outside of the
                      # ioloop.
                      if not f.done():
                          ioloop.add_callback(f.set_result, True)
              except Exception:
                  f.set_exc_info(sys.exc_info())
                  self.unregister_listener(handle_update)
  
          self.register_listener(handle_update, reading=True)
          # Handle case where sensor is already at the desired value
          ioloop.add_callback(handle_update, self, self._reading)
  
          if timeout:
              to = ioloop.time() + timeout
              timeout_f = with_timeout(to, f)
              # Make sure we stop listening if the wait times out to prevent a
              # buildup of listeners
              timeout_f.add_done_callback(
                  lambda f: self.unregister_listener(handle_update))
              return timeout_f
          else:
              return f