<commit_before>"""classes and functions related to a particle in a n dimensional harmonic potential"""

import numpy as np

from pele.potentials import BasePotential
from pele.systems import BaseSystem
from pele.optimize import Result
from scipy import linalg
from bh_sampling import vector_random_uniform_hypersphere

__all__ =["HarPotential","HarParticle","HarRunner"]

class HarPotential(BasePotential):
    """
    Defines an harmonic potential, returns energy depending on coordinates

    Parameters
    ----------
    centre: list of int
        centre of harmonic well
    kappa: nxn matrix of floats
        spring constants

    """
    def __init__(self, centre, kappa):
        self.centre = np.asfarray(centre)
        self.kappa = kappa #np.asfarray(kappa) #kappa must be a nxn (diagonal) tensor where n is the number of dimension

    def getEnergy(self, coords):
        coords = np.asfarray(coords)
        dist_vec = coords - self.centre
        F = np.dot(self.kappa, dist_vec)
        return 0.5 * np.dot(F,F)
        #return 0.5 * dist_vec.dot(self.kappa * dist_vec) STEFANO 29 JUNE
#        E_vec = 0.5 * self.kappa * dist_vec * dist_vec
#        E = 0.
#        for e in E_vec:
#            E += e
##        print "getEnergy ", E
#        return E

class HarParticle(BaseSystem):
    """ Defines a particle in an harmonic potential of n dimensions

    Notes
    -----
    with n degrees of freedom and spring constant k:

        Z = (2*pi*T/k)^(n/2)
        <E> = -n*T/2
        <E^2> = T^2*n*(n+2)/4
        Cv = n/2
    """

    def __init__(self, ndim, centre=None, kappa=None, Eground=0., Emax_init=10.):
        self.ndim = ndim
        #kappa is an n x n dimensional tensor  containing n spring constants
        if kappa is None:
            self.kappa = np.diag(np.ones(self.ndim)) #np.ones(self.ndim) STEFANO 29 JUNE, create diagonal matrix of ones
        else:
            self.kappa = kappa #np.asfarray(kappa)
        assert(np.sqrt(self.kappa.size) == ndim) #STEFANO 29 JUNE
         # use numpy vectors for coordinates, centre must be a numpy vector
        if centre is None:
            self.centre = np.zeros(self.ndim)
        else:
            self.centre = np.array(centre)
        self.Eground = Eground
        self.Emax_init = Emax_init
        self.kappa_sqrt = linalg.sqrtm(self.kappa) #np.sqrt(self.kappa)

        print "Emax_init", self.Emax_init

    def get_potential(self):
        return HarPotential(self.centre, self.kappa)

    def vector_random_uniform_hypersphere(self):
        """
        return a normalised vector sampled uniformly in a hypersphere of dimension ndim
        must then multiply each component by sqrt(norm_max)
        """
        return vector_random_uniform_hypersphere(self.ndim)

    def get_config_tests(self):
        """
        needed to return true at all tests in run_nestedsampling
        """
        return True

    def get_config_tests_in(self, coords, radius):
        coords_norm = np.linalg.norm(coords-self.centre)
#        print "coords_norm", coords_norm
        return coords is not None and radius > coords_norm

    def get_random_configuration_Emax(self, Emax):
        """make sure they're all inside the radius, get_config_test is not strictly necessary, consider removing it"""
        #radius is a scalar corresponding to the max distance from the centre
        radius = np.sqrt(2. * (float(Emax) - self.Eground))

        coords = self.vector_random_uniform_hypersphere() * radius
        coords = np.dot(coords,linalg.inv(self.kappa_sqrt)) #/= self.kappa_sqrt
        coords += self.centre
        assert(self.get_config_tests_in(coords, radius))
        return coords

    def get_random_configuration(self):
        """make sure they're all inside the radius, get_config_test is not strictly necessary, consider removing it"""
        #radius is a scalar corresponding to the max distance from the centre
        Emax = self.Emax_init
        return self.get_random_configuration_Emax(Emax)

class HarRunner(object):

    def __init__(self, system):
        self.system = system
        self.pot = system.get_potential()

    def __call__(self, x0, mciter, stepsize, Emax, energy, seed=None):
        return self.run(Emax)

    def run(self, Emax):
        self.Emax = Emax
        res = Result()
        res.mciter = 100
        res.nsteps = 100
        res.naccept = 70
        res.x = self.system.get_random_configuration_Emax(self.Emax)
        res.energy = self.pot.getEnergy(res.x)
        return res

def test1():
    import matplotlib.pyplot as plt
    v = np.random.uniform(-4,4,size=10000)
    energies = v**2 / 2.
    plt.hist(energies, bins=50)
    plt.show()

def test():
    import matplotlib.pyplot as plt
    n = 100
    hp = HarParticle(n)#, centre=[0.]*n, kappa=[1.]*n)
    pot = hp.get_potential()

    coords = np.array([hp.get_random_configuration_Emax(10.) for i in range(10000)])
    energies = [pot.getEnergy(x) for x in coords]
    print coords
    print "max energy", np.max(energies)
#    plt.plot(vals, 'o')
    plt.hist(coords[:,0], bins=50)
    plt.show()
    plt.hist(energies, bins=50)
    plt.show()

if __name__ == "__main__":
    test()
#    test1()<commit_msg>restored<commit_after>"""classes and functions related to a particle in a n dimensional harmonic potential"""

import numpy as np

from pele.potentials import BasePotential
from pele.systems import BaseSystem
from pele.optimize import Result
from scipy import linalg
from bh_sampling import vector_random_uniform_hypersphere

__all__ =["HarPotential","HarParticle","HarRunner"]

class HarPotential(BasePotential):
    """
    Defines an harmonic potential, returns energy depending on coordinates

    Parameters
    ----------
    centre: list of int
        centre of harmonic well
    kappa: nxn matrix of floats
        spring constants

    """
    def __init__(self, centre, kappa):
        self.centre = np.asfarray(centre)
        self.kappa = np.asfarray(kappa) #kappa must be a nxn (diagonal) tensor where n is the number of dimension

    def getEnergy(self, coords):
        coords = np.asfarray(coords)
        dist_vec = coords - self.centre
        F = np.dot(self.kappa, dist_vec)
        return 0.5 * np.dot(F,F)
        #return 0.5 * dist_vec.dot(self.kappa * dist_vec) STEFANO 29 JUNE
#        E_vec = 0.5 * self.kappa * dist_vec * dist_vec
#        E = 0.
#        for e in E_vec:
#            E += e
##        print "getEnergy ", E
#        return E

class HarParticle(BaseSystem):
    """ Defines a particle in an harmonic potential of n dimensions

    Notes
    -----
    with n degrees of freedom and spring constant k:

        Z = (2*pi*T/k)^(n/2)
        <E> = -n*T/2
        <E^2> = T^2*n*(n+2)/4
        Cv = n/2
    """

    def __init__(self, ndim, centre=None, kappa=None, Eground=0., Emax_init=10.):
        self.ndim = ndim
        #kappa is an n x n dimensional tensor  containing n spring constants
        if kappa is None:
            self.kappa = np.diag(np.ones(self.ndim)) #np.ones(self.ndim) STEFANO 29 JUNE, create diagonal matrix of ones
        else:
            self.kappa = np.asfarray(kappa)
        assert(np.sqrt(self.kappa.size) == ndim) #STEFANO 29 JUNE
         # use numpy vectors for coordinates, centre must be a numpy vector
        if centre is None:
            self.centre = np.zeros(self.ndim)
        else:
            self.centre = np.array(centre)
        self.Eground = Eground
        self.Emax_init = Emax_init
        self.kappa_sqrt = linalg.sqrtm(self.kappa) #np.sqrt(self.kappa)

        print "Emax_init", self.Emax_init

    def get_potential(self):
        return HarPotential(self.centre, self.kappa)

    def vector_random_uniform_hypersphere(self):
        """
        return a normalised vector sampled uniformly in a hypersphere of dimension ndim
        must then multiply each component by sqrt(norm_max)
        """
        return vector_random_uniform_hypersphere(self.ndim)

    def get_config_tests(self):
        """
        needed to return true at all tests in run_nestedsampling
        """
        return True

    def get_config_tests_in(self, coords, radius):
        coords_norm = np.linalg.norm(coords-self.centre)
#        print "coords_norm", coords_norm
        return coords is not None and radius > coords_norm

    def get_random_configuration_Emax(self, Emax):
        """make sure they're all inside the radius, get_config_test is not strictly necessary, consider removing it"""
        #radius is a scalar corresponding to the max distance from the centre
        radius = np.sqrt(2. * (float(Emax) - self.Eground))

        coords = self.vector_random_uniform_hypersphere() * radius
        coords = np.dot(coords,linalg.inv(self.kappa_sqrt)) #/= self.kappa_sqrt
        coords += self.centre
        assert(self.get_config_tests_in(coords, radius))
        return coords

    def get_random_configuration(self):
        """make sure they're all inside the radius, get_config_test is not strictly necessary, consider removing it"""
        #radius is a scalar corresponding to the max distance from the centre
        Emax = self.Emax_init
        return self.get_random_configuration_Emax(Emax)

class HarRunner(object):

    def __init__(self, system):
        self.system = system
        self.pot = system.get_potential()

    def __call__(self, x0, mciter, stepsize, Emax, energy, seed=None):
        return self.run(Emax)

    def run(self, Emax):
        self.Emax = Emax
        res = Result()
        res.mciter = 100
        res.nsteps = 100
        res.naccept = 70
        res.x = self.system.get_random_configuration_Emax(self.Emax)
        res.energy = self.pot.getEnergy(res.x)
        return res

def test1():
    import matplotlib.pyplot as plt
    v = np.random.uniform(-4,4,size=10000)
    energies = v**2 / 2.
    plt.hist(energies, bins=50)
    plt.show()

def test():
    import matplotlib.pyplot as plt
    n = 100
    hp = HarParticle(n)#, centre=[0.]*n, kappa=[1.]*n)
    pot = hp.get_potential()

    coords = np.array([hp.get_random_configuration_Emax(10.) for i in range(10000)])
    energies = [pot.getEnergy(x) for x in coords]
    print coords
    print "max energy", np.max(energies)
#    plt.plot(vals, 'o')
    plt.hist(coords[:,0], bins=50)
    plt.show()
    plt.hist(energies, bins=50)
    plt.show()

if __name__ == "__main__":
    test()
#    test1()<|endoftext|>


<commit_before># Pulls all the other functions together to make magic!
#
# Author: Christopher Arderne
# Date: 26 November 2016
# Python version: 3.5

import os
import pandas as pd
from pyonsset.constants import *
from pyonsset import prep, tables, elec

specs_path = 'db/specs.xlsx'
specs = pd.read_excel(specs_path, index_col=0)

countries = str(input('countries: ')).split()
countries = specs.index.tolist() if 'all' in countries else countries
wb_tier = int(input('wb tier: '))
diesel_high = True if 'y' in input('diesel high y/n: ') else False
diesel_tag = 'high' if diesel_high else 'low'
do_anything = True if 'y' in input('anything y/n: ') else False
do_prep = True if 'y' in input('prep y/n: ') else False
do_run = True if 'y' in input('run y/n: ') else False
combine = True if 'y' in input('combine y/n: ') else False

output_dir = 'db/run_12Nov'
try: os.makedirs(output_dir)
except FileExistsError: pass

if do_anything:
    for country in countries:
        # create country_specs here
        print(' --- {} --- {} --- {} --- '.format(country, wb_tier, diesel_tag))
        settlements_in_csv = 'db/base/{}.csv'.format(country)
        settlements_out_csv = os.path.join(output_dir, '{}_{}_{}.csv'.format(country, wb_tier, diesel_tag))
        summary_csv = os.path.join(output_dir, '{}_{}_{}_summary.csv'.format(country, wb_tier, diesel_tag))

        if os.path.isfile(settlements_in_csv):
            df = pd.read_csv(settlements_in_csv)
        else:
            df = pd.read_csv('db/settlements.csv')
            df = df.loc[df[SET_COUNTRY] == country]
            do_prep = True

        if do_prep:
            df = prep.condition(df)
            df = prep.grid_penalties(df)
            df = prep.wind(df)

            pop_actual = specs.loc[country, SPE_POP]
            pop_future = specs.loc[country, SPE_POP_FUTURE]
            urban = specs.loc[country, SPE_URBAN]
            urban_future = specs.loc[country, SPE_URBAN_FUTURE]
            urban_cutoff = specs.loc[country, SPE_URBAN_CUTOFF]

            elec = specs.loc[country, SPE_ELEC]
            pop_cutoff = specs.loc[country, SPE_POP_CUTOFF1]
            min_night_lights = specs.loc[country, SPE_MIN_NIGHT_LIGHTS]
            max_grid_dist = specs.loc[country, SPE_MAX_GRID_DIST]
            max_road_dist = specs.loc[country, SPE_MAX_ROAD_DIST]
            pop_tot = specs.loc[country, SPE_POP]
            pop_cutoff2 = specs.loc[country, SPE_POP_CUTOFF2]

            df, urban_cutoff, urban_modelled = prep.pop(df, pop_actual, pop_future, urban, urban_future, urban_cutoff)
            df, min_night_lights, max_grid_dist, max_road_dist, elec_modelled, pop_cutoff, pop_cutoff2 =\
                prep.elec_current(df, elec, pop_cutoff, min_night_lights, max_grid_dist, pop_tot, pop_cutoff2)

            specs.to_excel(specs_path)
            df.to_csv(settlements_in_csv, index=False)

        if do_run:
            diesel_price = specs[SPE_DIESEL_PRICE_HIGH][country] if diesel_high else specs[SPE_DIESEL_PRICE_LOW][country]
            grid_price = specs[SPE_GRID_PRICE][country]
            existing_grid_cost_ratio = specs[SPE_EXISTING_GRID_COST_RATIO][country]
            num_people_per_hh = float(specs[SPE_NUM_PEOPLE_PER_HH][country])
            transmission_losses = float(specs[SPE_GRID_LOSSES][country])
            grid_capacity_investment = float(specs[SPE_GRID_CAPACITY_INVESTMENT][country])
            max_dist = float(specs[SPE_MAX_GRID_EXTENSION_DIST][country])
            grid_base_to_peak = float(specs[SPE_BASE_TO_PEAK][country])
            wb_tiers_all = {1: 7.738, 2: 43.8, 3: 160.6, 4: 423.4, 5: 598.6}
            energy_per_hh = wb_tiers_all[wb_tier] * num_people_per_hh

            grid_lcoes = tables.get_grid_lcoe_table(energy_per_hh, max_dist, num_people_per_hh, transmission_losses, grid_base_to_peak,
                                                    grid_price, grid_capacity_investment)
            df = elec.techs_only(df, diesel_price, energy_per_hh, num_people_per_hh)
            df = elec.run_elec(df, grid_lcoes, grid_price, existing_grid_cost_ratio, max_dist)
            df = elec.results_columns(df, energy_per_hh, grid_base_to_peak, num_people_per_hh, diesel_price, grid_price,
                                      transmission_losses, grid_capacity_investment)
            elec.summaries(df, country).to_csv(summary_csv, header=True)

            df.to_csv(settlements_out_csv, index=False)

if combine:
    print('combining')
    df_base = pd.DataFrame()
    summaries = pd.DataFrame(columns=countries)

    for country in countries:
        print(country)
        df_add = pd.read_csv(os.path.join(output_dir, '{}_{}_{}.csv'.format(country, wb_tier, diesel_tag)))
        df_base = df_base.append(df_add, ignore_index=True)

        summaries[country] = pd.read_csv(os.path.join(output_dir, '{}_{}_{}_summary.csv'.format(country, wb_tier, diesel_tag)),
                                         squeeze=True, index_col=0)

    print('saving csv')
    df_base.to_csv(os.path.join(output_dir, '{}_{}.csv'.format(wb_tier, diesel_tag)), index=False)
    summaries.to_csv(os.path.join(output_dir, '{}_{}_summary.csv'.format(wb_tier, diesel_tag)))<commit_msg>Combination of constants, prep, tables and elec<commit_after># Pulls all the other functions together to make magic!
#
# Author: Christopher Arderne
# Date: 26 November 2016
# Python version: 3.5

import os
from pyonsset.onsset import *
os.chdir('..')
os.chdir('db')

specs_path = str(input('Enter the name of the specs file: '))
specs = pd.read_excel(specs_path, index_col=0)

countries = str(input('countries: ')).split()
countries = specs.index.tolist() if 'all' in countries else countries

choice = int(input('Enter 1 to split, 2 to prep, 3 to run a scenario: '))

if choice == 1:
    settlements_csv = str(input('Enter the name of the file containing all countries: '))
    base_dir = str(input('Enter the base file directory to save the split countries: '))

    try: os.makedirs(base_dir)
    except FileExistsError: pass

    df = pd.read_csv(settlements_csv)

    print(' --- Splitting --- ')
    for country in countries:
        print(country)
        df.loc[df[SET_COUNTRY] == country].to_csv(os.path.join(base_dir, '{}.csv'.format(country)), index=False)

elif choice == 2:
    base_dir = str(input('Enter the base file directory containing separated countries (files will be overwritten): '))

    for country in countries:
        settlements_in_csv = os.path.join(base_dir, '{}.csv'.format(country))

        try:
            df = pd.read_csv(settlements_in_csv)
        except FileNotFoundError:
            print('You need to first split into a base directory!')
            raise

        df = condition_df(df)
        df = grid_penalties(df)
        df = calc_wind_cfs(df)

        pop_actual = specs.loc[country, SPE_POP]
        pop_future = specs.loc[country, SPE_POP_FUTURE]
        urban = specs.loc[country, SPE_URBAN]
        urban_future = specs.loc[country, SPE_URBAN_FUTURE]
        urban_cutoff = specs.loc[country, SPE_URBAN_CUTOFF]

        elec_actual = specs.loc[country, SPE_ELEC]
        pop_cutoff = specs.loc[country, SPE_POP_CUTOFF1]
        min_night_lights = specs.loc[country, SPE_MIN_NIGHT_LIGHTS]
        max_grid_dist = specs.loc[country, SPE_MAX_GRID_DIST]
        max_road_dist = specs.loc[country, SPE_MAX_ROAD_DIST]
        pop_tot = specs.loc[country, SPE_POP]
        pop_cutoff2 = specs.loc[country, SPE_POP_CUTOFF2]

        df, urban_cutoff, urban_modelled = calibrate_pop_and_urban(df, pop_actual, pop_future, urban, urban_future, urban_cutoff)
        df, min_night_lights, max_grid_dist, max_road_dist, elec_modelled, pop_cutoff, pop_cutoff2 = \
            elec_current_and_future(df, elec_actual, pop_cutoff, min_night_lights, max_grid_dist, max_road_dist, pop_tot,
                                    pop_cutoff2)

        specs.loc[country, SPE_MIN_NIGHT_LIGHTS] = min_night_lights
        specs.loc[country, SPE_MAX_GRID_DIST] = max_grid_dist
        specs.loc[country, SPE_MAX_ROAD_DIST] = max_road_dist
        specs.loc[country, SPE_ELEC_MODELLED] = elec_modelled
        specs.loc[country, SPE_POP_CUTOFF1] = pop_cutoff
        specs.loc[country, SPE_POP_CUTOFF2] = pop_cutoff2

        specs.to_excel(specs_path)
        df.to_csv(settlements_in_csv, index=False)

elif choice == 3:
    base_dir = str(input('Enter the base file directory containing separated and prepped countries: '))
    output_dir = str(input('Enter the output directory (can contain multiple runs): '))

    wb_tiers_all = {1: 7.738, 2: 43.8, 3: 160.6, 4: 423.4, 5: 598.6}
    wb_tier = int(input('World Bank Tiers of Electricity Access\n'
                      '1: {} kWh/hh/year\n2: {} kWh/hh/year\n3: {} kWh/hh/year\n4: {} kWh/hh/year\n5: {} kWh/hh/year\n'
                      'Enter the tier number: '.format(wb_tiers_all[1], wb_tiers_all[2], wb_tiers_all[3],
                                                       wb_tiers_all[4], wb_tiers_all[5])))
    diesel_high = True if 'y' in input('Use high diesel value? <y/n> ') else False
    diesel_tag = 'high' if diesel_high else 'low'
    do_combine = True if 'y' in input('Combine countries into a single file? <y/n> ') else False

    try: os.makedirs(output_dir)
    except FileExistsError: pass

    for country in countries:
        # create country_specs here
        print(' --- {} --- {} --- {} --- '.format(country, wb_tier, diesel_tag))
        settlements_in_csv = os.path.join(base_dir, '{}.csv'.format(country))
        settlements_out_csv = os.path.join(output_dir, '{}_{}_{}.csv'.format(country, wb_tier, diesel_tag))
        summary_csv = os.path.join(output_dir, '{}_{}_{}_summary.csv'.format(country, wb_tier, diesel_tag))

        try:
            df = pd.read_csv(settlements_in_csv)
        except FileNotFoundError:
            print('You need to first split into a base directory and prep!')
            raise

        diesel_price = specs[SPE_DIESEL_PRICE_HIGH][country] if diesel_high else specs[SPE_DIESEL_PRICE_LOW][country]
        grid_price = specs[SPE_GRID_PRICE][country]
        existing_grid_cost_ratio = specs[SPE_EXISTING_GRID_COST_RATIO][country]
        num_people_per_hh = float(specs[SPE_NUM_PEOPLE_PER_HH][country])
        transmission_losses = float(specs[SPE_GRID_LOSSES][country])
        grid_capacity_investment = float(specs[SPE_GRID_CAPACITY_INVESTMENT][country])
        max_dist = float(specs[SPE_MAX_GRID_EXTENSION_DIST][country])
        grid_base_to_peak = float(specs[SPE_BASE_TO_PEAK][country])
        energy_per_hh = wb_tiers_all[wb_tier] * num_people_per_hh

        mg_hydro_vals = {'capacity_factor': 0.5, 'capital_cost': 5000, 'om_costs':0.02,
                         'base_to_peak_load_ratio': 1, 'system_life': 30}
        mg_pv_vals = {'capital_cost': 4300, 'om_costs': 0.015, 'base_to_peak_load_ratio': 0.9, 'system_life': 20}
        mg_wind_vals = {'capital_cost': 3000, 'om_costs': 0.02, 'base_to_peak_load_ratio': 0.75, 'system_life': 20}
        mg_diesel_vals = {'capacity_factor': 0.7, 'capital_cost': 721, 'om_costs': 0.1,
                          'base_to_peak_load_ratio': 0.5, 'system_life': 15, 'efficiency': 0.33}

        sa_pv_vals = {'capital_cost': 5500, 'om_costs': 0.012, 'base_to_peak_load_ratio': 0.9, 'system_life': 15}
        sa_diesel_vals = {'capacity_factor': 0.7, 'capital_cost': 938, 'om_costs': 0.1,
                          'base_to_peak_load_ratio': 0.5, 'system_life': 10, 'efficiency': 0.28}

        mg_vals = {'om_of_td_lines': 0.03, 'distribution_losses': 0.05, 'connection_cost_per_hh': 100}
        grid_vals = {'capacity_factor': 1, 'base_to_peak_load_ratio': grid_base_to_peak, 'om_of_td_lines': 0.03, 'connection_cost_per_hh': 125, 'system_life': 30}

        grid_lcoes = get_grid_lcoe_table(energy_per_hh, max_dist, num_people_per_hh, transmission_losses,
                                                grid_base_to_peak, grid_price, grid_capacity_investment, grid_vals)
        df = techs_only(df, diesel_price, energy_per_hh, num_people_per_hh, mg_vals, mg_hydro_vals, mg_pv_vals,
                             mg_wind_vals, mg_diesel_vals, sa_pv_vals, sa_diesel_vals)
        df = run_elec(df, grid_lcoes, grid_price, existing_grid_cost_ratio, max_dist)
        df = results_columns(df, energy_per_hh, grid_base_to_peak, num_people_per_hh, diesel_price, grid_price,
                                  transmission_losses, grid_capacity_investment, grid_vals, mg_vals, mg_hydro_vals,
                                  mg_pv_vals, mg_wind_vals, mg_diesel_vals, sa_pv_vals, sa_diesel_vals)
        calc_summaries(df, country).to_csv(summary_csv, header=True)

        df.to_csv(settlements_out_csv, index=False)

    if do_combine:
        print(' --- Combining --- ')
        df_base = pd.DataFrame()
        summaries = pd.DataFrame(columns=countries)

        for country in countries:
            print(country)
            df_add = pd.read_csv(os.path.join(output_dir, '{}_{}_{}.csv'.format(country, wb_tier, diesel_tag)))
            df_base = df_base.append(df_add, ignore_index=True)

            summaries[country] = pd.read_csv(os.path.join(output_dir, '{}_{}_{}_summary.csv'.format(country, wb_tier, diesel_tag)),
                                             squeeze=True, index_col=0)

        print('saving csv')
        df_base.to_csv(os.path.join(output_dir, '{}_{}.csv'.format(wb_tier, diesel_tag)), index=False)
        summaries.to_csv(os.path.join(output_dir, '{}_{}_summary.csv'.format(wb_tier, diesel_tag)))
<|endoftext|>


<commit_before>import json
import os
import time
import logging

import requests
import six

if six.PY2:
    from exceptions import Exception

API_KEY = os.environ.get('OPENFEC_API_KEY', None)
BASE_URL = 'https://api.open.fec.gov'
VERSION = '/v1'

class PyOpenFecException(Exception):
    """
    An exception from the PyOpenFec API.
    """
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)

    def __unicode__(self):
        return unicode(self.value)

    def __repr__(self):
        return repr(self.value)

class PyOpenFecApiClass(object):
    """
    Universal class for PyOpenFec API classes to inherit from.
    """
    ratelimit_remaining = 1000
    wait_time = 0.5

    def to_dict(self):
        return self.__dict__()

    def to_json(self):
        return json.dumps(self.to_dict())

    @classmethod
    def count(cls, **kwargs):
        resource = '{class_name}s'.format(class_name=cls.__name__.lower())
        initial_results = cls._make_request(resource, **kwargs)
        if initial_results.get('pagination', None):
            return initial_results['pagination']['count']

    @classmethod
    def fetch(cls, **kwargs):
        if 'resource' in kwargs:
            resource = kwargs.pop('resource')
        else:
            resource = '%ss' % cls.__name__.lower()
        initial_results = cls._make_request(resource, **kwargs)

        if initial_results.get('results', None):
            if len(initial_results['results']) > 0:
                for result in initial_results['results']:
                    yield cls(**result)

        if initial_results.get('pagination', None):
            if initial_results['pagination'].get('pages', None):
                if initial_results['pagination']['pages'] > 1:
                    current_page = 2

                    while current_page <= initial_results['pagination']['pages']:
                        params = dict(kwargs)
                        params['page'] = current_page
                        paged_results = cls._make_request(resource, **params)

                        if paged_results.get('results', None):
                            if len(paged_results['results']) > 0:
                                for result in paged_results['results']:
                                    yield cls(**result)

                        current_page += 1

    @classmethod
    def _throttled_request(cls, url, params):

        if cls.ratelimit_remaining == 0:
            while cls.ratelimit_remaining == 0:
                cls.wait_time = cls.wait_time * 1.5
                logging.warn(
                    'Rate limit was about to be exceeded. Waiting {}s.'.format(
                        cls.wait_time))
                time.sleep(cls.wait_time)
                response = requests.get(url, params=params)
                cls.ratelimit_remaining = int(response.headers['x-ratelimit-remaining'])
        else:
            response = requests.get(url, params=params)
            cls.ratelimit_remaining = int(response.headers['x-ratelimit-remaining'])

        return response

    @classmethod
    def _make_request(cls, resource, **kwargs):
        url = BASE_URL + VERSION + '/%s' % resource

        if not API_KEY:
            raise PyOpenFecException('Please export an env var OPENFEC_API_KEY with your API key.')

        params = dict(kwargs)
        params['api_key'] = API_KEY

        r = cls._throttled_request(url, params)
        logging.debug(r.url)

        if r.status_code != 200:
            raise PyOpenFecException('OpenFEC site returned a status code of %s for this request.' % r.status_code)

        return r.json()
<commit_msg>setting wait time back to 0.5 when successful call was made<commit_after>import json
import os
import time
import logging

import requests
import six

if six.PY2:
    from exceptions import Exception

API_KEY = os.environ.get('OPENFEC_API_KEY', None)
BASE_URL = 'https://api.open.fec.gov'
VERSION = '/v1'

class PyOpenFecException(Exception):
    """
    An exception from the PyOpenFec API.
    """
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)

    def __unicode__(self):
        return unicode(self.value)

    def __repr__(self):
        return repr(self.value)

class PyOpenFecApiClass(object):
    """
    Universal class for PyOpenFec API classes to inherit from.
    """
    ratelimit_remaining = 1000
    wait_time = 0.5

    def to_dict(self):
        return self.__dict__()

    def to_json(self):
        return json.dumps(self.to_dict())

    @classmethod
    def count(cls, **kwargs):
        resource = '{class_name}s'.format(class_name=cls.__name__.lower())
        initial_results = cls._make_request(resource, **kwargs)
        if initial_results.get('pagination', None):
            return initial_results['pagination']['count']

    @classmethod
    def fetch(cls, **kwargs):
        if 'resource' in kwargs:
            resource = kwargs.pop('resource')
        else:
            resource = '%ss' % cls.__name__.lower()
        initial_results = cls._make_request(resource, **kwargs)

        if initial_results.get('results', None):
            if len(initial_results['results']) > 0:
                for result in initial_results['results']:
                    yield cls(**result)

        if initial_results.get('pagination', None):
            if initial_results['pagination'].get('pages', None):
                if initial_results['pagination']['pages'] > 1:
                    current_page = 2

                    while current_page <= initial_results['pagination']['pages']:
                        params = dict(kwargs)
                        params['page'] = current_page
                        paged_results = cls._make_request(resource, **params)

                        if paged_results.get('results', None):
                            if len(paged_results['results']) > 0:
                                for result in paged_results['results']:
                                    yield cls(**result)

                        current_page += 1

    @classmethod
    def _throttled_request(cls, url, params):

        if cls.ratelimit_remaining == 0:
            while cls.ratelimit_remaining == 0:
                cls.wait_time = cls.wait_time * 1.5
                logging.warn(
                    'Rate limit was about to be exceeded. Waiting {}s.'.format(
                        cls.wait_time))
                time.sleep(cls.wait_time)
                response = requests.get(url, params=params)
                cls.ratelimit_remaining = int(response.headers['x-ratelimit-remaining'])
        else:
            response = requests.get(url, params=params)
            cls.ratelimit_remaining = int(response.headers['x-ratelimit-remaining'])

        cls.wait_time = 0.5

        return response

    @classmethod
    def _make_request(cls, resource, **kwargs):
        url = BASE_URL + VERSION + '/%s' % resource

        if not API_KEY:
            raise PyOpenFecException('Please export an env var OPENFEC_API_KEY with your API key.')

        params = dict(kwargs)
        params['api_key'] = API_KEY

        r = cls._throttled_request(url, params)
        logging.debug(r.url)

        if r.status_code != 200:
            raise PyOpenFecException('OpenFEC site returned a status code of %s for this request.' % r.status_code)

        return r.json()
<|endoftext|>


<commit_before>"""
PyPika is divided into a couple of modules, primarily the ``queries`` and ``terms`` modules.

pypika.queries
--------------

This is where the ``Query`` class can be found which is the core class in PyPika.  Also, other top level classes such
as ``Table`` can be found here.  ``Query`` is a container that holds all of the ``Term`` types together and also
serializes the builder to a string.

pypika.terms
------------

This module contains the classes which represent individual parts of queries that extend the ``Term`` base class.

pypika.functions
----------------

Wrappers for common SQL functions are stored in this package.

pypika.enums
------------

Enumerated values are kept in this package which are used as options for Queries and Terms.

pypika.utils
------------

This contains all of the utility classes such as exceptions and decorators.

"""
# noinspection PyUnresolvedReferences
from pypika.dialects import (
    ClickHouseQuery,
    Dialects,
    MSSQLQuery,
    MySQLQuery,
    OracleQuery,
    PostgreSQLQuery,
    RedshiftQuery,
    SQLLiteQuery,
    VerticaQuery,
)
# noinspection PyUnresolvedReferences
from pypika.enums import (
    DatePart,
    JoinType,
    Order,
)
# noinspection PyUnresolvedReferences
from pypika.queries import (
    AliasedQuery,
    Query,
    Schema,
    Table,
    make_tables as Tables,
)
# noinspection PyUnresolvedReferences
from pypika.terms import (
    Array,
    Bracket,
    Case,
    Criterion,
    EmptyCriterion,
    Field,
    Interval,
    Not,
    NullValue,
    Parameter,
    Rollup,
    Tuple,
)
# noinspection PyUnresolvedReferences
from pypika.utils import (
    CaseException,
    GroupingException,
    JoinException,
    QueryException,
    RollupException,
    UnionException,
)

__author__ = 'Timothy Heys'
__email__ = 'theys@kayak.com'
__version__ = '0.32.0'
<commit_msg>Bumped version to 0.33.0<commit_after>"""
PyPika is divided into a couple of modules, primarily the ``queries`` and ``terms`` modules.

pypika.queries
--------------

This is where the ``Query`` class can be found which is the core class in PyPika.  Also, other top level classes such
as ``Table`` can be found here.  ``Query`` is a container that holds all of the ``Term`` types together and also
serializes the builder to a string.

pypika.terms
------------

This module contains the classes which represent individual parts of queries that extend the ``Term`` base class.

pypika.functions
----------------

Wrappers for common SQL functions are stored in this package.

pypika.enums
------------

Enumerated values are kept in this package which are used as options for Queries and Terms.

pypika.utils
------------

This contains all of the utility classes such as exceptions and decorators.

"""
# noinspection PyUnresolvedReferences
from pypika.dialects import (
    ClickHouseQuery,
    Dialects,
    MSSQLQuery,
    MySQLQuery,
    OracleQuery,
    PostgreSQLQuery,
    RedshiftQuery,
    SQLLiteQuery,
    VerticaQuery,
)
# noinspection PyUnresolvedReferences
from pypika.enums import (
    DatePart,
    JoinType,
    Order,
)
# noinspection PyUnresolvedReferences
from pypika.queries import (
    AliasedQuery,
    Query,
    Schema,
    Table,
    make_tables as Tables,
)
# noinspection PyUnresolvedReferences
from pypika.terms import (
    Array,
    Bracket,
    Case,
    Criterion,
    EmptyCriterion,
    Field,
    Interval,
    Not,
    NullValue,
    Parameter,
    Rollup,
    Tuple,
)
# noinspection PyUnresolvedReferences
from pypika.utils import (
    CaseException,
    GroupingException,
    JoinException,
    QueryException,
    RollupException,
    UnionException,
)

__author__ = 'Timothy Heys'
__email__ = 'theys@kayak.com'
__version__ = '0.33.0'
<|endoftext|>


<commit_before># Use, distribution and modification of this file is bound by the terms of the MIT (expat) license.

"""
Various testing utilities for PyQt.
"""

__author__ = "Oliver Schoenborn"
__license__ = "MIT"
__version__ = '0.9.0'

from pathlib import Path
from math import sqrt

from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QImage, QPixmap, QColor

__all__ = ['check_widget_snapshot', 'ImgDiffer']

class ImgDiffer:

    def __init__(self, rms_tol_perc: float = None, num_tol_perc: float = None, max_pix_diff_tol: int = None):
        """
        :param rms_tol_perc: percentage difference allowed between widget's snapshot and the reference, i.e.
            a floating point value in range 0..100
        :param num_tol_perc: the maximum percentage of mismatched pixels allowed, relative to total number
            of pixels in the reference image; two pixels differ if any of their R, G, B and A values differ
        :param max_pix_diff_tol: maximum difference allowed in any pixel

        At least one of the three must be non-None. If all 3 are None, rms_tol_perc will be set to zero,
        implying strict equality only (no differences allowed).
        """
        if rms_tol_perc is None and num_tol_perc is None and max_pix_diff_tol is None:
            rms_tol_perc = 0.0
        self.rms_tol_perc = None if rms_tol_perc is None else float(rms_tol_perc)  # ensure FPV so report can format
        self.num_tol_perc = None if num_tol_perc is None else float(num_tol_perc)  # ensure FPV so report can format
        self.max_pix_diff_tol = max_pix_diff_tol

        self.diff_rms_perc = None
        self.num_diffs_perc = None
        self.max_pix_diff = None

    def get_diff(self, image: QImage, ref_image: QImage) -> QImage:
        diff_width = max(ref_image.width(), image.width())
        diff_height = max(ref_image.height(), image.height())
        diff_image = QImage(diff_width, diff_height, ref_image.format())

        COLOR_NO_PIXEL = QColor('white')
        diff_rms = 0
        num_diffs = 0
        self.max_pix_diff = 0
        total_num_pixels = 0
        for i in range(diff_width):
            for j in range(diff_height):
                pixel = image.pixelColor(i, j)
                ref_pixel = ref_image.pixelColor(i, j)
                if pixel.isValid() and ref_pixel.isValid():
                    total_num_pixels += 1
                    if pixel == ref_pixel:
                        diff_image.setPixelColor(i, j, self._get_pixel_diff_ref_color())
                    else:
                        num_diffs += 1
                        diff_rms_pix, diff_color = self._get_pixel_diff(pixel, ref_pixel)
                        diff_rms += diff_rms_pix
                        max_diff = max(diff_color)
                        if max_diff > self.max_pix_diff:
                            self.max_pix_diff = max_diff
                        diff_image.setPixelColor(i, j, QColor(*diff_color))

                elif pixel.isValid():
                    diff_image.setPixelColor(i, j, pixel)

                elif ref_pixel.isValid():
                    diff_image.setPixelColor(i, j, ref_pixel)

                else:
                    diff_image.setPixelColor(i, j, COLOR_NO_PIXEL)

        self.num_diffs_perc = (num_diffs / total_num_pixels) * 100
        if num_diffs == 0:
            self.diff_rms_perc = 0.0
            if ref_image.width() == image.width() and ref_image.height() == image.height():
                return None
            return diff_image

        else:
            diff_rms /= num_diffs
            self.diff_rms_perc = diff_rms * 100

            rms_ok = (self.rms_tol_perc is None or self.diff_rms_perc <= self.rms_tol_perc)
            num_diff_ok = (self.num_tol_perc is None or self.num_diffs_perc <= self.num_tol_perc)
            max_pix_diff_ok = (self.max_pix_diff_tol is None or self.max_pix_diff <= self.max_pix_diff_tol)
            diff_acceptable = (rms_ok and num_diff_ok and max_pix_diff_ok)
            return None if diff_acceptable else diff_image

    def report(self) -> str:
        msg = "RMS diff={} (rms_tol_perc={}), number of pixels changed={} (num_tol_perc={})"
        results = (self.diff_rms_perc, self.rms_tol_perc, self.num_diffs_perc, self.num_tol_perc)
        msg = msg.format(*['{}' if obj is None else '{:.2f}%' for obj in results])
        return msg.format(*results)

    def _get_pixel_diff(self, pix_color: QColor, ref_pix_color: QColor) -> (int, int, int, int):
        DIFF_MAX = 255
        pix_rgba = pix_color.getRgb()
        ref_pix_rgba = ref_pix_color.getRgb()

        diff = [pow((x - y) / DIFF_MAX, 2) for x, y in zip(pix_rgba, ref_pix_rgba)]
        diff_rms = sqrt(sum(diff) / len(pix_rgba))

        DIFF_REF_PIX = self._get_pixel_diff_ref()
        diff_color = [abs(x - y) for x, y in zip(pix_rgba, ref_pix_rgba)]

        return diff_rms, diff_color

    def _get_pixel_diff_ref_color(self) -> QColor:
        DIFF_REF_PIX = self._get_pixel_diff_ref()
        return QColor(DIFF_REF_PIX, DIFF_REF_PIX, DIFF_REF_PIX)

    def _get_pixel_diff_ref(self) -> int:
        DIFF_REF_PIX = 0  # value corresponds to "no difference"
        return DIFF_REF_PIX

# Discussion of check_widget_snapshot() is at
# http://www.codeproject.com/Tips/1134902/Testing-QWidget-Snapshot-Regression-in-PyQt.
def check_widget_snapshot(widget: QWidget, ref_path: str, fig_name: str, delete_old_results: bool = True,
                          img_differ: ImgDiffer = None, log=None, **img_diff_kwargs) -> bool:
    """
    Get the difference between a widget's appearance and a file stored on disk. If the file doesn't
    exist, the file is created.
    :param widget: the widget for which appearance must be verified
    :param ref_path: the path to folder containing reference image (can be a file name too, then the
        parent is used as folder -- useful for tests where __file__ can be passed)
    :param fig_name: the name of the reference image (will be saved in ref_path folder if it doesn't
        exist, or read if it does)
    :param delete_old_results: if True, any previous image results will be deleted (default); else keep them
        even if the check passes (could be misleading)
    :param img_differ: instance that adheres ot ImgDiffer protocol; default created if None

    :return: True if reference didn't exist (and was hence generated); True if widget matches reference;
        True if not matched but RMS diff is less than rms_tol_perc % and number of different pixels
        < max_num_diffs; False otherwise

    Example use:

        # file some_test.py in folder 'testing'
        app = QApplication([])
        widget = QLabel('test')
        assert check_widget_snapshot(widget, __file__, 'label', rms_tol_perc=0.5, num_tol_perc=4)

    The first time the test is run, it will save a snapshot of the widget to label.png in
    Path(__file__).parent and return True. The next time it is run, the widget snapshot will be compared
    to the image saved. If the image colors have changed by more than 0.5% when averaged over all pixels,
    or if more than 4% of pixels have changed in any way, check_widget_snapshot() will save a snapshot
    of the widget to label_actual.png and the difference image to label_diff.png and will return False,
    thus causing the test to fail. Otherwise (no differences, or differences within stated bounds),
    check_widget_snapshot() will just return True and the test will pass.
    """
    actual_pixmap = widget.grab()
    image = actual_pixmap.toImage()

    ref_path = Path(ref_path)
    if ref_path.is_file():
        ref_path = ref_path.parent
    assert ref_path.is_dir()
    ref_pixmap_path = (ref_path / fig_name).with_suffix('.png')
    actual_pix_path = ref_pixmap_path.with_name(fig_name + '_actual.png')
    diff_pix_path = ref_pixmap_path.with_name(fig_name + '_diff.png')
    assert actual_pix_path.parent == diff_pix_path.parent

    # delete any old data:
    if delete_old_results:
        if actual_pix_path.exists():
            actual_pix_path.unlink()
        if diff_pix_path.exists():
            diff_pix_path.unlink()

    # if ref image doesn't exist, generate it and return:
    if not ref_pixmap_path.exists():
        if log is not None:
            log.info('Generating ref snapshot %s in %s for widget %s',
                     ref_pixmap_path.name, ref_pixmap_path.parent, widget)
        actual_pixmap.save(str(ref_pixmap_path))
        return True

    # it exists, so compare to it, return if identical:
    ref_pixmap = QPixmap(str(ref_pixmap_path))
    ref_image = ref_pixmap.toImage()
    if ref_image == image:
        return True

    # not equal so get a diff image if diff is too large:
    if img_differ is None:
        img_differ = ImgDiffer(**img_diff_kwargs)
    else:
        if img_diff_kwargs:
            msg = "Unknown kwargs {} (because img_differ was given rather than None)"
            raise ValueError(msg.format(img_diff_kwargs))

    diff_image = img_differ.get_diff(image, ref_image)
    if log is not None:
        log.info("Widget %s vs ref %s in %s:",
                 widget.objectName() or repr(widget), ref_pixmap_path.name, ref_pixmap_path.parent)
        log.info(" " * 4 + img_differ.report())

    if diff_image is None:
        return True

    # save the actual and diff image
    if log is not None:
        log.warn("    Snapshot has changed beyond tolerances, saving actual and diff images to folder %s:",
                 actual_pix_path.parent)
        log.warn("    Saving actual image to %s", actual_pix_path.name)
        log.warn("    Saving diff image (White - |ref - widget|) to %s", diff_pix_path.name)

    actual_pixmap.save(str(actual_pix_path))
    diff_pixmap = QPixmap(diff_image)
    diff_pixmap.save(str(diff_pix_path))

    return False
<commit_msg>Docstrings, added try args<commit_after># Use, distribution and modification of this file is bound by the terms of the MIT (expat) license.

"""
Various testing utilities for PyQt.
"""

__author__ = "Oliver Schoenborn"
__license__ = "MIT"
__version__ = '0.9.0'

from pathlib import Path
from math import sqrt
from time import perf_counter

from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QImage, QPixmap, QColor

__all__ = ['check_widget_snapshot', 'ImgDiffer']

class ImgDiffer:
    """
    Default class used by check_widget_snapshot in order to measure whether two images are sufficiently
    similar to be considered as identical. The images are assumed to come from QWidget.grab(), so the
    differences measured are simple:

    - if two images are identical, get_img_diff(image1, image2) returns None
    - if the two images differ beyond specified tolerances, get_img_diff(image1, image2) returns a QImage
      instance that contains the differences between the two images. Each pixel that is the same in both
      images is black in the diff image, and each pixel that is different is the absolute difference between
      the two pixels. So a pixel that is black in image1 and white in image2, or vice versa, will show up
      as a white pixel in the diff image.

    This class computes the RMS difference between pixels averaged over the number of different pixels,
    the percentage of pixels that are different, and the largest difference between two channels.
    The following situations are covered:

    - images where most pixels differ by a small amount, and other pixels are identical: large percentage
      of pixels are different, but by a small RMS amount
    - images where very few pixels differ, but they differ by a lot: small percentage of pixels are different,
      but by a large RMS amount
    - a mixture of the two: RMS could be small if lots of pixels changed by a small amount and a few pixels
      changed by a large amount (for example, if a label changed text, like an "i" for an "l"), but max change
      will be large.

    If a diff is executed on the same platform all the time, the differ should probably have 0 tolerance
    (any change is likely a regression). But if a diff is executed on several machines, small differences
    could be visible due to anti-aliasing effects so they do not represent a true difference. In this case
    the 3 tolerances should be non-zero but small.
    """

    DIFF_REF_COLOR = 0
    PIXEL_COLOR_NO_DIFF = QColor(DIFF_REF_COLOR, DIFF_REF_COLOR, DIFF_REF_COLOR, DIFF_REF_COLOR)
    PIXEL_COLOR_NO_PIXEL = QColor('white')

    def __init__(self, rms_tol_perc: float = None, num_tol_perc: float = None, max_pix_diff_tol: int = None):
        """
        :param rms_tol_perc: percentage difference allowed between images, i.e. a floating point value in range
            0..100.
        :param num_tol_perc: the maximum percentage of mismatched pixels allowed, relative to total number
            of pixels in the reference image. I.e. a floating point value in range 0..100. Two pixels differ
            if any of their R, G, B and A values differ.
        :param max_pix_diff_tol: maximum difference allowed in any one pixel, i.e. an integer in the range
            0..255.

        At least one of the three must be non-None. If all 3 are None, rms_tol_perc will be set to zero,
        implying strict equality only (no differences allowed).

        A value of 0 for any of the parameters means the images must be strictly identical otherwise a diff
        will be produced.

        For any of the parameters, a value equal to the maximum is that same as setting the value to None:
        that parameter is not used to determine whether a difference image should be returned.
        """
        if rms_tol_perc is None and num_tol_perc is None and max_pix_diff_tol is None:
            rms_tol_perc = 0.0
        self.rms_tol_perc = None if rms_tol_perc is None else float(rms_tol_perc)  # ensure FPV so report can format
        self.num_tol_perc = None if num_tol_perc is None else float(num_tol_perc)  # ensure FPV so report can format
        self.max_pix_diff_tol = max_pix_diff_tol

        self.diff_rms_perc = None
        self.num_diffs_perc = None
        self.max_pix_diff = None

    def get_diff(self, image: QImage, ref_image: QImage) -> QImage:
        """
        Get a difference image that represents the differences between two images.
        Identical pixels produce a black pixel, otherwise the pixel is the absolute
        difference of the two colors. If the images are different sizes, a diff
        image will be returned regardless of the tolerances specified at construction
        time. In that case, the areas that do not overlap will have the pixels from
        the image that has pixels in those areas. In an area where neither image
        has pixels (because they have different widths AND heights), the color will
        be white.
        """
        diff_width = max(ref_image.width(), image.width())
        diff_height = max(ref_image.height(), image.height())
        diff_image = QImage(diff_width, diff_height, ref_image.format())

        diff_rms = 0
        num_diffs = 0
        self.max_pix_diff = 0
        total_num_pixels = 0

        for i in range(diff_width):
            for j in range(diff_height):
                pixel = image.pixelColor(i, j)
                ref_pixel = ref_image.pixelColor(i, j)

                if pixel.isValid() and ref_pixel.isValid():
                    total_num_pixels += 1
                    if pixel == ref_pixel:
                        diff_image.setPixelColor(i, j, self.PIXEL_COLOR_NO_DIFF)
                    else:
                        num_diffs += 1
                        diff_rms_pix, diff_color = self._get_pixel_diff(pixel, ref_pixel)
                        diff_rms += diff_rms_pix
                        max_diff = max(diff_color)
                        if max_diff > self.max_pix_diff:
                            self.max_pix_diff = max_diff
                        diff_image.setPixelColor(i, j, QColor(*diff_color))

                elif pixel.isValid():
                    diff_image.setPixelColor(i, j, pixel)

                elif ref_pixel.isValid():
                    diff_image.setPixelColor(i, j, ref_pixel)

                else:
                    diff_image.setPixelColor(i, j, self.PIXEL_COLOR_NO_PIXEL)

        self.num_diffs_perc = (num_diffs / total_num_pixels) * 100
        if num_diffs == 0:
            self.diff_rms_perc = 0.0
            if ref_image.width() == image.width() and ref_image.height() == image.height():
                return None
            return diff_image

        else:
            diff_rms /= num_diffs
            self.diff_rms_perc = diff_rms * 100

            rms_ok = (self.rms_tol_perc is None or self.diff_rms_perc <= self.rms_tol_perc)
            num_diff_ok = (self.num_tol_perc is None or self.num_diffs_perc <= self.num_tol_perc)
            max_pix_diff_ok = (self.max_pix_diff_tol is None or self.max_pix_diff <= self.max_pix_diff_tol)
            diff_acceptable = (rms_ok and num_diff_ok and max_pix_diff_ok)
            return None if diff_acceptable else diff_image

    def report(self) -> str:
        """
        Returns a text string that describes the actual difference metrics computed by the last
        get_diff(), as well as the tolerances that were used.
        """
        msg = "RMS diff={} (rms_tol_perc={}), number of pixels changed={} (num_tol_perc={})"
        results = (self.diff_rms_perc, self.rms_tol_perc, self.num_diffs_perc, self.num_tol_perc)
        msg = msg.format(*['{}' if obj is None else '{:.2f}%' for obj in results])
        return msg.format(*results)

    def _get_pixel_diff(self, pix_color: QColor, ref_pix_color: QColor) -> (float, (int, int, int, int)):
        """
        Get the difference between two pixels. The returns a pair: first item is the RMS of the
        differences across all 4 channels of the colors (RGBA); second item is the absolute
        difference between the pixel channels.
        """
        of the pixels
        DIFF_MAX = 255
        pix_rgba = pix_color.getRgb()
        ref_pix_rgba = ref_pix_color.getRgb()

        diff = [pow((x - y) / DIFF_MAX, 2) for x, y in zip(pix_rgba, ref_pix_rgba)]
        diff_rms = sqrt(sum(diff) / len(pix_rgba))

        diff_color = [abs(x - y) for x, y in zip(pix_rgba, ref_pix_rgba)]

        return diff_rms, diff_color

# Discussion of check_widget_snapshot() is at
# http://www.codeproject.com/Tips/1134902/Testing-QWidget-Snapshot-Regression-in-PyQt.
def check_widget_snapshot(widget: QWidget, ref_path: str, fig_name: str, delete_old_results: bool = True,
                          img_differ: ImgDiffer = None, log=None, try_sec: float=None, tries_freq: float=None,
                          **img_diff_kwargs) -> bool:
    """
    Get the difference between a widget's appearance and a file stored on disk. If the file doesn't
    exist, the file is created.

    :param widget: the widget for which appearance must be verified
    :param ref_path: the path to folder containing reference image (can be a file name too, then the
        parent is used as folder -- useful for tests where __file__ can be passed)
    :param fig_name: the name of the reference image (will be saved in ref_path folder if it doesn't
        exist, or read if it does)
    :param delete_old_results: if True, any previous image results will be deleted (default); else keep them
        even if the check passes (could be misleading)
    :param img_differ: instance that adheres ot ImgDiffer protocol; default created if None
    :param log: a logging.Logger instance
    :param try_sec: If this is None, only one comparison is made between the widgets. Otherwise, the
        comparison is made repeatedly every try_interval seconds, until try_sec have elapsed.
    :param try_interval: seconds to wait between tries. Must be < try_sec.

    :return: True if reference didn't exist (and was hence generated); True if widget matches reference;
        True if not matched but tolerances were sufficiently large to treat as identical; False otherwise.

    Example use:

        # file some_test.py in folder 'testing'
        app = QApplication([])
        widget = QLabel('test')
        assert check_widget_snapshot(widget, __file__, 'label', rms_tol_perc=0.5, num_tol_perc=4)

    The first time the test is run, it will save a snapshot of the widget to label.png in
    Path(__file__).parent and return True. The next time it is run, the widget snapshot will be compared
    to the image saved. If the image colors have changed by more than 0.5% when averaged over all pixels,
    or if more than 4% of pixels have changed in any way, check_widget_snapshot() will save a snapshot
    of the widget to label_actual.png and the difference image to label_diff.png and will return False,
    thus causing the test to fail. Otherwise (no differences, or differences within stated bounds),
    check_widget_snapshot() will just return True and the test will pass.
    """
    actual_pixmap = widget.grab()
    image = actual_pixmap.toImage()

    ref_path = Path(ref_path)
    if ref_path.is_file():
        ref_path = ref_path.parent
    assert ref_path.is_dir()
    ref_pixmap_path = (ref_path / fig_name).with_suffix('.png')
    actual_pix_path = ref_pixmap_path.with_name(fig_name + '_actual.png')
    diff_pix_path = ref_pixmap_path.with_name(fig_name + '_diff.png')
    assert actual_pix_path.parent == diff_pix_path.parent

    # delete any old data:
    if delete_old_results:
        if actual_pix_path.exists():
            actual_pix_path.unlink()
        if diff_pix_path.exists():
            diff_pix_path.unlink()

    # if ref image doesn't exist, generate it and return:
    if not ref_pixmap_path.exists():
        if log is not None:
            log.info('Generating ref snapshot %s in %s for widget %s',
                     ref_pixmap_path.name, ref_pixmap_path.parent, widget)
        actual_pixmap = widget.grab()
        actual_pixmap.save(str(ref_pixmap_path))
        return True

    # it exists, so compare to it, return if identical:
    ref_pixmap = QPixmap(str(ref_pixmap_path))
    ref_image = ref_pixmap.toImage()
    if ref_image == image:
        return True

    # not equal so get a diff image if diff is too large:
    if img_differ is None:
        img_differ = ImgDiffer(**img_diff_kwargs)
    else:
        if img_diff_kwargs:
            msg = "Unknown kwargs {} (because img_differ was given rather than None)"
            raise ValueError(msg.format(img_diff_kwargs))

    if try_sec is None:
        diff_image = img_differ.get_diff(image, ref_image)
    else:
        start_time = perf_counter()
        while perf_counter() - start_time < try_sec:
            diff_image = img_differ.get_diff(image, ref_image)

    if log is None:
        log.info("Widget %s vs ref %s in %s:",
                 widget.objectName() or repr(widget), ref_pixmap_path.name, ref_pixmap_path.parent)
        log.info(" " * 4 + img_differ.report())

    if diff_img is None:
        return True

    # save the actual and diff image
    if log is not None:
        log.warn("    Snapshot has changed beyond tolerances, saving actual and diff images to folder %s:",
                 actual_pix_path.parent)
        log.warn("    Saving actual image to %s", actual_pix_path.name)
        log.warn("    Saving diff image (White - |ref - widget|) to %s", diff_pix_path.name)

    actual_pixmap.save(str(actual_pix_path))
    diff_pixmap = QPixmap(diff_image)
    diff_pixmap.save(str(diff_pix_path))

    return False
<|endoftext|>


<commit_before>__version__ = '0.5.0-alpha3'
<commit_msg>version bump to 0.5a4<commit_after>__version__ = '0.5a4'
<|endoftext|>


<commit_before>"""
*****
Pydot
*****

Import and export NetworkX graphs in Graphviz dot format using pydot.

Either this module or nx_pygraphviz can be used to interface with graphviz.

See Also
--------
Pydot: http://code.google.com/p/pydot/
Graphviz:	   http://www.research.att.com/sw/tools/graphviz/
DOT Language:  http://www.graphviz.org/doc/info/lang.html
"""
#    Copyright (C) 2004-2011 by
#    Aric Hagberg <hagberg@lanl.gov>
#    Dan Schult <dschult@colgate.edu>
#    Pieter Swart <swart@lanl.gov>
#    All rights reserved.
#    BSD license.
from networkx.utils import open_file
import networkx as nx
__author__ = """Aric Hagberg (hagberg@lanl.gov)"""
__all__ = ['write_dot', 'read_dot', 'graphviz_layout', 'pydot_layout',
           'to_pydot', 'from_pydot']

@open_file(1,mode='w')
def write_dot(G,path):
    """Write NetworkX graph G to Graphviz dot format on path.

    Path can be a string or a file handle.
    """
    try:
        import pydot
    except ImportError:
        raise ImportError("write_dot() requires pydot",
                          "http://code.google.com/p/pydot/")
    P=to_pydot(G)
    path.write(P.to_string())
    return

@open_file(0,mode='r')
def read_dot(path):
    """Return a NetworkX MultiGraph or MultiDiGraph from a dot file on path.

    Parameters
    ----------
    path : filename or file handle

    Returns
    -------
    G : NetworkX multigraph
        A MultiGraph or MultiDiGraph.

    Notes
    -----
    Use G=nx.Graph(nx.read_dot(path)) to return a Graph instead of a MultiGraph.
    """
    try:
        import pydot
    except ImportError:
        raise ImportError("read_dot() requires pydot",
                          "http://code.google.com/p/pydot/")

    data=path.read()
    P=pydot.graph_from_dot_data(data)
    return from_pydot(P)

def from_pydot(P):
    """Return a NetworkX graph from a Pydot graph.

    Parameters
    ----------
    P : Pydot graph
      A graph created with Pydot

    Returns
    -------
    G : NetworkX multigraph
        A MultiGraph or MultiDiGraph.

    Examples
    --------
    >>> K5=nx.complete_graph(5)
    >>> A=nx.to_pydot(K5)
    >>> G=nx.from_pydot(A) # return MultiGraph
    >>> G=nx.Graph(nx.from_pydot(A)) # make a Graph instead of MultiGraph

    """
    if P.get_strict(None): # pydot bug: get_strict() shouldn't take argument
        multiedges=False
    else:
        multiedges=True

    if P.get_type()=='graph': # undirected
        if multiedges:
            create_using=nx.MultiGraph()
        else:
            create_using=nx.Graph()
    else:
        if multiedges:
            create_using=nx.MultiDiGraph()
        else:
            create_using=nx.DiGraph()

    # assign defaults
    N=nx.empty_graph(0,create_using)
    N.name=P.get_name()

    # add nodes, attributes to N.node_attr
    for p in P.get_node_list():
        n=p.get_name().strip('"')
        if n in ('node','graph','edge'):
            continue
        N.add_node(n,**p.get_attributes())

    # add edges
    for e in P.get_edge_list():
        u=e.get_source().strip('"')
        v=e.get_destination().strip('"')
        attr=e.get_attributes()
        N.add_edge(u,v,**attr)

    # add default attributes for graph, nodes, edges
    N.graph['graph']=P.get_attributes()
    try:
        N.graph['node']=P.get_node_defaults()[0]
    except:# IndexError,TypeError:
        N.graph['node']={}
    try:
        N.graph['edge']=P.get_edge_defaults()[0]
    except:# IndexError,TypeError:
        N.graph['edge']={}
    return N

def to_pydot(N, strict=True):
    """Return a pydot graph from a NetworkX graph N.

    Parameters
    ----------
    N : NetworkX graph
      A graph created with NetworkX

    Examples
    --------
    >>> K5=nx.complete_graph(5)
    >>> P=nx.to_pydot(K5)

    Notes
    -----

    """
    try:
        import pydot
    except ImportError:
        raise ImportError('to_pydot() requires pydot: '
                          'http://code.google.com/p/pydot/')

    # set Graphviz graph type
    if N.is_directed():
        graph_type='digraph'
    else:
        graph_type='graph'
    strict=N.number_of_selfloops()==0 and not N.is_multigraph()

    name = N.graph.get('name')
    graph_defaults=N.graph.get('graph',{})
    if name is None:
        P = pydot.Dot(graph_type=graph_type,strict=strict,**graph_defaults)
    else:
        P = pydot.Dot('"%s"'%name,graph_type=graph_type,strict=strict,
                      **graph_defaults)
    try:
        P.set_node_defaults(**N.graph['node'])
    except KeyError:
        pass
    try:
        P.set_edge_defaults(**N.graph['edge'])
    except KeyError:
        pass

    for n,nodedata in N.nodes_iter(data=True):
        str_nodedata=dict((k,str(v)) for k,v in nodedata.items())
        p=pydot.Node(str(n),**str_nodedata)
        P.add_node(p)

    if N.is_multigraph():
        for u,v,key,edgedata in N.edges_iter(data=True,keys=True):
            str_edgedata=dict((k,str(v)) for k,v in edgedata.items())
            edge=pydot.Edge(str(u),str(v),key=str(key),**str_edgedata)
            P.add_edge(edge)

    else:
        for u,v,edgedata in N.edges_iter(data=True):
            str_edgedata=dict((k,str(v)) for k,v in edgedata.items())
            edge=pydot.Edge(str(u),str(v),**str_edgedata)
            P.add_edge(edge)

    return P

def pydot_from_networkx(N):
    """Create a Pydot graph from a NetworkX graph."""
    from warnings import warn
    warn('pydot_from_networkx is replaced by to_pydot', DeprecationWarning)
    return to_pydot(N)

def networkx_from_pydot(D, create_using=None):
    """Create a NetworkX graph from a Pydot graph."""
    from warnings import warn
    warn('networkx_from_pydot is replaced by from_pydot',
         DeprecationWarning)
    return from_pydot(D)

def graphviz_layout(G,prog='neato',root=None, **kwds):
    """Create node positions using Pydot and Graphviz.

    Returns a dictionary of positions keyed by node.

    Examples
    --------
    >>> G=nx.complete_graph(4)
    >>> pos=nx.graphviz_layout(G)
    >>> pos=nx.graphviz_layout(G,prog='dot')

    Notes
    -----
    This is a wrapper for pydot_layout.

    """
    return pydot_layout(G=G,prog=prog,root=root,**kwds)

def pydot_layout(G,prog='neato',root=None, **kwds):
    """Create node positions using Pydot and Graphviz.

    Returns a dictionary of positions keyed by node.

    Examples
    --------
    >>> G=nx.complete_graph(4)
    >>> pos=nx.pydot_layout(G)
    >>> pos=nx.pydot_layout(G,prog='dot')

    """
    try:
        import pydot
    except ImportError:
        raise ImportError('pydot_layout() requires pydot ',
                          'http://code.google.com/p/pydot/')

    P=to_pydot(G)
    if root is not None :
        P.set("root",str(root))

    D=P.create_dot(prog=prog)

    if D=="":  # no data returned
        print("Graphviz layout with %s failed"%(prog))
        print()
        print("To debug what happened try:")
        print("P=pydot_from_networkx(G)")
        print("P.write_dot(\"file.dot\")")
        print("And then run %s on file.dot"%(prog))
        return

    Q=pydot.graph_from_dot_data(D)

    node_pos={}
    for n in G.nodes():
        node=Q.get_node(pydot.Node(str(n)).get_name())
        if isinstance(node,list):
            node=node[0]
        pos=node.get_pos()[1:-1] # strip leading and trailing double quotes
        if pos != None:
            xx,yy=pos.split(",")
            node_pos[n]=(float(xx),float(yy))
    return node_pos

# fixture for nose tests
def setup_module(module):
    from nose import SkipTest
    try:
        import pydot
    except:
        raise SkipTest("pydot not available")
<commit_msg>Allow unicode with pydot interface to graphviz. Addresses #535<commit_after>"""
*****
Pydot
*****

Import and export NetworkX graphs in Graphviz dot format using pydot.

Either this module or nx_pygraphviz can be used to interface with graphviz.

See Also
--------
Pydot: http://code.google.com/p/pydot/
Graphviz:	   http://www.research.att.com/sw/tools/graphviz/
DOT Language:  http://www.graphviz.org/doc/info/lang.html
"""
#    Copyright (C) 2004-2011 by
#    Aric Hagberg <hagberg@lanl.gov>
#    Dan Schult <dschult@colgate.edu>
#    Pieter Swart <swart@lanl.gov>
#    All rights reserved.
#    BSD license.
from networkx.utils import open_file, make_str
import networkx as nx
__author__ = """Aric Hagberg (hagberg@lanl.gov)"""
__all__ = ['write_dot', 'read_dot', 'graphviz_layout', 'pydot_layout',
           'to_pydot', 'from_pydot']

@open_file(1,mode='w')
def write_dot(G,path):
    """Write NetworkX graph G to Graphviz dot format on path.

    Path can be a string or a file handle.
    """
    try:
        import pydot
    except ImportError:
        raise ImportError("write_dot() requires pydot",
                          "http://code.google.com/p/pydot/")
    P=to_pydot(G)
    path.write(P.to_string())
    return

@open_file(0,mode='r')
def read_dot(path):
    """Return a NetworkX MultiGraph or MultiDiGraph from a dot file on path.

    Parameters
    ----------
    path : filename or file handle

    Returns
    -------
    G : NetworkX multigraph
        A MultiGraph or MultiDiGraph.

    Notes
    -----
    Use G=nx.Graph(nx.read_dot(path)) to return a Graph instead of a MultiGraph.
    """
    try:
        import pydot
    except ImportError:
        raise ImportError("read_dot() requires pydot",
                          "http://code.google.com/p/pydot/")

    data=path.read()
    P=pydot.graph_from_dot_data(data)
    return from_pydot(P)

def from_pydot(P):
    """Return a NetworkX graph from a Pydot graph.

    Parameters
    ----------
    P : Pydot graph
      A graph created with Pydot

    Returns
    -------
    G : NetworkX multigraph
        A MultiGraph or MultiDiGraph.

    Examples
    --------
    >>> K5=nx.complete_graph(5)
    >>> A=nx.to_pydot(K5)
    >>> G=nx.from_pydot(A) # return MultiGraph
    >>> G=nx.Graph(nx.from_pydot(A)) # make a Graph instead of MultiGraph

    """
    if P.get_strict(None): # pydot bug: get_strict() shouldn't take argument
        multiedges=False
    else:
        multiedges=True

    if P.get_type()=='graph': # undirected
        if multiedges:
            create_using=nx.MultiGraph()
        else:
            create_using=nx.Graph()
    else:
        if multiedges:
            create_using=nx.MultiDiGraph()
        else:
            create_using=nx.DiGraph()

    # assign defaults
    N=nx.empty_graph(0,create_using)
    N.name=P.get_name()

    # add nodes, attributes to N.node_attr
    for p in P.get_node_list():
        n=p.get_name().strip('"')
        if n in ('node','graph','edge'):
            continue
        N.add_node(n,**p.get_attributes())

    # add edges
    for e in P.get_edge_list():
        u=e.get_source().strip('"')
        v=e.get_destination().strip('"')
        attr=e.get_attributes()
        N.add_edge(u,v,**attr)

    # add default attributes for graph, nodes, edges
    N.graph['graph']=P.get_attributes()
    try:
        N.graph['node']=P.get_node_defaults()[0]
    except:# IndexError,TypeError:
        N.graph['node']={}
    try:
        N.graph['edge']=P.get_edge_defaults()[0]
    except:# IndexError,TypeError:
        N.graph['edge']={}
    return N

def to_pydot(N, strict=True):
    """Return a pydot graph from a NetworkX graph N.

    Parameters
    ----------
    N : NetworkX graph
      A graph created with NetworkX

    Examples
    --------
    >>> K5=nx.complete_graph(5)
    >>> P=nx.to_pydot(K5)

    Notes
    -----

    """
    try:
        import pydot
    except ImportError:
        raise ImportError('to_pydot() requires pydot: '
                          'http://code.google.com/p/pydot/')

    # set Graphviz graph type
    if N.is_directed():
        graph_type='digraph'
    else:
        graph_type='graph'
    strict=N.number_of_selfloops()==0 and not N.is_multigraph()

    name = N.graph.get('name')
    graph_defaults=N.graph.get('graph',{})
    if name is None:
        P = pydot.Dot(graph_type=graph_type,strict=strict,**graph_defaults)
    else:
        P = pydot.Dot('"%s"'%name,graph_type=graph_type,strict=strict,
                      **graph_defaults)
    try:
        P.set_node_defaults(**N.graph['node'])
    except KeyError:
        pass
    try:
        P.set_edge_defaults(**N.graph['edge'])
    except KeyError:
        pass

    for n,nodedata in N.nodes_iter(data=True):
        str_nodedata=dict((k,make_str(v)) for k,v in nodedata.items())
        p=pydot.Node(make_str(n),**str_nodedata)
        P.add_node(p)

    if N.is_multigraph():
        for u,v,key,edgedata in N.edges_iter(data=True,keys=True):
            str_edgedata=dict((k,make_str(v)) for k,v in edgedata.items())
            edge=pydot.Edge(make_str(u),make_str(v),key=make_str(key),**str_edgedata)
            P.add_edge(edge)

    else:
        for u,v,edgedata in N.edges_iter(data=True):
            str_edgedata=dict((k,make_str(v)) for k,v in edgedata.items())
            edge=pydot.Edge(make_str(u),make_str(v),**str_edgedata)
            P.add_edge(edge)

    return P

def pydot_from_networkx(N):
    """Create a Pydot graph from a NetworkX graph."""
    from warnings import warn
    warn('pydot_from_networkx is replaced by to_pydot', DeprecationWarning)
    return to_pydot(N)

def networkx_from_pydot(D, create_using=None):
    """Create a NetworkX graph from a Pydot graph."""
    from warnings import warn
    warn('networkx_from_pydot is replaced by from_pydot',
         DeprecationWarning)
    return from_pydot(D)

def graphviz_layout(G,prog='neato',root=None, **kwds):
    """Create node positions using Pydot and Graphviz.

    Returns a dictionary of positions keyed by node.

    Examples
    --------
    >>> G=nx.complete_graph(4)
    >>> pos=nx.graphviz_layout(G)
    >>> pos=nx.graphviz_layout(G,prog='dot')

    Notes
    -----
    This is a wrapper for pydot_layout.

    """
    return pydot_layout(G=G,prog=prog,root=root,**kwds)

def pydot_layout(G,prog='neato',root=None, **kwds):
    """Create node positions using Pydot and Graphviz.

    Returns a dictionary of positions keyed by node.

    Examples
    --------
    >>> G=nx.complete_graph(4)
    >>> pos=nx.pydot_layout(G)
    >>> pos=nx.pydot_layout(G,prog='dot')

    """
    try:
        import pydot
    except ImportError:
        raise ImportError('pydot_layout() requires pydot ',
                          'http://code.google.com/p/pydot/')

    P=to_pydot(G)
    if root is not None :
        P.set("root",make_str(root))

    D=P.create_dot(prog=prog)

    if D=="":  # no data returned
        print("Graphviz layout with %s failed"%(prog))
        print()
        print("To debug what happened try:")
        print("P=pydot_from_networkx(G)")
        print("P.write_dot(\"file.dot\")")
        print("And then run %s on file.dot"%(prog))
        return

    Q=pydot.graph_from_dot_data(D)

    node_pos={}
    for n in G.nodes():
        pydot_node = pydot.Node(make_str(n)).get_name().encode('utf-8')
        node=Q.get_node(pydot_node)

        if isinstance(node,list):
            node=node[0]
        pos=node.get_pos()[1:-1] # strip leading and trailing double quotes
        if pos != None:
            xx,yy=pos.split(",")
            node_pos[n]=(float(xx),float(yy))
    return node_pos

# fixture for nose tests
def setup_module(module):
    from nose import SkipTest
    try:
        import pydot
    except:
        raise SkipTest("pydot not available")
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from copy import deepcopy

from .request import SnowRequest
from .url_builder import URLBuilder

class Resource(object):
    """Creates a new :class:`Resource` object

    Resources provides a natural way of interfacing with ServiceNow APIs.

    :param base_path: Base path
    :param api_path: API path
    :param chunk_size: Response stream parser chunk size (in bytes)
    :param \*\*kwargs: Arguments to pass along to :class:`Request`
    """

    def __init__(self, base_url=None, base_path=None, api_path=None, parameters=None, **kwargs):

        self._base_url = base_url
        self._base_path = base_path
        self._api_path = api_path
        self._url_builder = URLBuilder(base_url, base_path, api_path)

        self.kwargs = kwargs

        self.parameters = deepcopy(parameters)

    def __repr__(self):
        return '<%s [%s]>' % (self.__class__.__name__, self.path)

    @property
    def path(self):
        return "%s" % self._base_path + self._api_path

    @property
    def _request(self):
        parameters = deepcopy(self.parameters)

        return SnowRequest(url_builder=self._url_builder, parameters=parameters, **self.kwargs)

    def get(self, query, limit=None, offset=None, fields=list()):
        """Queries the API resource

        :param query: Dictionary, string or :class:`QueryBuilder` object
        :param limit: (optional) Limits the number of records returned
        :param fields: (optional) List of fields to include in the response created_on in descending order.
        :param offset: (optional) Number of records to skip before returning records
        :return:
            - :class:`Response` object
        """

        return self._request.get(query, limit, offset, fields)

    def create(self, payload):
        """Creates a new record in the API resource

        :param payload: Dictionary containing key-value fields of the new record
        :return:
            - Dictionary of the inserted record
        """

        return self._request.create(payload)

    def update(self, query, payload):
        """Updates a record in the API resource

        :param query: Dictionary, string or :class:`QueryBuilder` object
        :param payload: Dictionary containing key-value fields of the record to be updated
        :return:
            - Dictionary of the updated record
        """

        return self._request.update(query, payload)

    def delete(self, query):
        """Deletes matching record

        :param query: Dictionary, string or :class:`QueryBuilder` object
        :return:
            - Dictionary containing information about deletion result
        """

        return self._request.delete(query)

    def custom(self, method, path_append=None, headers=None, **kwargs):
        """Creates a custom request

        :param method: HTTP method to use
        :param path_append: (optional) relative to :attr:`api_path`
        :param headers: (optional) Dictionary of headers to add or override
        :param kwargs: kwargs to pass along to :class:`requests.Request`
        :return:
            - :class:`Response` object
        """

        return self._request.custom(method, path_append=path_append, headers=headers, **kwargs)
<commit_msg>Renamed `custom` to `request`, added alias<commit_after># -*- coding: utf-8 -*-

from copy import deepcopy

from .request import SnowRequest
from .url_builder import URLBuilder

class Resource(object):
    """Creates a new :class:`Resource` object

    Resources provides a natural way of interfacing with ServiceNow APIs.

    :param base_path: Base path
    :param api_path: API path
    :param chunk_size: Response stream parser chunk size (in bytes)
    :param \*\*kwargs: Arguments to pass along to :class:`Request`
    """

    def __init__(self, base_url=None, base_path=None, api_path=None, parameters=None, **kwargs):

        self._base_url = base_url
        self._base_path = base_path
        self._api_path = api_path
        self._url_builder = URLBuilder(base_url, base_path, api_path)

        self.kwargs = kwargs

        # @TODO - Remove this alias in a future release
        self.custom = self.request

        self.parameters = deepcopy(parameters)

    def __repr__(self):
        return '<%s [%s]>' % (self.__class__.__name__, self.path)

    @property
    def path(self):
        return "%s" % self._base_path + self._api_path

    @property
    def _request(self):
        parameters = deepcopy(self.parameters)

        return SnowRequest(url_builder=self._url_builder, parameters=parameters, **self.kwargs)

    def get(self, query, limit=None, offset=None, fields=list()):
        """Queries the API resource

        :param query: Dictionary, string or :class:`QueryBuilder` object
        :param limit: (optional) Limits the number of records returned
        :param fields: (optional) List of fields to include in the response created_on in descending order.
        :param offset: (optional) Number of records to skip before returning records
        :return:
            - :class:`Response` object
        """

        return self._request.get(query, limit, offset, fields)

    def create(self, payload):
        """Creates a new record in the API resource

        :param payload: Dictionary containing key-value fields of the new record
        :return:
            - Dictionary of the inserted record
        """

        return self._request.create(payload)

    def update(self, query, payload):
        """Updates a record in the API resource

        :param query: Dictionary, string or :class:`QueryBuilder` object
        :param payload: Dictionary containing key-value fields of the record to be updated
        :return:
            - Dictionary of the updated record
        """

        return self._request.update(query, payload)

    def delete(self, query):
        """Deletes matching record

        :param query: Dictionary, string or :class:`QueryBuilder` object
        :return:
            - Dictionary containing information about deletion result
        """

        return self._request.delete(query)

    def request(self, method, path_append=None, headers=None, **kwargs):
        """Create a custom request

        :param method: HTTP method to use
        :param path_append: (optional) relative to :attr:`api_path`
        :param headers: (optional) Dictionary of headers to add or override
        :param kwargs: kwargs to pass along to :class:`requests.Request`
        :return:
            - :class:`Response` object
        """

        return self._request.custom(method, path_append=path_append, headers=headers, **kwargs)
<|endoftext|>