def _get_value(self, ctx, node_state):
        # if there's a timestep func and nothing's changed apart from the
        # date look for a previous value and call the timestep func
        dirty_flags = node_state.dirty_flags
        if self._is_generator \
        and dirty_flags == DIRTY_FLAGS_TIME \
        and node_state.generator is not None: 
            # if this node has been valued already for this context
            # check the date and see if it can be updated from that
            try:
                # don't unpack as a tuple as the produces slighly more complicated cython code
                tmp = self._get_cached_value_and_date(ctx, node_state)
                prev_value = tmp[0]
                prev_date = tmp[1]
            except __HOLE__:
                prev_value, prev_date = None, None

            if prev_date is not None:
                date_cmp = cython.declare(int)
                date_cmp = 0 if prev_date == ctx._now else (-1 if prev_date < ctx._now else 1)
                if date_cmp == 0: # prev_date == ctx._now
                    self._touch(node_state, DIRTY_FLAGS_ALL, True)
                    return prev_value

                if date_cmp < 0: # prev_date < ctx._now
                    # if a filter's set check if the previous value can be re-used
                    if self._filter_func is not None:
                        if _profiling_enabled:
                            with ctx._profile(self) as timer:
                                needs_update = self._filter_func()
                        else:
                            needs_update = self._filter_func()

                        if not needs_update:
                            # re-use the previous value
                            if _trace_enabled:
                                _logger.debug("Re-using previous value of %s[%s]" % (self.name, ctx))

                            self._touch(node_state, DIRTY_FLAGS_ALL, True)
                            return prev_value

                    # call the timestep function with or without the context
                    if _trace_enabled:
                        _logger.debug("Evaluating next value of %s[%s]" % (self.name, ctx))

                    if _profiling_enabled:
                        with ctx._profile(self):
                            new_value = next(node_state.generator)
                    else:
                        new_value = next(node_state.generator)

                    return new_value

        # if still dirty call func to get the new value
        if _trace_enabled:
            _logger.debug("Evaluating %s[%s] (%s)" % (self.name,
                                                      ctx,
                                                      DIRTY_FLAGS.to_string(dirty_flags)))

        # call the function, set the value and return it
        if _profiling_enabled:
            with ctx._profile(self) as timer:
                value = self._func()
        else:
            value = self._func()

        if self._is_generator:
            gen = value

            # evaluate the generator
            if _profiling_enabled:
                with ctx._profile(self) as timer:
                    value = next(gen)
            else:
                value = next(gen)

            node_state.generator = iter(gen)

            # if a filter's set call it just to make sure any dependencies it requires
            # are set up correctly to avoid conditional dependency errors later
            if self._filter_func is not None:
                if _profiling_enabled:
                    with ctx._profile(self) as timer:
                        self._filter_func()
                else:
                    self._filter_func()

        return value
dataset/ETHPy150Open manahl/mdf/mdf/nodes.py/MDFEvalNode._get_value