def set_center_freq(self, center_freq):
        """Set center frequency and clear averaged PSD data"""
        psd_state = {
            'repeats': 0,
            'freq_array': self._base_freq_array + self._lnb_lo + center_freq,
            'pwr_array': None,
            'update_lock': threading.Lock(),
            'futures': [],
        }
        return psd_state

def set_center_freq ( self , center_freq ) : psd_state = { 'repeats' : 0 , 'freq_array' : self . _base_freq_array + self . _lnb_lo + center_freq , 'pwr_array' : None , 'update_lock' : threading . Lock ( ) , 'futures' : [ ] , } return psd_state


def result(self, psd_state):
        """Return freqs and averaged PSD for given center frequency"""
        freq_array = numpy.fft.fftshift(psd_state['freq_array'])
        pwr_array = numpy.fft.fftshift(psd_state['pwr_array'])

        if self._crop_factor:
            crop_bins_half = round((self._crop_factor * self._bins) / 2)
            freq_array = freq_array[crop_bins_half:-crop_bins_half]
            pwr_array = pwr_array[crop_bins_half:-crop_bins_half]

        if psd_state['repeats'] > 1:
            pwr_array = pwr_array / psd_state['repeats']

        if self._log_scale:
            pwr_array = 10 * numpy.log10(pwr_array)

        return (freq_array, pwr_array)

def result ( self , psd_state ) : freq_array = numpy . fft . fftshift ( psd_state [ 'freq_array' ] ) pwr_array = numpy . fft . fftshift ( psd_state [ 'pwr_array' ] ) if self . _crop_factor : crop_bins_half = round ( ( self . _crop_factor * self . _bins ) / 2 ) freq_array = freq_array [ crop_bins_half : - crop_bins_half ] pwr_array = pwr_array [ crop_bins_half : - crop_bins_half ] if psd_state [ 'repeats' ] > 1 : pwr_array = pwr_array / psd_state [ 'repeats' ] if self . _log_scale : pwr_array = 10 * numpy . log10 ( pwr_array ) return ( freq_array , pwr_array )


def wait_for_result(self, psd_state):
        """Wait for all PSD threads to finish and return result"""
        if len(psd_state['futures']) > 1:
            concurrent.futures.wait(psd_state['futures'])
        elif psd_state['futures']:
            psd_state['futures'][0].result()
        return self.result(psd_state)

def wait_for_result ( self , psd_state ) : if len ( psd_state [ 'futures' ] ) > 1 : concurrent . futures . wait ( psd_state [ 'futures' ] ) elif psd_state [ 'futures' ] : psd_state [ 'futures' ] [ 0 ] . result ( ) return self . result ( psd_state )


def update(self, psd_state, samples_array):
        """Compute PSD from samples and update average for given center frequency"""
        freq_array, pwr_array = simplespectral.welch(samples_array, self._sample_rate, nperseg=self._bins,
                                                     window=self._fft_window, noverlap=self._fft_overlap_bins,
                                                     detrend=self._detrend)

        if self._remove_dc:
            pwr_array[0] = (pwr_array[1] + pwr_array[-1]) / 2

        with psd_state['update_lock']:
            psd_state['repeats'] += 1
            if psd_state['pwr_array'] is None:
                psd_state['pwr_array'] = pwr_array
            else:
                psd_state['pwr_array'] += pwr_array

def update ( self , psd_state , samples_array ) : freq_array , pwr_array = simplespectral . welch ( samples_array , self . _sample_rate , nperseg = self . _bins , window = self . _fft_window , noverlap = self . _fft_overlap_bins , detrend = self . _detrend ) if self . _remove_dc : pwr_array [ 0 ] = ( pwr_array [ 1 ] + pwr_array [ - 1 ] ) / 2 with psd_state [ 'update_lock' ] : psd_state [ 'repeats' ] += 1 if psd_state [ 'pwr_array' ] is None : psd_state [ 'pwr_array' ] = pwr_array else : psd_state [ 'pwr_array' ] += pwr_array


def read(self, f):
        """Read data from file-like object"""
        magic = f.read(len(self.magic))
        if not magic:
            return None
        if magic != self.magic:
            raise ValueError('Magic bytes not found! Read data: {}'.format(magic))

        header = self.header._make(
            self.header_struct.unpack(f.read(self.header_struct.size))
        )
        pwr_array = numpy.fromstring(f.read(header.size), dtype='float32')
        return (header, pwr_array)

def
read
(
self
,
f
)
:
magic
=
f
.
read
(
len
(
self
.
magic
)
)
if
not
magic
:
return
if
magic
!=
self
.
magic
:
raise
ValueError
(
'Magic bytes not found! Read data: {}'
.
format
(
magic
)
)
header
=
self
.
header
.
_make
(
self
.
header_struct
.
unpack
(
f
.
read
(
self
.
header_struct
.
size
)
)
)
pwr_array
=
numpy
.
fromstring
(
f
.
read
(
header
.
size
)
,
dtype
=
'float32'
)
return
(
header
,
pwr_array
)


def write(self, f, time_start, time_stop, start, stop, step, samples, pwr_array):
        """Write data to file-like object"""
        f.write(self.magic)
        f.write(self.header_struct.pack(
            self.version, time_start, time_stop, start, stop, step, samples, pwr_array.nbytes
        ))
        #pwr_array.tofile(f)
        f.write(pwr_array.tobytes())
        f.flush()

def write ( self , f , time_start , time_stop , start , stop , step , samples , pwr_array ) : f . write ( self . magic ) f . write ( self . header_struct . pack ( self . version , time_start , time_stop , start , stop , step , samples , pwr_array . nbytes ) ) #pwr_array.tofile(f) f . write ( pwr_array . tobytes ( ) ) f . flush ( )


def submit(self, fn, *args, **kwargs):
        """Submits a callable to be executed with the given arguments.

        Count maximum reached work queue size in ThreadPoolExecutor.max_queue_size_reached.
        """
        future = super().submit(fn, *args, **kwargs)
        work_queue_size = self._work_queue.qsize()
        if work_queue_size > self.max_queue_size_reached:
            self.max_queue_size_reached = work_queue_size
        return future

def submit ( self , fn , * args , * * kwargs ) : future = super ( ) . submit ( fn , * args , * * kwargs ) work_queue_size = self . _work_queue . qsize ( ) if work_queue_size > self . max_queue_size_reached : self . max_queue_size_reached = work_queue_size return future

Submits a callable to be executed with the given arguments .


def time_to_repeats(self, bins, integration_time):
        """Convert integration time to number of repeats"""
        return math.ceil((self.device.sample_rate * integration_time) / bins)

def time_to_repeats ( self , bins , integration_time ) : return math . ceil ( ( self . device . sample_rate * integration_time ) / bins )


def freq_plan(self, min_freq, max_freq, bins, overlap=0, quiet=False):
        """Returns list of frequencies for frequency hopping"""
        bin_size = self.bins_to_bin_size(bins)
        bins_crop = round((1 - overlap) * bins)
        sample_rate_crop = (1 - overlap) * self.device.sample_rate

        freq_range = max_freq - min_freq
        hopping = True if freq_range >= sample_rate_crop else False
        hop_size = self.nearest_freq(sample_rate_crop, bin_size)
        hops = math.ceil(freq_range / hop_size) if hopping else 1
        min_center_freq = min_freq + (hop_size / 2) if hopping else min_freq + (freq_range / 2)
        max_center_freq = min_center_freq + ((hops - 1) * hop_size)

        freq_list = [min_center_freq + (i * hop_size) for i in range(hops)]

        if not quiet:
            logger.info('overlap: {:.5f}'.format(overlap))
            logger.info('bin_size: {:.2f} Hz'.format(bin_size))
            logger.info('bins: {}'.format(bins))
            logger.info('bins (after crop): {}'.format(bins_crop))
            logger.info('sample_rate: {:.3f} MHz'.format(self.device.sample_rate / 1e6))
            logger.info('sample_rate (after crop): {:.3f} MHz'.format(sample_rate_crop / 1e6))
            logger.info('freq_range: {:.3f} MHz'.format(freq_range / 1e6))
            logger.info('hopping: {}'.format('YES' if hopping else 'NO'))
            logger.info('hop_size: {:.3f} MHz'.format(hop_size / 1e6))
            logger.info('hops: {}'.format(hops))
            logger.info('min_center_freq: {:.3f} MHz'.format(min_center_freq / 1e6))
            logger.info('max_center_freq: {:.3f} MHz'.format(max_center_freq / 1e6))
            logger.info('min_freq (after crop): {:.3f} MHz'.format((min_center_freq - (hop_size / 2)) / 1e6))
            logger.info('max_freq (after crop): {:.3f} MHz'.format((max_center_freq + (hop_size / 2)) / 1e6))

            logger.debug('Frequency hops table:')
            logger.debug('  {:8s}      {:8s}      {:8s}'.format('Min:', 'Center:', 'Max:'))
            for f in freq_list:
                logger.debug('  {:8.3f} MHz  {:8.3f} MHz  {:8.3f} MHz'.format(
                    (f - (self.device.sample_rate / 2)) / 1e6,
                    f / 1e6,
                    (f + (self.device.sample_rate / 2)) / 1e6,
                ))

        return freq_list


def create_buffer(self, bins, repeats, base_buffer_size, max_buffer_size=0):
        """Create buffer for reading samples"""
        samples = bins * repeats
        buffer_repeats = 1
        buffer_size = math.ceil(samples / base_buffer_size) * base_buffer_size

        if not max_buffer_size:
            # Max buffer size about 100 MB
            max_buffer_size = (100 * 1024**2) / 8

        if max_buffer_size > 0:
            max_buffer_size = math.ceil(max_buffer_size / base_buffer_size) * base_buffer_size
            if buffer_size > max_buffer_size:
                logger.warning('Required buffer size ({}) will be shrinked to max_buffer_size ({})!'.format(
                    buffer_size, max_buffer_size
                ))
                buffer_repeats = math.ceil(buffer_size / max_buffer_size)
                buffer_size = max_buffer_size

        logger.info('repeats: {}'.format(repeats))
        logger.info('samples: {} (time: {:.5f} s)'.format(samples, samples / self.device.sample_rate))
        if max_buffer_size > 0:
            logger.info('max_buffer_size (samples): {} (repeats: {:.2f}, time: {:.5f} s)'.format(
                max_buffer_size, max_buffer_size / bins, max_buffer_size / self.device.sample_rate
            ))
        else:
            logger.info('max_buffer_size (samples): UNLIMITED')
        logger.info('buffer_size (samples): {} (repeats: {:.2f}, time: {:.5f} s)'.format(
            buffer_size, buffer_size / bins, buffer_size / self.device.sample_rate
        ))
        logger.info('buffer_repeats: {}'.format(buffer_repeats))

        return (buffer_repeats, zeros(buffer_size, numpy.complex64))


def setup(self, bins, repeats, base_buffer_size=0, max_buffer_size=0, fft_window='hann',
              fft_overlap=0.5, crop_factor=0, log_scale=True, remove_dc=False, detrend=None,
              lnb_lo=0, tune_delay=0, reset_stream=False, max_threads=0, max_queue_size=0):
        """Prepare samples buffer and start streaming samples from device"""
        if self.device.is_streaming:
            self.device.stop_stream()

        base_buffer = self.device.start_stream(buffer_size=base_buffer_size)
        self._bins = bins
        self._repeats = repeats
        self._base_buffer_size = len(base_buffer)
        self._max_buffer_size = max_buffer_size
        self._buffer_repeats, self._buffer = self.create_buffer(
            bins, repeats, self._base_buffer_size, self._max_buffer_size
        )
        self._tune_delay = tune_delay
        self._reset_stream = reset_stream
        self._psd = psd.PSD(bins, self.device.sample_rate, fft_window=fft_window, fft_overlap=fft_overlap,
                            crop_factor=crop_factor, log_scale=log_scale, remove_dc=remove_dc, detrend=detrend,
                            lnb_lo=lnb_lo, max_threads=max_threads, max_queue_size=max_queue_size)
        self._writer = writer.formats[self._output_format](self._output)

def setup ( self , bins , repeats , base_buffer_size = 0 , max_buffer_size = 0 , fft_window = 'hann' , fft_overlap = 0.5 , crop_factor = 0 , log_scale = True , remove_dc = False , detrend = None , lnb_lo = 0 , tune_delay = 0 , reset_stream = False , max_threads = 0 , max_queue_size = 0 ) : if self . device . is_streaming : self . device . stop_stream ( ) base_buffer = self . device . start_stream ( buffer_size = base_buffer_size ) self . _bins = bins self . _repeats = repeats self . _base_buffer_size = len ( base_buffer ) self . _max_buffer_size = max_buffer_size self . _buffer_repeats , self . _buffer = self . create_buffer ( bins , repeats , self . _base_buffer_size , self . _max_buffer_size ) self . _tune_delay = tune_delay self . _reset_stream = reset_stream self . _psd = psd . PSD ( bins , self . device . sample_rate , fft_window = fft_window , fft_overlap = fft_overlap , crop_factor = crop_factor , log_scale = log_scale , remove_dc = remove_dc , detrend = detrend , lnb_lo = lnb_lo , max_threads = max_threads , max_queue_size = max_queue_size ) self . _writer = writer . formats [ self . _output_format ] ( self . _output )


def stop(self):
        """Stop streaming samples from device and delete samples buffer"""
        if not self.device.is_streaming:
            return

        self.device.stop_stream()
        self._writer.close()

        self._bins = None
        self._repeats = None
        self._base_buffer_size = None
        self._max_buffer_size = None
        self._buffer_repeats = None
        self._buffer = None
        self._tune_delay = None
        self._reset_stream = None
        self._psd = None
        self._writer = None

def stop ( self ) : if not self . device . is_streaming : return self . device . stop_stream ( ) self . _writer . close ( ) self . _bins = None self . _repeats = None self . _base_buffer_size = None self . _max_buffer_size = None self . _buffer_repeats = None self . _buffer = None self . _tune_delay = None self . _reset_stream = None self . _psd = None self . _writer = None


def psd(self, freq):
        """Tune to specified center frequency and compute Power Spectral Density"""
        if not self.device.is_streaming:
            raise RuntimeError('Streaming is not initialized, you must run setup() first!')

        # Tune to new frequency in main thread
        logger.debug('  Frequency hop: {:.2f} Hz'.format(freq))
        t_freq = time.time()
        if self.device.freq != freq:
            # Deactivate streaming before tuning
            if self._reset_stream:
                self.device.device.deactivateStream(self.device.stream)

            # Actually tune to new center frequency
            self.device.freq = freq

            # Reactivate straming after tuning
            if self._reset_stream:
                self.device.device.activateStream(self.device.stream)

            # Delay reading samples after tuning
            if self._tune_delay:
                t_delay = time.time()
                while True:
                    self.device.read_stream()
                    t_delay_end = time.time()
                    if t_delay_end - t_delay >= self._tune_delay:
                        break
                logger.debug('    Tune delay: {:.3f} s'.format(t_delay_end - t_delay))
        else:
            logger.debug('    Same frequency as before, tuning skipped')
        psd_state = self._psd.set_center_freq(freq)
        t_freq_end = time.time()
        logger.debug('    Tune time: {:.3f} s'.format(t_freq_end - t_freq))

        for repeat in range(self._buffer_repeats):
            logger.debug('    Repeat: {}'.format(repeat + 1))
            # Read samples from SDR in main thread
            t_acq = time.time()
            acq_time_start = datetime.datetime.utcnow()
            self.device.read_stream_into_buffer(self._buffer)
            acq_time_stop = datetime.datetime.utcnow()
            t_acq_end = time.time()
            logger.debug('      Acquisition time: {:.3f} s'.format(t_acq_end - t_acq))

            # Start FFT computation in another thread
            self._psd.update_async(psd_state, numpy.copy(self._buffer))

            t_final = time.time()

            if _shutdown:
                break

        psd_future = self._psd.result_async(psd_state)
        logger.debug('    Total hop time: {:.3f} s'.format(t_final - t_freq))

        return (psd_future, acq_time_start, acq_time_stop)


def sweep(self, min_freq, max_freq, bins, repeats, runs=0, time_limit=0, overlap=0,
              fft_window='hann', fft_overlap=0.5, crop=False, log_scale=True, remove_dc=False, detrend=None, lnb_lo=0,
              tune_delay=0, reset_stream=False, base_buffer_size=0, max_buffer_size=0, max_threads=0, max_queue_size=0):
        """Sweep spectrum using frequency hopping"""
        self.setup(
            bins, repeats, base_buffer_size, max_buffer_size,
            fft_window=fft_window, fft_overlap=fft_overlap, crop_factor=overlap if crop else 0,
            log_scale=log_scale, remove_dc=remove_dc, detrend=detrend, lnb_lo=lnb_lo, tune_delay=tune_delay,
            reset_stream=reset_stream, max_threads=max_threads, max_queue_size=max_queue_size
        )

        try:
            freq_list = self.freq_plan(min_freq - lnb_lo, max_freq - lnb_lo, bins, overlap)
            t_start = time.time()
            run = 0
            while not _shutdown and (runs == 0 or run < runs):
                run += 1
                t_run_start = time.time()
                logger.debug('Run: {}'.format(run))

                for freq in freq_list:
                    # Tune to new frequency, acquire samples and compute Power Spectral Density
                    psd_future, acq_time_start, acq_time_stop = self.psd(freq)

                    # Write PSD to stdout (in another thread)
                    self._writer.write_async(psd_future, acq_time_start, acq_time_stop,
                                             len(self._buffer) * self._buffer_repeats)

                    if _shutdown:
                        break

                # Write end of measurement marker (in another thread)
                write_next_future = self._writer.write_next_async()
                t_run = time.time()
                logger.debug('  Total run time: {:.3f} s'.format(t_run - t_run_start))

                # End measurement if time limit is exceeded
                if time_limit and (time.time() - t_start) >= time_limit:
                    logger.info('Time limit of {} s exceeded, completed {} runs'.format(time_limit, run))
                    break

            # Wait for last write to be finished
            write_next_future.result()

            # Debug thread pool queues
            logging.debug('Number of USB buffer overflow errors: {}'.format(self.device.buffer_overflow_count))
            logging.debug('PSD worker threads: {}'.format(self._psd._executor._max_workers))
            logging.debug('Max. PSD queue size: {} / {}'.format(self._psd._executor.max_queue_size_reached,
                                                                self._psd._executor.max_queue_size))
            logging.debug('Writer worker threads: {}'.format(self._writer._executor._max_workers))
            logging.debug('Max. Writer queue size: {} / {}'.format(self._writer._executor.max_queue_size_reached,
                                                                   self._writer._executor.max_queue_size))
        finally:
            # Shutdown SDR
            self.stop()
            t_stop = time.time()
            logger.info('Total time: {:.3f} s'.format(t_stop - t_start))


def _set_addr(self, addr):
        """private helper method"""
        if self._addr != addr:
            ioctl(self._fd, SMBUS.I2C_SLAVE, addr)
            self._addr = addr

def _set_addr ( self , addr ) : if self . _addr != addr : ioctl ( self . _fd , SMBUS . I2C_SLAVE , addr ) self . _addr = addr


def run_cmake(arg=""):
    """
    Forcing to run cmake
    """
    if ds.find_executable('cmake') is None:
        print "CMake  is required to build zql"
        print "Please install cmake version >= 2.8 and re-run setup"
        sys.exit(-1)

    print "Configuring zql build with CMake.... "
    cmake_args = arg
    try:
        build_dir = op.join(op.split(__file__)[0], 'build')
        dd.mkpath(build_dir)
        os.chdir("build")
        ds.spawn(['cmake', '..'] + cmake_args.split())
        ds.spawn(['make', 'clean'])
        ds.spawn(['make'])
        os.chdir("..")
    except ds.DistutilsExecError:
        print "Error while running cmake"
        print "run 'setup.py build --help' for build options"
        print "You may also try editing the settings in CMakeLists.txt file and re-running setup"
        sys.exit(-1)


def filter(cls, datetimes, number, now=None, **options):
        """Return a set of datetimes, after filtering ``datetimes``.

        The result will be the ``datetimes`` which are ``number`` of
        units before ``now``, until ``now``, with approximately one
        unit between each of them.  The first datetime for any unit is
        kept, later duplicates are removed.

        If there are ``datetimes`` after ``now``, they will be
        returned unfiltered.
        """
        if not isinstance(number, int) or number < 0:
            raise ValueError('Invalid number: %s' % number)

        datetimes = tuple(datetimes)

        # Sample the first datetime to see if it is timezone-aware
        tzinfo = None
        if datetimes and datetimes[0].tzinfo is not None:
            tzinfo = UTC()

        if now is None:
            now = datetime.now(tzinfo)

        if not hasattr(now, 'second'):
            # now looks like a date, so convert it into a datetime
            now = datetime.combine(now, time(23, 59, 59, 999999, tzinfo=tzinfo))

        # Always keep datetimes from the future
        future = set(dt for dt in datetimes if dt > now)

        if number == 0:
            return future

        # Don't consider datetimes from before the start
        start = cls.start(now, number, **options)
        valid = (dt for dt in datetimes if start <= dt <= now)

        # Deduplicate datetimes with the same mask() value by keeping
        # the oldest.
        kept = {}
        for dt in sorted(valid):
            kept.setdefault(cls.mask(dt, **options), dt)

        return set(kept.values()) | future

Return a set of datetimes after filtering datetimes .


def mask(cls, dt, **options):
        """
        Return a datetime with the same value as ``dt``, to a
        resolution of days.
        """
        return dt.replace(hour=0, minute=0, second=0, microsecond=0)

def mask ( cls , dt , * * options ) : return dt . replace ( hour = 0 , minute = 0 , second = 0 , microsecond = 0 )

Return a datetime with the same value as dt to a resolution of days .


def mask(cls, dt, firstweekday=calendar.SATURDAY, **options):
        """
        Return a datetime with the same value as ``dt``, to a
        resolution of weeks.

        ``firstweekday`` determines when the week starts. It defaults
        to Saturday.
        """
        correction = (dt.weekday() - firstweekday) % cls.DAYS_IN_WEEK
        week = dt - timedelta(days=correction)
        return week.replace(hour=0, minute=0, second=0, microsecond=0)

def mask ( cls , dt , firstweekday = calendar . SATURDAY , * * options ) : correction = ( dt . weekday ( ) - firstweekday ) % cls . DAYS_IN_WEEK week = dt - timedelta ( days = correction ) return week . replace ( hour = 0 , minute = 0 , second = 0 , microsecond = 0 )

Return a datetime with the same value as dt to a resolution of weeks .


def to_keep(datetimes,
            years=0, months=0, weeks=0, days=0,
            hours=0, minutes=0, seconds=0,
            firstweekday=SATURDAY, now=None):
    """
    Return a set of datetimes that should be kept, out of ``datetimes``.

    Keeps up to ``years``, ``months``, ``weeks``, ``days``,
    ``hours``, ``minutes``, and ``seconds`` in the past.

    When keeping weeks, it prefers to keep ``firstweekday``, which
    defaults to Saturday.

    If ``now`` is None, it will base its calculations on
    ``datetime.datetime.now()``. Datetimes after this point will always be
    kept.
    """
    datetimes = set(datetimes)
    return (filters.Years.filter(datetimes, number=years, now=now) |
            filters.Months.filter(datetimes, number=months, now=now) |
            filters.Weeks.filter(datetimes, number=weeks,
                                 firstweekday=firstweekday, now=now) |
            filters.Days.filter(datetimes, number=days, now=now) |
            filters.Hours.filter(datetimes, number=hours, now=now) |
            filters.Minutes.filter(datetimes, number=minutes, now=now) |
            filters.Seconds.filter(datetimes, number=seconds, now=now))

def to_keep ( datetimes , years = 0 , months = 0 , weeks = 0 , days = 0 , hours = 0 , minutes = 0 , seconds = 0 , firstweekday = SATURDAY , now = None ) : datetimes = set ( datetimes ) return ( filters . Years . filter ( datetimes , number = years , now = now ) | filters . Months . filter ( datetimes , number = months , now = now ) | filters . Weeks . filter ( datetimes , number = weeks , firstweekday = firstweekday , now = now ) | filters . Days . filter ( datetimes , number = days , now = now ) | filters . Hours . filter ( datetimes , number = hours , now = now ) | filters . Minutes . filter ( datetimes , number = minutes , now = now ) | filters . Seconds . filter ( datetimes , number = seconds , now = now ) )

Return a set of datetimes that should be kept out of datetimes .


def to_delete(datetimes,
              years=0, months=0, weeks=0, days=0,
              hours=0, minutes=0, seconds=0,
              firstweekday=SATURDAY, now=None):
    """
    Return a set of datetimes that should be deleted, out of ``datetimes``.

    See ``to_keep`` for a description of arguments.
    """
    datetimes = set(datetimes)
    return datetimes - to_keep(datetimes,
                               years=years, months=months,
                               weeks=weeks, days=days,
                               hours=hours, minutes=minutes, seconds=seconds,
                               firstweekday=firstweekday, now=now)

def to_delete ( datetimes , years = 0 , months = 0 , weeks = 0 , days = 0 , hours = 0 , minutes = 0 , seconds = 0 , firstweekday = SATURDAY , now = None ) : datetimes = set ( datetimes ) return datetimes - to_keep ( datetimes , years = years , months = months , weeks = weeks , days = days , hours = hours , minutes = minutes , seconds = seconds , firstweekday = firstweekday , now = now )

Return a set of datetimes that should be deleted out of datetimes .


def dates_to_keep(dates,
                  years=0, months=0, weeks=0, days=0, firstweekday=SATURDAY,
                  now=None):
    """
    Return a set of dates that should be kept, out of ``dates``.

    See ``to_keep`` for a description of arguments.
    """
    datetimes = to_keep((datetime.combine(d, time()) for d in dates),
                        years=years, months=months, weeks=weeks, days=days,
                        hours=0, minutes=0, seconds=0,
                        firstweekday=firstweekday, now=now)
    return set(dt.date() for dt in datetimes)

def dates_to_keep ( dates , years = 0 , months = 0 , weeks = 0 , days = 0 , firstweekday = SATURDAY , now = None ) : datetimes = to_keep ( ( datetime . combine ( d , time ( ) ) for d in dates ) , years = years , months = months , weeks = weeks , days = days , hours = 0 , minutes = 0 , seconds = 0 , firstweekday = firstweekday , now = now ) return set ( dt . date ( ) for dt in datetimes )

Return a set of dates that should be kept out of dates .


def dates_to_delete(dates,
                    years=0, months=0, weeks=0, days=0, firstweekday=SATURDAY,
                    now=None):
    """
    Return a set of date that should be deleted, out of ``dates``.

    See ``to_keep`` for a description of arguments.
    """
    dates = set(dates)
    return dates - dates_to_keep(dates,
                                 years=years, months=months,
                                 weeks=weeks, days=days,
                                 firstweekday=firstweekday, now=now)

def dates_to_delete ( dates , years = 0 , months = 0 , weeks = 0 , days = 0 , firstweekday = SATURDAY , now = None ) : dates = set ( dates ) return dates - dates_to_keep ( dates , years = years , months = months , weeks = weeks , days = days , firstweekday = firstweekday , now = now )

Return a set of date that should be deleted out of dates .


def _get_spi_control_byte(self, read_write_cmd):
        """Returns an SPI control byte.

        The MCP23S17 is a slave SPI device. The slave address contains
        four fixed bits and three user-defined hardware address bits
        (if enabled via IOCON.HAEN) (pins A2, A1 and A0) with the
        read/write bit filling out the control byte::

            +--------------------+
            |0|1|0|0|A2|A1|A0|R/W|
            +--------------------+
             7 6 5 4 3  2  1   0

        :param read_write_cmd: Read or write command.
        :type read_write_cmd: int
        """
        # board_addr_pattern = (self.hardware_addr & 0b111) << 1
        board_addr_pattern = (self.hardware_addr << 1) & 0xE
        rw_cmd_pattern = read_write_cmd & 1  # make sure it's just 1 bit long
        return 0x40 | board_addr_pattern | rw_cmd_pattern


def read_bit(self, bit_num, address):
        """Returns the bit specified from the address.

        :param bit_num: The bit number to read from.
        :type bit_num: int
        :param address: The address to read from.
        :type address: int
        :returns: int -- the bit value from the address
        """
        value = self.read(address)
        bit_mask = get_bit_mask(bit_num)
        return 1 if value & bit_mask else 0

def read_bit ( self , bit_num , address ) : value = self . read ( address ) bit_mask = get_bit_mask ( bit_num ) return 1 if value & bit_mask else 0

Returns the bit specified from the address .


def write_bit(self, value, bit_num, address):
        """Writes the value given to the bit in the address specified.

        :param value: The value to write.
        :type value: int
        :param bit_num: The bit number to write to.
        :type bit_num: int
        :param address: The address to write to.
        :type address: int
        """
        bit_mask = get_bit_mask(bit_num)
        old_byte = self.read(address)
         # generate the new byte
        if value:
            new_byte = old_byte | bit_mask
        else:
            new_byte = old_byte & ~bit_mask
        self.write(new_byte, address)

def
write_bit
(
self
,
value
,
bit_num
,
address
)
:
bit_mask
=
get_bit_mask
(
bit_num
)
old_byte
=
self
.
read
(
address
)
# generate the new byte
if
value
:
new_byte
=
old_byte
|
bit_mask
else
:
new_byte
=
old_byte
&
~
bit_mask
self
.
write
(
new_byte
,
address
)

Writes the value given to the bit in the address specified .


def get_bit_num(bit_pattern):
    """Returns the lowest bit num from a given bit pattern. Returns None if no
    bits set.

    :param bit_pattern: The bit pattern.
    :type bit_pattern: int
    :returns: int -- the bit number
    :returns: None -- no bits set

    >>> pifacecommon.core.get_bit_num(0)
    None
    >>> pifacecommon.core.get_bit_num(0b1)
    0
    >>> pifacecommon.core.get_bit_num(0b11000)
    3
    """
    if bit_pattern == 0:
        return None

    bit_num = 0  # assume bit 0
    while (bit_pattern & 1) == 0:
        bit_pattern = bit_pattern >> 1
        bit_num += 1
        if bit_num > 7:
            bit_num = 0
            break

    return bit_num

Returns the lowest bit num from a given bit pattern . Returns None if no bits set .


def watch_port_events(port, chip, pin_function_maps, event_queue,
                      return_after_kbdint=False):
    """Waits for a port event. When a port event occurs it is placed onto the
    event queue.

    :param port: The port we are waiting for interrupts on (GPIOA/GPIOB).
    :type port: int
    :param chip: The chip we are waiting for interrupts on.
    :type chip: :class:`pifacecommon.mcp23s17.MCP23S17`
    :param pin_function_maps: A list of classes that have inheritted from
        :class:`FunctionMap`\ s describing what to do with events.
    :type pin_function_maps: list
    :param event_queue: A queue to put events on.
    :type event_queue: :py:class:`multiprocessing.Queue`
    """
    # set up epoll
    gpio25 = open(GPIO_INTERRUPT_DEVICE_VALUE, 'r')  # change to use 'with'?
    epoll = select.epoll()
    epoll.register(gpio25, select.EPOLLIN | select.EPOLLET)

    while True:
        # wait here until input
        try:
            events = epoll.poll()
        except KeyboardInterrupt as e:
            if return_after_kbdint:
                return
            else:
                raise e
        except IOError as e:
            # ignore "Interrupted system call" error.
            # I don't really like this solution. Ignoring problems is bad!
            if e.errno != errno.EINTR:
                raise

        # find out where the interrupt came from and put it on the event queue
        if port == pifacecommon.mcp23s17.GPIOA:
            interrupt_flag = chip.intfa.value
        else:
            interrupt_flag = chip.intfb.value

        if interrupt_flag == 0:
            continue  # The interrupt has not been flagged on this board
        else:
            if port == pifacecommon.mcp23s17.GPIOA:
                interrupt_capture = chip.intcapa.value
            else:
                interrupt_capture = chip.intcapb.value
            event_queue.add_event(InterruptEvent(
                interrupt_flag, interrupt_capture, chip, time.time()))

    epoll.close()

Waits for a port event . When a port event occurs it is placed onto the event queue .


def handle_events(
        function_maps, event_queue, event_matches_function_map,
        terminate_signal):
    """Waits for events on the event queue and calls the registered functions.

    :param function_maps: A list of classes that have inheritted from
        :class:`FunctionMap`\ s describing what to do with events.
    :type function_maps: list
    :param event_queue: A queue to put events on.
    :type event_queue: :py:class:`multiprocessing.Queue`
    :param event_matches_function_map: A function that determines if the given
        event and :class:`FunctionMap` match.
    :type event_matches_function_map: function
    :param terminate_signal: The signal that, when placed on the event queue,
        causes this function to exit.
    """
    while True:
        # print("HANDLE: Waiting for events!")
        event = event_queue.get()
        # print("HANDLE: It's an event!")
        if event == terminate_signal:
            return
        # if matching get the callback function, else function is None
        functions = map(
            lambda fm: fm.callback
            if event_matches_function_map(event, fm) else None,
            function_maps)
        # reduce to just the callback functions (remove None)
        # TODO: I think this can just be filter(None, functions)
        functions = filter(lambda f: f is not None, functions)

        for function in functions:
            function(event)

Waits for events on the event queue and calls the registered functions .


def bring_gpio_interrupt_into_userspace():  # activate gpio interrupt
    """Bring the interrupt pin on the GPIO into Linux userspace."""
    try:
        # is it already there?
        with open(GPIO_INTERRUPT_DEVICE_VALUE):
            return
    except IOError:
        # no, bring it into userspace
        with open(GPIO_EXPORT_FILE, 'w') as export_file:
            export_file.write(str(GPIO_INTERRUPT_PIN))

        wait_until_file_exists(GPIO_INTERRUPT_DEVICE_VALUE)

def
bring_gpio_interrupt_into_userspace
(
)
:
# activate gpio interrupt
try
:
# is it already there?
with
open
(
GPIO_INTERRUPT_DEVICE_VALUE
)
:
return
except
IOError
:
# no, bring it into userspace
with
open
(
GPIO_EXPORT_FILE
,
'w'
)
as
export_file
:
export_file
.
write
(
str
(
GPIO_INTERRUPT_PIN
)
)
wait_until_file_exists
(
GPIO_INTERRUPT_DEVICE_VALUE
)

Bring the interrupt pin on the GPIO into Linux userspace .


def set_gpio_interrupt_edge(edge='falling'):
    """Set the interrupt edge on the userspace GPIO pin.

    :param edge: The interrupt edge ('none', 'falling', 'rising').
    :type edge: string
    """
    # we're only interested in the falling edge (1 -> 0)
    start_time = time.time()
    time_limit = start_time + FILE_IO_TIMEOUT
    while time.time() < time_limit:
        try:
            with open(GPIO_INTERRUPT_DEVICE_EDGE, 'w') as gpio_edge:
                gpio_edge.write(edge)
                return
        except IOError:
            pass

Set the interrupt edge on the userspace GPIO pin .


def wait_until_file_exists(filename):
    """Wait until a file exists.

    :param filename: The name of the file to wait for.
    :type filename: string
    """
    start_time = time.time()
    time_limit = start_time + FILE_IO_TIMEOUT
    while time.time() < time_limit:
        try:
            with open(filename):
                return
        except IOError:
            pass

    raise Timeout("Waiting too long for %s." % filename)

def
wait_until_file_exists
(
filename
)
:
start_time
=
time
.
time
(
)
time_limit
=
start_time
+
FILE_IO_TIMEOUT
while
time
.
time
(
)
<
time_limit
:
try
:
with
open
(
filename
)
:
return
except
IOError
:
pass
raise
Timeout
(
"Waiting too long for %s."
%
filename
)


def register(self, pin_num, direction, callback,
                 settle_time=DEFAULT_SETTLE_TIME):
        """Registers a pin number and direction to a callback function.

        :param pin_num: The pin pin number.
        :type pin_num: int
        :param direction: The event direction
            (use: IODIR_ON/IODIR_OFF/IODIR_BOTH)
        :type direction: int
        :param callback: The function to run when event is detected.
        :type callback: function
        :param settle_time: Time within which subsequent events are ignored.
        :type settle_time: int
        """
        self.pin_function_maps.append(
            PinFunctionMap(pin_num, direction, callback, settle_time))

def register ( self , pin_num , direction , callback , settle_time = DEFAULT_SETTLE_TIME ) : self . pin_function_maps . append ( PinFunctionMap ( pin_num , direction , callback , settle_time ) )

Registers a pin number and direction to a callback function .


def deregister(self, pin_num=None, direction=None):
        """De-registers callback functions

        :param pin_num: The pin number. If None then all functions are de-registered
        :type pin_num: int
        :param direction: The event direction. If None then all functions for the
                          given pin are de-registered
        :type direction:int
        """
        to_delete = []
        for i, function_map in enumerate(self.pin_function_maps):
            if ( pin_num == None
                 or ( function_map.pin_num == pin_num
                      and ( direction == None
                            or function_map.direction == direction ) ) ):
                to_delete.append(i)
        for i in reversed(to_delete):
            del self.pin_function_maps[i]

def deregister ( self , pin_num = None , direction = None ) : to_delete = [ ] for i , function_map in enumerate ( self . pin_function_maps ) : if ( pin_num == None or ( function_map . pin_num == pin_num and ( direction == None or function_map . direction == direction ) ) ) : to_delete . append ( i ) for i in reversed ( to_delete ) : del self . pin_function_maps [ i ]


def gpio_interrupts_enable(self):
        """Enables GPIO interrupts."""
        try:
            bring_gpio_interrupt_into_userspace()
            set_gpio_interrupt_edge()
        except Timeout as e:
            raise InterruptEnableException(
                "There was an error bringing gpio%d into userspace. %s" %
                (GPIO_INTERRUPT_PIN, e.message)
            )


def spisend(self, bytes_to_send):
        """Sends bytes via the SPI bus.

        :param bytes_to_send: The bytes to send on the SPI device.
        :type bytes_to_send: bytes
        :returns: bytes -- returned bytes from SPI device
        :raises: InitError
        """
        # make some buffer space to store reading/writing
        wbuffer = ctypes.create_string_buffer(bytes_to_send,
                                              len(bytes_to_send))
        rbuffer = ctypes.create_string_buffer(len(bytes_to_send))

        # create the spi transfer struct
        transfer = spi_ioc_transfer(
            tx_buf=ctypes.addressof(wbuffer),
            rx_buf=ctypes.addressof(rbuffer),
            len=ctypes.sizeof(wbuffer),
            speed_hz=ctypes.c_uint32(self.speed_hz)
        )

        if self.spi_callback is not None:
            self.spi_callback(bytes_to_send)
        # send the spi command
        ioctl(self.fd, SPI_IOC_MESSAGE(1), transfer)
        return ctypes.string_at(rbuffer, ctypes.sizeof(rbuffer))


def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
        """
        Re-implement almost the same code from crispy_forms but passing
        ``form`` instance to item ``render_link`` method.
        """
        links, content = '', ''

        # accordion group needs the parent div id to set `data-parent` (I don't
        # know why). This needs to be a unique id
        if not self.css_id:
            self.css_id = "-".join(["tabsholder",
                                    text_type(randint(1000, 9999))])

        for tab in self.fields:
            tab.active = False

        # Activate item
        self.open_target_group_for_form(form)

        for tab in self.fields:
            content += render_field(
                tab, form, form_style, context, template_pack=template_pack
            )
            links += tab.render_link(form, template_pack)

        context.update({
            'tabs': self,
            'links': links,
            'content': content
        })

        template = self.get_template_name(template_pack)
        return render_to_string(template, context.flatten())

Re - implement almost the same code from crispy_forms but passing form instance to item render_link method .


def has_errors(self, form):
        """
        Find tab fields listed as invalid
        """
        return any([fieldname_error for fieldname_error in form.errors.keys()
                    if fieldname_error in self])

def has_errors ( self , form ) : return any ( [ fieldname_error for fieldname_error in form . errors . keys ( ) if fieldname_error in self ] )


def render_link(self, form, template_pack=TEMPLATE_PACK, **kwargs):
        """
        Render the link for the tab-pane. It must be called after render so
        ``css_class`` is updated with ``active`` class name if needed.
        """
        link_template = self.link_template % template_pack
        return render_to_string(link_template,
                                {
                                    'link': self,
                                    'item_has_errors': self.has_errors(form)
                                })

def render_link ( self , form , template_pack = TEMPLATE_PACK , * * kwargs ) : link_template = self . link_template % template_pack return render_to_string ( link_template , { 'link' : self , 'item_has_errors' : self . has_errors ( form ) } )

Render the link for the tab - pane . It must be called after render so css_class is updated with active class name if needed .


def _extract_version(package_name):
    """
    Get package version from installed distribution or configuration file if not
    installed
    """
    try:
        return pkg_resources.get_distribution(package_name).version
    except pkg_resources.DistributionNotFound:
        _conf = read_configuration(os.path.join(PROJECT_DIR, "setup.cfg"))
    return _conf["metadata"]["version"]

def _extract_version ( package_name ) : try : return pkg_resources . get_distribution ( package_name ) . version except pkg_resources . DistributionNotFound : _conf = read_configuration ( os . path . join ( PROJECT_DIR , "setup.cfg" ) ) return _conf [ "metadata" ] [ "version" ]


def get_form_kwargs(self):
        """
        Pass template pack argument
        """
        kwargs = super(FormContainersMixin, self).get_form_kwargs()
        kwargs.update({
            'pack': "foundation-{}".format(self.kwargs.get('foundation_version'))
        })
        return kwargs

def get_form_kwargs ( self ) : kwargs = super ( FormContainersMixin , self ) . get_form_kwargs ( ) kwargs . update ( { 'pack' : "foundation-{}" . format ( self . kwargs . get ( 'foundation_version' ) ) } ) return kwargs


def _check_status(cls, response_json):
        """Check the status of the incoming response, raise exception if status is not 200.

        Args:
            response_json (dict): results of the response of the GET request.

        Returns:
           None

        """
        status = response_json['status']
        msg = response_json['msg']

        if status == 400:
            raise BadRequestException(msg)
        elif status == 403:
            raise PermissionDeniedException(msg)
        elif status == 404:
            raise FileNotFoundException(msg)
        elif status == 451:
            raise UnavailableForLegalReasonsException(msg)
        elif status == 509:
            raise BandwidthUsageExceeded(msg)
        elif status >= 500:
            raise ServerErrorException(msg)

def _check_status ( cls , response_json ) : status = response_json [ 'status' ] msg = response_json [ 'msg' ] if status == 400 : raise BadRequestException ( msg ) elif status == 403 : raise PermissionDeniedException ( msg ) elif status == 404 : raise FileNotFoundException ( msg ) elif status == 451 : raise UnavailableForLegalReasonsException ( msg ) elif status == 509 : raise BandwidthUsageExceeded ( msg ) elif status >= 500 : raise ServerErrorException ( msg )

Check the status of the incoming response raise exception if status is not 200 .


def _get(self, url, params=None):
        """Used by every other method, it makes a GET request with the given params.

        Args:
            url (str): relative path of a specific service (account_info, ...).
            params (:obj:`dict`, optional): contains parameters to be sent in the GET request.

        Returns:
            dict: results of the response of the GET request.

        """
        if not params:
            params = {}

        params.update({'login': self.login, 'key': self.key})

        response_json = requests.get(self.api_url + url, params).json()

        return self._process_response(response_json)

def _get ( self , url , params = None ) : if not params : params = { } params . update ( { 'login' : self . login , 'key' : self . key } ) response_json = requests . get ( self . api_url + url , params ) . json ( ) return self . _process_response ( response_json )

Used by every other method it makes a GET request with the given params .


def get_download_link(self, file_id, ticket, captcha_response=None):
        """Requests direct download link for requested file,
        this method makes use of the response of prepare_download, prepare_download must be called first.

        Args:
            file_id (str): id of the file to be downloaded.

            ticket (str): preparation ticket is found in prepare_download response,\
                          this is why we need to call prepare_download before get_download_link.

            captcha_response (:obj:`str`, optional): sometimes prepare_download will have captcha url to be solved, \
                                                     first, this is the solution of the captcha.

        Returns:
            dict: dictionary containing (file info, download url, ...). ::

                  {
                    "name": "The quick brown fox.txt",
                    "size": 12345,
                    "sha1": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
                    "content_type": "plain/text",
                    "upload_at": "2011-01-26 13:33:37",
                    "url": "https://abvzps.example.com/dl/l/4spxX_-cSO4/The+quick+brown+fox.txt",
                    "token": "4spxX_-cSO4"
                  }

        """
        params = {'ticket': ticket, 'file': file_id}

        if captcha_response:
            params['captcha_response'] = captcha_response

        return self._get('file/dl', params)

def get_download_link ( self , file_id , ticket , captcha_response = None ) : params = { 'ticket' : ticket , 'file' : file_id } if captcha_response : params [ 'captcha_response' ] = captcha_response return self . _get ( 'file/dl' , params )

Requests direct download link for requested file this method makes use of the response of prepare_download prepare_download must be called first .


def upload_link(self, folder_id=None, sha1=None, httponly=False):
        """Makes a request to prepare for file upload.

        Note:
            If folder_id is not provided, it will make and upload link to the ``Home`` folder.

        Args:
            folder_id (:obj:`str`, optional): folder-ID to upload to.
            sha1 (:obj:`str`, optional): expected sha1 If sha1 of uploaded file doesn't match this value, upload fails.
            httponly (:obj:`bool`, optional): If this is set to true, use only http upload links.

        Returns:
            dict: dictionary containing (url: will be used in actual upload, valid_until). ::

                {
                    "url": "https://1fiafqj.oloadcdn.net/uls/nZ8H3X9e0AotInbU",
                    "valid_until": "2017-08-19 19:06:46"
                }

        """

        kwargs = {'folder': folder_id, 'sha1': sha1, 'httponly': httponly}
        params = {key: value for key, value in kwargs.items() if value}
        return self._get('file/ul', params=params)

def upload_link ( self , folder_id = None , sha1 = None , httponly = False ) : kwargs = { 'folder' : folder_id , 'sha1' : sha1 , 'httponly' : httponly } params = { key : value for key , value in kwargs . items ( ) if value } return self . _get ( 'file/ul' , params = params )

Makes a request to prepare for file upload .


def upload_file(self, file_path, folder_id=None, sha1=None, httponly=False):
        """Calls upload_link request to get valid url, then it makes a post request with given file to be uploaded.
        No need to call upload_link explicitly since upload_file calls it.

        Note:
            If folder_id is not provided, the file will be uploaded to ``Home`` folder.

        Args:
            file_path (str): full path of the file to be uploaded.
            folder_id (:obj:`str`, optional): folder-ID to upload to.
            sha1 (:obj:`str`, optional): expected sha1 If sha1 of uploaded file doesn't match this value, upload fails.
            httponly (:obj:`bool`, optional): If this is set to true, use only http upload links.

        Returns:
            dict: dictionary containing uploaded file info. ::

                {
                    "content_type": "application/zip",
                    "id": "0yiQTPzi4Y4",
                    "name": 'favicons.zip',
                    "sha1": 'f2cb05663563ec1b7e75dbcd5b96d523cb78d80c',
                    "size": '24160',
                    "url": 'https://openload.co/f/0yiQTPzi4Y4/favicons.zip'
                 }

        """

        upload_url_response_json = self.upload_link(folder_id=folder_id, sha1=sha1, httponly=httponly)
        upload_url = upload_url_response_json['url']

        with open(file_path, 'rb') as f:
            response_json = requests.post(upload_url, files={'upload_file': f}).json()

        self._check_status(response_json)
        return response_json['result']

def upload_file ( self , file_path , folder_id = None , sha1 = None , httponly = False ) : upload_url_response_json = self . upload_link ( folder_id = folder_id , sha1 = sha1 , httponly = httponly ) upload_url = upload_url_response_json [ 'url' ] with open ( file_path , 'rb' ) as f : response_json = requests . post ( upload_url , files = { 'upload_file' : f } ) . json ( ) self . _check_status ( response_json ) return response_json [ 'result' ]

Calls upload_link request to get valid url then it makes a post request with given file to be uploaded . No need to call upload_link explicitly since upload_file calls it .


def remote_upload(self, remote_url, folder_id=None, headers=None):
        """Used to make a remote file upload to openload.co

        Note:
            If folder_id is not provided, the file will be uploaded to ``Home`` folder.

        Args:
            remote_url (str): direct link of file to be remotely downloaded.
            folder_id (:obj:`str`, optional): folder-ID to upload to.
            headers (:obj:`dict`, optional): additional HTTP headers (e.g. Cookies or HTTP Basic-Auth)

        Returns:
            dict: dictionary containing ("id": uploaded file id, "folderid"). ::

                {
                    "id": "12",
                    "folderid": "4248"
                }

        """

        kwargs = {'folder': folder_id, 'headers': headers}
        params = {'url': remote_url}
        params.update({key: value for key, value in kwargs.items() if value})

        return self._get('remotedl/add', params=params)

def remote_upload ( self , remote_url , folder_id = None , headers = None ) : kwargs = { 'folder' : folder_id , 'headers' : headers } params = { 'url' : remote_url } params . update ( { key : value for key , value in kwargs . items ( ) if value } ) return self . _get ( 'remotedl/add' , params = params )

Used to make a remote file upload to openload . co


def remote_upload_status(self, limit=None, remote_upload_id=None):
        """Checks a remote file upload to status.

        Args:
            limit (:obj:`int`, optional): Maximum number of results (Default: 5, Maximum: 100).
            remote_upload_id (:obj:`str`, optional): Remote Upload ID.

        Returns:
            dict: dictionary containing all remote uploads, each dictionary element is a dictionary. ::

                {
                    "24": {
                      "id": "24",
                      "remoteurl": "http://proof.ovh.net/files/100Mio.dat",
                      "status": "new",
                      "folderid": "4248",
                      "added": "2015-02-21 09:20:26",
                      "last_update": "2015-02-21 09:20:26",
                      "extid": False,
                      "url": False
                    },
                    "22": {
                      "id": "22",
                      "remoteurl": "http://proof.ovh.net/files/1Gio.dat",
                      "status": "downloading",
                      "bytes_loaded": "823997062",
                      "bytes_total": "1073741824",
                      "folderid": "4248",
                      "added": "2015-02-21 09:20:26",
                      "last_update": "2015-02-21 09:21:56",
                      "extid": False,
                      "url": False
                    },
                    ...
                }

        """

        kwargs = {'limit': limit, 'id': remote_upload_id}
        params = {key: value for key, value in kwargs.items() if value}

        return self._get('remotedl/status', params=params)

def remote_upload_status ( self , limit = None , remote_upload_id = None ) : kwargs = { 'limit' : limit , 'id' : remote_upload_id } params = { key : value for key , value in kwargs . items ( ) if value } return self . _get ( 'remotedl/status' , params = params )


def list_folder(self, folder_id=None):
        """Request a list of files and folders in specified folder.

        Note:
            if folder_id is not provided, ``Home`` folder will be listed

        Args:
            folder_id (:obj:`str`, optional): id of the folder to be listed.

        Returns:
            dict: dictionary containing only two keys ("folders", "files"), \
                  each key represents a list of dictionaries. ::

                      {
                        "folders": [
                          {
                            "id": "5144",
                            "name": ".videothumb"
                          },
                          {
                            "id": "5792",
                            "name": ".subtitles"
                          },
                          ...
                        ],
                        "files": [
                          {
                            "name": "big_buck_bunny.mp4.mp4",
                            "sha1": "c6531f5ce9669d6547023d92aea4805b7c45d133",
                            "folderid": "4258",
                            "upload_at": "1419791256",
                            "status": "active",
                            "size": "5114011",
                            "content_type": "video/mp4",
                            "download_count": "48",
                            "cstatus": "ok",
                            "link": "https://openload.co/f/UPPjeAk--30/big_buck_bunny.mp4.mp4",
                            "linkextid": "UPPjeAk--30"
                          },
                          ...
                        ]
                      }

        """
        params = {'folder': folder_id} if folder_id else {}

        return self._get('file/listfolder', params=params)

def list_folder ( self , folder_id = None ) : params = { 'folder' : folder_id } if folder_id else { } return self . _get ( 'file/listfolder' , params = params )

Request a list of files and folders in specified folder .


def running_conversions(self, folder_id=None):
        """Shows running file converts by folder

        Note:
            If folder_id is not provided, ``Home`` folder will be used.

        Args:
            folder_id (:obj:`str`, optional): id of the folder to list conversions of files exist in it.

        Returns:
            list: list of dictionaries, each dictionary represents a file conversion info. ::

                      [
                        {
                          "name": "Geysir.AVI",
                          "id": "3565411",
                          "status": "pending",
                          "last_update": "2015-08-23 19:41:40",
                          "progress": 0.32,
                          "retries": "0",
                          "link": "https://openload.co/f/f02JFG293J8/Geysir.AVI",
                          "linkextid": "f02JFG293J8"
                        },
                        ....
                      ]

        """
        params = {'folder': folder_id} if folder_id else {}
        return self._get('file/runningconverts', params=params)

def running_conversions ( self , folder_id = None ) : params = { 'folder' : folder_id } if folder_id else { } return self . _get ( 'file/runningconverts' , params = params )


def calc_humidity(temp, dewpoint):
    '''
    calculates the humidity via the formula from weatherwise.org
    return the relative humidity
    '''

    t = fahrenheit_to_celsius(temp)
    td = fahrenheit_to_celsius(dewpoint)

    num = 112 - (0.1 * t) + td
    denom = 112 + (0.9 * t)

    rh = math.pow((num / denom), 8)

    return rh

def calc_humidity ( temp , dewpoint ) : t = fahrenheit_to_celsius ( temp ) td = fahrenheit_to_celsius ( dewpoint ) num = 112 - ( 0.1 * t ) + td denom = 112 + ( 0.9 * t ) rh = math . pow ( ( num / denom ) , 8 ) return rh

calculates the humidity via the formula from weatherwise . org return the relative humidity


def calc_dewpoint(temp, hum):
    '''
    calculates the dewpoint via the formula from weatherwise.org
    return the dewpoint in degrees F.
    '''

    c = fahrenheit_to_celsius(temp)
    x = 1 - 0.01 * hum;

    dewpoint = (14.55 + 0.114 * c) * x;
    dewpoint = dewpoint + ((2.5 + 0.007 * c) * x) ** 3;
    dewpoint = dewpoint + (15.9 + 0.117 * c) * x ** 14;
    dewpoint = c - dewpoint;

    return celsius_to_fahrenheit(dewpoint)

def calc_dewpoint ( temp , hum ) : c = fahrenheit_to_celsius ( temp ) x = 1 - 0.01 * hum dewpoint = ( 14.55 + 0.114 * c ) * x dewpoint = dewpoint + ( ( 2.5 + 0.007 * c ) * x ) ** 3 dewpoint = dewpoint + ( 15.9 + 0.117 * c ) * x ** 14 dewpoint = c - dewpoint return celsius_to_fahrenheit ( dewpoint )

calculates the dewpoint via the formula from weatherwise . org return the dewpoint in degrees F .


def publish(self):
      '''
      Perform HTTP session to transmit defined weather values.
      '''
      return self._publish( self.args, self.server, self.URI)

def publish ( self ) : return self . _publish ( self . args , self . server , self . URI )

Perform HTTP session to transmit defined weather values .


def get(data):
        '''
        return CRC calc value from raw serial data
        '''
        crc = 0
        for byte in array('B', data):
            crc = (VProCRC.CRC_TABLE[(crc >> 8) ^ byte] ^ ((crc & 0xFF) << 8))
        return crc

def get ( data ) : crc = 0 for byte in array ( 'B' , data ) : crc = ( VProCRC . CRC_TABLE [ ( crc >> 8 ) ^ byte ] ^ ( ( crc & 0xFF ) << 8 ) ) return crc


def verify(data):
        '''
        perform CRC check on raw serial data, return true if valid.
        a valid CRC == 0.
        '''
        if len(data) == 0:
            return False
        crc = VProCRC.get(data)
        if crc:
            log.info("CRC Bad")
        else:
            log.debug("CRC OK")
        return not crc

def
verify
(
data
)
:
if
len
(
data
)
==
0
:
return
False
crc
=
VProCRC
.
get
(
data
)
if
crc
:
log
.
info
(
"CRC Bad"
)
else
:
log
.
debug
(
"CRC OK"
)
return
not
crc

perform CRC check on raw serial data return true if valid . a valid CRC == 0 .


def _unpack_storm_date(date):
        '''
        given a packed storm date field, unpack and return 'YYYY-MM-DD' string.
        '''
        year = (date & 0x7f) + 2000  # 7 bits
        day = (date >> 7) & 0x01f  # 5 bits
        month = (date >> 12) & 0x0f  # 4 bits
        return "%s-%s-%s" % (year, month, day)

def
_unpack_storm_date
(
date
)
:
year
=
(
date
&
0x7f
)
+
2000
# 7 bits
day
=
(
date
>>
7
)
&
0x01f
# 5 bits
month
=
(
date
>>
12
)
&
0x0f
# 4 bits
return
"%s-%s-%s"
%
(
year
,
month
,
day
)

given a packed storm date field unpack and return YYYY - MM - DD string .


def _use_rev_b_archive(self, records, offset):
        '''
        return True if weather station returns Rev.B archives
        '''
        # if pre-determined, return result
        if type(self._ARCHIVE_REV_B) is bool:
            return self._ARCHIVE_REV_B
        # assume, B and check 'RecType' field
        data = ArchiveBStruct.unpack_from(records, offset)
        if data['RecType'] == 0:
            log.info('detected archive rev. B')
            self._ARCHIVE_REV_B = True
        else:
            log.info('detected archive rev. A')
            self._ARCHIVE_REV_B = False

        return self._ARCHIVE_REV_B

def
_use_rev_b_archive
(
self
,
records
,
offset
)
:
# if pre-determined, return result
if
type
(
self
.
_ARCHIVE_REV_B
)
is
bool
:
return
self
.
_ARCHIVE_REV_B
# assume, B and check 'RecType' field
data
=
ArchiveBStruct
.
unpack_from
(
records
,
offset
)
if
data
[
'RecType'
]
==
0
:
log
.
info
(
'detected archive rev. B'
)
self
.
_ARCHIVE_REV_B
=
True
else
:
log
.
info
(
'detected archive rev. A'
)
self
.
_ARCHIVE_REV_B
=
False
return
self
.
_ARCHIVE_REV_B

return True if weather station returns Rev . B archives


def _wakeup(self):
        '''
        issue wakeup command to device to take out of standby mode.
        '''
        log.info("send: WAKEUP")
        for i in xrange(3):
            self.port.write('\n')  # wakeup device
            ack = self.port.read(len(self.WAKE_ACK))  # read wakeup string
            log_raw('read', ack)
            if ack == self.WAKE_ACK:
                return
        raise NoDeviceException('Can not access weather station')

def
_wakeup
(
self
)
:
log
.
info
(
"send: WAKEUP"
)
for
i
in
xrange
(
3
)
:
self
.
port
.
write
(
'\n'
)
# wakeup device
ack
=
self
.
port
.
read
(
len
(
self
.
WAKE_ACK
)
)
# read wakeup string
log_raw
(
'read'
,
ack
)
if
ack
==
self
.
WAKE_ACK
:
return
raise
NoDeviceException
(
'Can not access weather station'
)

issue wakeup command to device to take out of standby mode .


def _cmd(self, cmd, *args, **kw):
        '''
        write a single command, with variable number of arguments. after the
        command, the device must return ACK
        '''
        ok = kw.setdefault('ok', False)

        self._wakeup()
        if args:
            cmd = "%s %s" % (cmd, ' '.join(str(a) for a in args))
        for i in xrange(3):
            log.info("send: " + cmd)
            self.port.write(cmd + '\n')
            if ok:
                ack = self.port.read(len(self.OK))  # read OK
                log_raw('read', ack)
                if ack == self.OK:
                    return
            else:
                ack = self.port.read(len(self.ACK))  # read ACK
                log_raw('read', ack)
                if ack == self.ACK:
                    return
        raise NoDeviceException('Can not access weather station')

def
_cmd
(
self
,
cmd
,
*
args
,
*
*
kw
)
:
ok
=
kw
.
setdefault
(
'ok'
,
False
)
self
.
_wakeup
(
)
if
args
:
cmd
=
"%s %s"
%
(
cmd
,
' '
.
join
(
str
(
a
)
for
a
in
args
)
)
for
i
in
xrange
(
3
)
:
log
.
info
(
"send: "
+
cmd
)
self
.
port
.
write
(
cmd
+
'\n'
)
if
ok
:
ack
=
self
.
port
.
read
(
len
(
self
.
OK
)
)
# read OK
log_raw
(
'read'
,
ack
)
if
ack
==
self
.
OK
:
return
else
:
ack
=
self
.
port
.
read
(
len
(
self
.
ACK
)
)
# read ACK
log_raw
(
'read'
,
ack
)
if
ack
==
self
.
ACK
:
return
raise
NoDeviceException
(
'Can not access weather station'
)

write a single command with variable number of arguments . after the command the device must return ACK


def _dmpaft_cmd(self, time_fields):
        '''
        issue a command to read the archive records after a known time stamp.
        '''
        records = []
        # convert time stamp fields to buffer
        tbuf = struct.pack('2H', *time_fields)

        # 1. send 'DMPAFT' cmd
        self._cmd('DMPAFT')

        # 2. send time stamp + crc
        crc = VProCRC.get(tbuf)
        crc = struct.pack('>H', crc)  # crc in big-endian format
        log_raw('send', tbuf + crc)
        self.port.write(tbuf + crc)  # send time stamp + crc
        ack = self.port.read(len(self.ACK))  # read ACK
        log_raw('read', ack)
        if ack != self.ACK: return  # if bad ack, return

        # 3. read pre-amble data
        raw = self.port.read(DmpStruct.size)
        log_raw('read', raw)
        if not VProCRC.verify(raw):  # check CRC value
            log_raw('send ESC', self.ESC)
            self.port.write(self.ESC)  # if bad, escape and abort
            return
        log_raw('send ACK', self.ACK)
        self.port.write(self.ACK)  # send ACK

        # 4. loop through all page records
        dmp = DmpStruct.unpack(raw)
        log.info('reading %d pages, start offset %d' %
                 (dmp['Pages'], dmp['Offset']))
        for i in xrange(dmp['Pages']):
            # 5. read page data
            raw = self.port.read(DmpPageStruct.size)
            log_raw('read', raw)
            if not VProCRC.verify(raw):  # check CRC value
                log_raw('send ESC', self.ESC)
                self.port.write(self.ESC)  # if bad, escape and abort
                return
            log_raw('send ACK', self.ACK)
            self.port.write(self.ACK)  # send ACK

            # 6. loop through archive records
            page = DmpPageStruct.unpack(raw)
            offset = 0  # assume offset at 0
            if i == 0:
                offset = dmp['Offset'] * ArchiveAStruct.size
            while offset < ArchiveAStruct.size * 5:
                log.info('page %d, reading record at offset %d' %
                         (page['Index'], offset))
                if self._use_rev_b_archive(page['Records'], offset):
                    a = ArchiveBStruct.unpack_from(page['Records'], offset)
                else:
                    a = ArchiveAStruct.unpack_from(page['Records'], offset)
                # 7. verify that record has valid data, and store
                if a['DateStamp'] != 0xffff and a['TimeStamp'] != 0xffff:
                    records.append(a)
                offset += ArchiveAStruct.size
        log.info('read all pages')
        return records

issue a command to read the archive records after a known time stamp .


def _get_new_archive_fields(self):
        '''
        returns a dictionary of fields from the newest archive record in the
        device. return None when no records are new.
        '''
        for i in xrange(3):
            records = self._dmpaft_cmd(self._archive_time)
            if records is not None: break
            time.sleep(1)

        if records is None:
            raise NoDeviceException('Can not access weather station')

        # find the newest record
        new_rec = None
        for r in records:
            new_time = (r['DateStamp'], r['TimeStamp'])
            if self._archive_time < new_time:
                self._archive_time = new_time
                new_rec = r

        return new_rec

def
_get_new_archive_fields
(
self
)
:
for
i
in
xrange
(
3
)
:
records
=
self
.
_dmpaft_cmd
(
self
.
_archive_time
)
if
records
is
not
:
break
time
.
sleep
(
1
)
if
records
is
:
raise
NoDeviceException
(
'Can not access weather station'
)
# find the newest record
new_rec
=
for
r
in
records
:
new_time
=
(
r
[
'DateStamp'
]
,
r
[
'TimeStamp'
]
)
if
self
.
_archive_time
<
new_time
:
self
.
_archive_time
=
new_time
new_rec
=
r
return
new_rec

returns a dictionary of fields from the newest archive record in the device . return None when no records are new .


def parse(self):
        '''
        read and parse a set of data read from the console.  after the
        data is parsed it is available in the fields variable.
        '''
        fields = self._get_loop_fields()
        fields['Archive'] = self._get_new_archive_fields()

        self._calc_derived_fields(fields)

        # set the fields variable the the values in the dict
        self.fields = fields

read and parse a set of data read from the console . after the data is parsed it is available in the fields variable .


def weather_update(station, pub_sites, interval):
   '''
   main execution loop. query weather data and post to online service.
   '''
   station.parse()      # read weather data

   # santity check weather data
   if station.fields['TempOut'] > 200:
      raise NoSensorException(
            'Out of range temperature value: %.1f, check sensors' %
            (station.fields['TempOut'],))

   gust, gust_dir = WindGust.get( station, interval )

   # upload data in the following order:
   for ps in pub_sites:
      try: # try block necessary to attempt every publisher
         ps.set(
               pressure    = station.fields['Pressure'],
               dewpoint    = station.fields['DewPoint'],
               humidity    = station.fields['HumOut'],
               tempf       = station.fields['TempOut'],
               rainin      = station.fields['RainRate'],
               rainday     = station.fields['RainDay'],
               dateutc     = station.fields['DateStampUtc'],
               windspeed   = station.fields['WindSpeed10Min'],
               winddir     = station.fields['WindDir'],
               windgust    = gust,
               windgustdir = gust_dir, )

         ps.publish()
      except (Exception) as e:
         log.warn('publisher %s: %s'%(ps.__class__.__name__,e))

main execution loop . query weather data and post to online service .


def init_log( quiet, debug ):
   '''
   setup system logging to desired verbosity.
   '''
   from logging.handlers import SysLogHandler
   fmt = logging.Formatter( os.path.basename(sys.argv[0]) +
         ".%(name)s %(levelname)s - %(message)s")
   facility = SysLogHandler.LOG_DAEMON
   syslog = SysLogHandler(address='/dev/log',facility=facility)
   syslog.setFormatter( fmt )
   log.addHandler(syslog)
   if not quiet:
      console = logging.StreamHandler()
      console.setFormatter( fmt )
      log.addHandler(console)
      log.setLevel(logging.INFO)
      if debug:
         log.setLevel(logging.DEBUG)

def
init_log
(
quiet
,
debug
)
:
from
logging
.
handlers
import
SysLogHandler
fmt
=
logging
.
Formatter
(
os
.
path
.
basename
(
sys
.
argv
[
0
]
)
+
".%(name)s %(levelname)s - %(message)s"
)
facility
=
SysLogHandler
.
LOG_DAEMON
syslog
=
SysLogHandler
(
address
=
'/dev/log'
,
facility
=
facility
)
syslog
.
setFormatter
(
fmt
)
log
.
addHandler
(
syslog
)
if
not
quiet
:
console
=
logging
.
StreamHandler
(
)
console
.
setFormatter
(
fmt
)
log
.
addHandler
(
console
)
log
.
setLevel
(
logging
.
INFO
)
if
debug
:
log
.
setLevel
(
logging
.
DEBUG
)

setup system logging to desired verbosity .


def get_pub_services(opts):
   '''
   use values in opts data to generate instances of publication services.
   '''
   sites = []
   for p_key in vars(opts).keys():
      args = getattr(opts,p_key)
      if p_key in PUB_SERVICES and args:
         if isinstance(args,tuple):
            ps = PUB_SERVICES[p_key](*args)
         else:
            ps = PUB_SERVICES[p_key](args)
         sites.append( ps )
   return sites

def get_pub_services ( opts ) : sites = [ ] for p_key in vars ( opts ) . keys ( ) : args = getattr ( opts , p_key ) if p_key in PUB_SERVICES and args : if isinstance ( args , tuple ) : ps = PUB_SERVICES [ p_key ] ( * args ) else : ps = PUB_SERVICES [ p_key ] ( args ) sites . append ( ps ) return sites

use values in opts data to generate instances of publication services .


def get( self, station, interval ):
      '''
      return gust data, if above threshold value and current time is inside
      reporting window period
      '''
      rec = station.fields['Archive']
      # process new data
      if rec:
         threshold = station.fields['WindSpeed10Min'] + GUST_MPH_MIN
         if rec['WindHi'] >= threshold:
            self.value = (rec['WindHi'],rec['WindHiDir'])
            self.count = GUST_TTL * 60 / interval
         else:
            self.value = self.NO_VALUE

      # return gust value, if remaining time is left, and valid
      if self.count:
         self.count -= 1
      else:
         self.value = self.NO_VALUE

      log.debug('wind gust of {0} mph from {1}'.format(*self.value))
      return self.value

return gust data if above threshold value and current time is inside reporting window period


def set( self, pressure='NA', dewpoint='NA', humidity='NA', tempf='NA',
            rainin='NA', rainday='NA', dateutc='NA', windgust='NA',
            windgustdir='NA', windspeed='NA', winddir='NA',
            clouds='NA', weather='NA', *args, **kw):
        '''
        Useful for defining weather data published to the server. Parameters
        not set will be reset and not sent to server. Unknown keyword args will
        be silently ignored, so be careful. This is necessary for publishers
        that support more fields than others.
        '''
        # see: http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol
        # unused, but valid, parameters are:
        #   windspdmph_avg2m, winddir_avg2m, windgustmph_10m, windgusdir_10m
        #   soiltempf, soilmoisture, leafwetness, solarradiation, UV
        #   indoortempf, indoorhumidity
        self.args.update( {
                'baromin':pressure,
                'clouds':clouds,
                'dailyrainin':rainday,
                'dateutc':dateutc,
                'dewptf':dewpoint,
                'humidity':humidity,
                'rainin':rainin,
                'tempf':tempf,
                'weather':weather,
                'winddir':winddir,
                'windgustdir':windgustdir,
                'windgustmph':windgust,
                'windspeedmph':windspeed,
            } )
        log.debug( self.args )

Useful for defining weather data published to the server . Parameters not set will be reset and not sent to server . Unknown keyword args will be silently ignored so be careful . This is necessary for publishers that support more fields than others .


def set( self, **kw):
      '''
      Store keyword args to be written to output file.
      '''
      self.args = kw
      log.debug( self.args )

def set ( self , * * kw ) : self . args = kw log . debug ( self . args )

Store keyword args to be written to output file .


def publish(self):
      '''
      Write output file.
      '''
      with open( self.file_name, 'w') as fh:
         for k,v in self.args.iteritems():
            buf = StringIO.StringIO()
            buf.write(k)
            self._append_vals(buf,v)
            fh.write(buf.getvalue() + '\n')
            buf.close()

def publish ( self ) : with open ( self . file_name , 'w' ) as fh : for k , v in self . args . iteritems ( ) : buf = StringIO . StringIO ( ) buf . write ( k ) self . _append_vals ( buf , v ) fh . write ( buf . getvalue ( ) + '\n' ) buf . close ( )


def wants_request(f):
    """
    Helper decorator for transitioning to user-only requirements, this aids
    in situations where the request may be marked optional and causes an
    incorrect flow into user-only requirements.

    This decorator causes the requirement to look like a user-only requirement
    but passes the current request context internally to the requirement.

    This decorator is intended only to assist during a transitionary phase
    and will be removed in flask-allows 1.0

    See: :issue:`20,27`
    """

    @wraps(f)
    def wrapper(user):
        return f(user, request)

    return wrapper

def wants_request ( f ) : @ wraps ( f ) def wrapper ( user ) : return f ( user , request ) return wrapper

Helper decorator for transitioning to user - only requirements this aids in situations where the request may be marked optional and causes an incorrect flow into user - only requirements .


def init_app(self, app):
        """
        Initializes the Flask-Allows object against the provided application
        """
        if not hasattr(app, "extensions"):  # pragma: no cover
            app.extensions = {}
        app.extensions["allows"] = self

        @app.before_request
        def start_context(*a, **k):
            self.overrides.push(Override())
            self.additional.push(Additional())

        @app.after_request
        def cleanup(response):
            self.clear_all_overrides()
            self.clear_all_additional()
            return response

def
init_app
(
self
,
app
)
:
if
not
hasattr
(
app
,
"extensions"
)
:
# pragma: no cover
app
.
extensions
=
{
}
app
.
extensions
[
"allows"
]
=
self
@
app
.
before_request
def
start_context
(
*
a
,
*
*
k
)
:
self
.
overrides
.
push
(
Override
(
)
)
self
.
additional
.
push
(
Additional
(
)
)
@
app
.
after_request
def
cleanup
(
response
)
:
self
.
clear_all_overrides
(
)
self
.
clear_all_additional
(
)
return
response

Initializes the Flask - Allows object against the provided application


def fulfill(self, requirements, identity=None):
        """
        Checks that the provided or current identity meets each requirement
        passed to this method.

        This method takes into account both additional and overridden
        requirements, with overridden requirements taking precedence::

            allows.additional.push(Additional(Has('foo')))
            allows.overrides.push(Override(Has('foo')))

            allows.fulfill([], user_without_foo)  # return True

        :param requirements: The requirements to check the identity against.
        :param identity: Optional. Identity to use in place of the current
            identity.
        """
        identity = identity or self._identity_loader()

        if self.additional.current:
            all_requirements = chain(iter(self.additional.current), requirements)
        else:
            all_requirements = iter(requirements)

        if self.overrides.current is not None:
            all_requirements = (
                r for r in all_requirements if r not in self.overrides.current
            )

        return all(_call_requirement(r, identity, request) for r in all_requirements)

def fulfill ( self , requirements , identity = None ) : identity = identity or self . _identity_loader ( ) if self . additional . current : all_requirements = chain ( iter ( self . additional . current ) , requirements ) else : all_requirements = iter ( requirements ) if self . overrides . current is not None : all_requirements = ( r for r in all_requirements if r not in self . overrides . current ) return all ( _call_requirement ( r , identity , request ) for r in all_requirements )

Checks that the provided or current identity meets each requirement passed to this method .


def push(self, override, use_parent=False):
        """
        Binds an override to the current context, optionally use the
        current overrides in conjunction with this override

        If ``use_parent`` is true, a new override is created from the
        parent and child overrides rather than manipulating either
        directly.
        """
        current = self.current
        if use_parent and current:
            override = current + override

        _override_ctx_stack.push((self, override))

def push ( self , override , use_parent = False ) : current = self . current if use_parent and current : override = current + override _override_ctx_stack . push ( ( self , override ) )

Binds an override to the current context optionally use the current overrides in conjunction with this override


def pop(self):
        """
        Pops the latest override context.

        If the override context was pushed by a different override manager,
        a ``RuntimeError`` is raised.
        """
        rv = _override_ctx_stack.pop()
        if rv is None or rv[0] is not self:
            raise RuntimeError(
                "popped wrong override context ({} instead of {})".format(rv, self)
            )


def override(self, override, use_parent=False):
        """
        Allows temporarily pushing an override context, yields the new context
        into the following block.
        """
        self.push(override, use_parent)
        yield self.current
        self.pop()

def override ( self , override , use_parent = False ) : self . push ( override , use_parent ) yield self . current self . pop ( )

Allows temporarily pushing an override context yields the new context into the following block .


def push(self, additional, use_parent=False):
        """
        Binds an additional to the current context, optionally use the
        current additionals in conjunction with this additional

        If ``use_parent`` is true, a new additional is created from the
        parent and child additionals rather than manipulating either
        directly.
        """
        current = self.current
        if use_parent and current:
            additional = current + additional

        _additional_ctx_stack.push((self, additional))

def push ( self , additional , use_parent = False ) : current = self . current if use_parent and current : additional = current + additional _additional_ctx_stack . push ( ( self , additional ) )

Binds an additional to the current context optionally use the current additionals in conjunction with this additional


def pop(self):
        """
        Pops the latest additional context.

        If the additional context was pushed by a different additional manager,
        a ``RuntimeError`` is raised.
        """
        rv = _additional_ctx_stack.pop()
        if rv is None or rv[0] is not self:
            raise RuntimeError(
                "popped wrong additional context ({} instead of {})".format(rv, self)
            )


def additional(self, additional, use_parent=False):
        """
        Allows temporarily pushing an additional context, yields the new context
        into the following block.
        """
        self.push(additional, use_parent)
        yield self.current
        self.pop()

def additional ( self , additional , use_parent = False ) : self . push ( additional , use_parent ) yield self . current self . pop ( )

Allows temporarily pushing an additional context yields the new context into the following block .


def unduplicate_field_names(field_names):
    """Append a number to duplicate field names to make them unique. """
    res = []
    for k in field_names:
        if k in res:
            i = 1
            while k + '_' + str(i) in res:
                i += 1
            k += '_' + str(i)
        res.append(k)
    return res

def unduplicate_field_names ( field_names ) : res = [ ] for k in field_names : if k in res : i = 1 while k + '_' + str ( i ) in res : i += 1 k += '_' + str ( i ) res . append ( k ) return res

Append a number to duplicate field names to make them unique .


def interpret_stats(results):
    """Generates the string to be shown as updates after the execution of a
    Cypher query

    :param results: ``ResultSet`` with the raw results of the execution of
                    the Cypher query
    """
    stats = results.stats
    contains_updates = stats.pop("contains_updates", False) if stats else False
    if not contains_updates:
        result = '{} rows affected.'.format(len(results))
    else:
        result = ''
        for stat, value in stats.items():
            if value:
                result = "{}\n{} {}.".format(result, value,
                                             stat.replace("_", " "))
    return result.strip()

def
interpret_stats
(
results
)
:
stats
=
results
.
stats
contains_updates
=
stats
.
pop
(
"contains_updates"
,
False
)
if
stats
else
False
if
not
contains_updates
:
result
=
'{} rows affected.'
.
format
(
len
(
results
)
)
else
:
result
=
''
for
stat
,
value
in
stats
.
items
(
)
:
if
value
:
result
=
"{}\n{} {}."
.
format
(
result
,
value
,
stat
.
replace
(
"_"
,
" "
)
)
return
result
.
strip
(
)


def extract_params_from_query(query, user_ns):
    """Generates a dictionary with safe keys and values to pass onto Neo4j

    :param query: string with the Cypher query to execute
    :param user_ns: dictionary with the IPython user space
    """
    # TODO: Optmize this function
    params = {}
    for k, v in user_ns.items():
        try:
            json.dumps(v)
            params[k] = v
        except:
            pass
    return params

def
extract_params_from_query
(
query
,
user_ns
)
:
# TODO: Optmize this function
params
=
{
}
for
k
,
v
in
user_ns
.
items
(
)
:
try
:
json
.
dumps
(
v
)
params
[
k
]
=
v
except
:
pass
return
params


def run(query, params=None, config=None, conn=None, **kwargs):
    """Executes a query and depending on the options of the extensions will
    return raw data, a ``ResultSet``, a Pandas ``DataFrame`` or a
    NetworkX graph.

    :param query: string with the Cypher query
    :param params: dictionary with parameters for the query (default=``None``)
    :param config: Configurable or NamedTuple with extra IPython configuration
                   details. If ``None``, a new object will be created
                   (defaults=``None``)
    :param conn: connection dictionary or string for the Neo4j backend.
                 If ``None``, a new connection will be created
                 (default=``None``)
    :param **kwargs: Any of the cell configuration options.
    """
    if params is None:
        params = {}
    if conn is None:
        conn = Connection.get(DEFAULT_CONFIGURABLE["uri"])
    elif isinstance(conn, string_types):
        conn = Connection.get(conn)
    if config is None:
        default_config = DEFAULT_CONFIGURABLE.copy()
        kwargs.update(default_config)
        config = DefaultConfigurable(**kwargs)
    if query.strip():
        # TODO: Handle multiple queries
        params = extract_params_from_query(query, params)
        result = conn.session.query(query, params,
                                    data_contents=config.data_contents)
        if config.feedback:
            print(interpret_stats(result))
        resultset = ResultSet(result, query, config)
        if config.auto_pandas:
            return resultset.get_dataframe()
        elif config.auto_networkx:
            graph = resultset.get_graph()
            resultset.draw()
            return graph
        else:
            return resultset  # returning only last result, intentionally
    else:
        return 'Connected: %s' % conn.name

Executes a query and depending on the options of the extensions will return raw data a ResultSet a Pandas DataFrame or a NetworkX graph .


def get_dataframe(self):
        """Returns a Pandas DataFrame instance built from the result set."""
        if pd is None:
            raise ImportError("Try installing Pandas first.")
        frame = pd.DataFrame(self[:], columns=(self and self.keys) or [])
        return frame

def
get_dataframe
(
self
)
:
if
pd
is
:
raise
ImportError
(
"Try installing Pandas first."
)
frame
=
pd
.
DataFrame
(
self
[
:
]
,
columns
=
(
self
and
self
.
keys
)
or
[
]
)
return
frame

Returns a Pandas DataFrame instance built from the result set .


def get_graph(self, directed=True):
        """Returns a NetworkX multi-graph instance built from the result set

        :param directed: boolean, optional (default=`True`).
            Whether to create a direted or an undirected graph.
        """
        if nx is None:
            raise ImportError("Try installing NetworkX first.")
        if directed:
            graph = nx.MultiDiGraph()
        else:
            graph = nx.MultiGraph()
        for item in self._results.graph:
            for node in item['nodes']:
                properties = copy.deepcopy(node['properties'])
                properties['labels'] = node['labels']
                graph.add_node(node['id'], **properties)
            for rel in item['relationships']:
                properties = copy.deepcopy(rel['properties'])
                properties.update(
                    id=rel['id'],
                    type=rel['type']
                )
                graph.add_edge(rel['startNode'], rel['endNode'],
                               key=rel.get('type'), **properties)
        return graph

def
get_graph
(
self
,
directed
=
True
)
:
if
nx
is
:
raise
ImportError
(
"Try installing NetworkX first."
)
if
directed
:
graph
=
nx
.
MultiDiGraph
(
)
else
:
graph
=
nx
.
MultiGraph
(
)
for
item
in
self
.
_results
.
graph
:
for
node
in
item
[
'nodes'
]
:
properties
=
copy
.
deepcopy
(
node
[
'properties'
]
)
properties
[
'labels'
]
=
node
[
'labels'
]
graph
.
add_node
(
node
[
'id'
]
,
*
*
properties
)
for
rel
in
item
[
'relationships'
]
:
properties
=
copy
.
deepcopy
(
rel
[
'properties'
]
)
properties
.
update
(
id
=
rel
[
'id'
]
,
type
=
rel
[
'type'
]
)
graph
.
add_edge
(
rel
[
'startNode'
]
,
rel
[
'endNode'
]
,
key
=
rel
.
get
(
'type'
)
,
*
*
properties
)
return
graph

Returns a NetworkX multi - graph instance built from the result set


def pie(self, key_word_sep=" ", title=None, **kwargs):
        """Generates a pylab pie chart from the result set.

        ``matplotlib`` must be installed, and in an
        IPython Notebook, inlining must be on::

            %%matplotlib inline

        Values (pie slice sizes) are taken from the
        rightmost column (numerical values required).
        All other columns are used to label the pie slices.

        :param key_word_sep: string used to separate column values
                             from each other in pie labels
        :param title: plot title, defaults to name of value column
        :kwargs: any additional keyword arguments will be passsed
            through to ``matplotlib.pylab.pie``.
        """
        if not plt:
            raise ImportError("Try installing matplotlib first.")
        self.guess_pie_columns(xlabel_sep=key_word_sep)
        pie = plt.pie(self.ys[0], labels=self.xlabels, **kwargs)
        plt.title(title or self.ys[0].name)
        return pie

def
pie
(
self
,
key_word_sep
=
" "
,
title
=
,
*
*
kwargs
)
:
if
not
plt
:
raise
ImportError
(
"Try installing matplotlib first."
)
self
.
guess_pie_columns
(
xlabel_sep
=
key_word_sep
)
pie
=
plt
.
pie
(
self
.
ys
[
0
]
,
labels
=
self
.
xlabels
,
*
*
kwargs
)
plt
.
title
(
title
or
self
.
ys
[
0
]
.
name
)
return
pie

Generates a pylab pie chart from the result set .


def plot(self, title=None, **kwargs):
        """Generates a pylab plot from the result set.

        ``matplotlib`` must be installed, and in an
        IPython Notebook, inlining must be on::

            %%matplotlib inline

        The first and last columns are taken as the X and Y
        values.  Any columns between are ignored.

        :param title: plot title, defaults to names of Y value columns

        Any additional keyword arguments will be passsed
        through to ``matplotlib.pylab.plot``.
        """
        if not plt:
            raise ImportError("Try installing matplotlib first.")
        self.guess_plot_columns()
        self.x = self.x or range(len(self.ys[0]))
        coords = reduce(operator.add, [(self.x, y) for y in self.ys])
        plot = plt.plot(*coords, **kwargs)
        if hasattr(self.x, 'name'):
            plt.xlabel(self.x.name)
        ylabel = ", ".join(y.name for y in self.ys)
        plt.title(title or ylabel)
        plt.ylabel(ylabel)
        return plot

def
plot
(
self
,
title
=
,
*
*
kwargs
)
:
if
not
plt
:
raise
ImportError
(
"Try installing matplotlib first."
)
self
.
guess_plot_columns
(
)
self
.
x
=
self
.
x
or
range
(
len
(
self
.
ys
[
0
]
)
)
coords
=
reduce
(
operator
.
add
,
[
(
self
.
x
,
y
)
for
y
in
self
.
ys
]
)
plot
=
plt
.
plot
(
*
coords
,
*
*
kwargs
)
if
hasattr
(
self
.
x
,
'name'
)
:
plt
.
xlabel
(
self
.
x
.
name
)
ylabel
=
", "
.
join
(
y
.
name
for
y
in
self
.
ys
)
plt
.
title
(
title
or
ylabel
)
plt
.
ylabel
(
ylabel
)
return
plot

Generates a pylab plot from the result set .


def bar(self, key_word_sep=" ", title=None, **kwargs):
        """Generates a pylab bar plot from the result set.

        ``matplotlib`` must be installed, and in an
        IPython Notebook, inlining must be on::

            %%matplotlib inline

        The last quantitative column is taken as the Y values;
        all other columns are combined to label the X axis.

        :param title: plot title, defaults to names of Y value columns
        :param key_word_sep: string used to separate column values
                             from each other in labels

        Any additional keyword arguments will be passsed
        through to ``matplotlib.pylab.bar``.
        """
        if not plt:
            raise ImportError("Try installing matplotlib first.")
        self.guess_pie_columns(xlabel_sep=key_word_sep)
        plot = plt.bar(range(len(self.ys[0])), self.ys[0], **kwargs)
        if self.xlabels:
            plt.xticks(range(len(self.xlabels)), self.xlabels,
                       rotation=45)
        plt.xlabel(self.xlabel)
        plt.ylabel(self.ys[0].name)
        return plot

def
bar
(
self
,
key_word_sep
=
" "
,
title
=
,
*
*
kwargs
)
:
if
not
plt
:
raise
ImportError
(
"Try installing matplotlib first."
)
self
.
guess_pie_columns
(
xlabel_sep
=
key_word_sep
)
plot
=
plt
.
bar
(
range
(
len
(
self
.
ys
[
0
]
)
)
,
self
.
ys
[
0
]
,
*
*
kwargs
)
if
self
.
xlabels
:
plt
.
xticks
(
range
(
len
(
self
.
xlabels
)
)
,
self
.
xlabels
,
rotation
=
45
)
plt
.
xlabel
(
self
.
xlabel
)
plt
.
ylabel
(
self
.
ys
[
0
]
.
name
)
return
plot

Generates a pylab bar plot from the result set .


def csv(self, filename=None, **format_params):
        """Generates results in comma-separated form.  Write to ``filename``
        if given. Any other parameter will be passed on to ``csv.writer``.

        :param filename: if given, the CSV will be written to filename.

        Any additional keyword arguments will be passsed
        through to ``csv.writer``.
        """
        if not self.pretty:
            return None  # no results
        if filename:
            outfile = open(filename, 'w')
        else:
            outfile = StringIO()
        writer = UnicodeWriter(outfile, **format_params)
        writer.writerow(self.field_names)
        for row in self:
            writer.writerow(row)
        if filename:
            outfile.close()
            return CsvResultDescriptor(filename)
        else:
            return outfile.getvalue()

def
csv
(
self
,
filename
=
,
*
*
format_params
)
:
if
not
self
.
pretty
:
return
# no results
if
filename
:
outfile
=
open
(
filename
,
'w'
)
else
:
outfile
=
StringIO
(
)
writer
=
UnicodeWriter
(
outfile
,
*
*
format_params
)
writer
.
writerow
(
self
.
field_names
)
for
row
in
self
:
writer
.
writerow
(
row
)
if
filename
:
outfile
.
close
(
)
return
CsvResultDescriptor
(
filename
)
else
:
return
outfile
.
getvalue
(
)

Generates results in comma - separated form . Write to filename if given . Any other parameter will be passed on to csv . writer .


def permission_required(perm, login_url=None, raise_exception=False):
    """
    Re-implementation of the permission_required decorator, honors settings.

    If ``DASHBOARD_REQUIRE_LOGIN`` is False, this decorator will always return
    ``True``, otherwise it will check for the permission as usual.

    """
    def check_perms(user):
        if not getattr(settings, 'DASHBOARD_REQUIRE_LOGIN',
                       app_settings.REQUIRE_LOGIN):
            return True
        # First check if the user has the permission (even anon users)
        if user.has_perm(perm):
            return True
        # In case the 403 handler should be called raise the exception
        if raise_exception:  # pragma: no cover
            raise PermissionDenied
        # As the last resort, show the login form
        return False
    return user_passes_test(check_perms, login_url=login_url)

Re - implementation of the permission_required decorator honors settings .


def get_context_data(self, **kwargs):
        """
        Adds ``is_rendered`` to the context and the widget's context data.

        ``is_rendered`` signals that the AJAX view has been called and that
        we are displaying the full widget now. When ``is_rendered`` is not
        found in the widget template it means that we are seeing the first
        page load and all widgets still have to get their real data from
        this AJAX view.

        """
        ctx = super(RenderWidgetMixin, self).get_context_data(**kwargs)
        ctx.update({
            'is_rendered': True,
            'widget': self.widget,
        })
        ctx.update(self.widget.get_context_data())
        return ctx

def get_context_data ( self , * * kwargs ) : ctx = super ( RenderWidgetMixin , self ) . get_context_data ( * * kwargs ) ctx . update ( { 'is_rendered' : True , 'widget' : self . widget , } ) ctx . update ( self . widget . get_context_data ( ) ) return ctx

Adds is_rendered to the context and the widget s context data .


def get_widgets_sorted(self):
        """Returns the widgets sorted by position."""
        result = []
        for widget_name, widget in self.get_widgets().items():
            result.append((widget_name, widget, widget.position))
        result.sort(key=lambda x: x[2])
        return result

def get_widgets_sorted ( self ) : result = [ ] for widget_name , widget in self . get_widgets ( ) . items ( ) : result . append ( ( widget_name , widget , widget . position ) ) result . sort ( key = lambda x : x [ 2 ] ) return result

Returns the widgets sorted by position .