<commit_before>import os
import time

from termcolor import colored

from tota.world import World
from tota.things import Ancient, Hero, Creep
from tota.utils import closes_empty_position
from tota import settings

def get_hero_function(name):
    module = __import__('tota.heroes.' + name, fromlist=['create', ])
    create_function = getattr(module, 'create')

    return create_function()

class Game:
    """An instance of game controls the flow of the game.

       This includes player and creeps spawning, game main loop, deciding when
       to stop, importing map data, drawing each update, etc.
    """
    def __init__(self, radiant_heroes, dire_heroes, map_file_path, world_size,
                 debug=False, use_basic_icons=False):
        self.radiant_heroes = radiant_heroes
        self.dire_heroes = dire_heroes
        self.map_file_path = map_file_path
        self.debug = debug
        self.use_basic_icons = use_basic_icons

        self.heroes = []
        self.ancients = {}

        self.world = World(world_size, debug=debug)

        self.initialize_world_map()
        self.cache_ancients()
        self.initialize_heroes()

    def initialize_world_map(self):
        with open(self.map_file_path, encoding='utf-8') as map_file:
            map_text = map_file.read()
            self.world.import_map(map_text)

    def cache_ancients(self):
        def get_ancient(team):
            ancients = [thing for thing in self.world.things.values()
                        if isinstance(thing, Ancient) and thing.team == team]
            if not ancients:
                message = "Can't find the ancient for the {} team".format(team)
                raise Exception(message)
            elif len(ancients) > 1:
                message = "Team {} has 2 ancients".format(team)
                raise Exception(message)
            else:
                return ancients[0]

        for team in (settings.TEAM_DIRE, settings.TEAM_RADIANT):
            self.ancients[team] = get_ancient(team)

    def initialize_heroes(self):
        teams = {
            settings.TEAM_DIRE: self.dire_heroes,
            settings.TEAM_RADIANT: self.radiant_heroes,
        }
        for team, heroes in teams.items():
            for hero_name in heroes:
                hero = Hero(name=hero_name,
                            team=team,
                            act_function=get_hero_function(hero_name))
                self.heroes.append(hero)
                self.spawn_near_ancient(hero)

    def spawn_near_ancient(self, thing):
        """Spawn players or creeps near their ancient."""
        # start searching from the ancient position, outwards, until an empty
        # space is found, using breadth first graph search
        ancient = self.ancients[thing.team]
        spawn_at = closes_empty_position(ancient, self.world)
        if spawn_at:
            self.world.spawn(thing, spawn_at)
        else:
            message = "Can't spawn {} near its ancient".format(thing.name)
            raise Exception(message)

    def position_draw(self, position):
        """Get the string to draw for a given position of the world."""
        # decorations first, then things over them
        thing = self.world.things.get(position)

        if thing is not None:
            if self.use_basic_icons:
                icon = thing.ICON_BASIC
            else:
                icon = thing.ICON
            return colored(icon, settings.TEAM_COLORS[thing.team])
        else:
            return ' '

    def play(self, frames_per_second=2.0):
        """Game main loop, ending in a game result with description."""
        while True:
            # spawn creep wave
            if self.world.t % settings.CREEP_WAVE_COOLDOWN == 0:
                for team in (settings.TEAM_RADIANT, settings.TEAM_DIRE):
                    for i in range(settings.CREEP_WAVE_SIZE):
                        creep = Creep(team)
                        self.spawn_near_ancient(creep)

            self.world.step()

            # maintain the flow of zombies if necessary
            self.draw()

            if self.debug:
                input()
            else:
                time.sleep(1.0 / frames_per_second)

            if self.game_ended():
                description = self.game_result()
                print('')
                print(description)

    def draw(self):
        """Draw the world."""
        screen = ''

        # print the world
        screen += '\n'.join(u''.join(self.position_draw((x, y))
                                     for x in range(self.world.size[0]))
                            for y in range(self.world.size[1]))

        # game stats
        screen += '\nticks:{}'.format(self.world.t)

        # print hero stats
        for hero in sorted(self.heroes, key=lambda x: x.name):
            if hero.life > 0:
                # a small "health bar" with unicode chars, from 0 to 10 chars
                life_chars_count = int((10.0 / hero.max_life) * hero.life)
                life_chars = life_chars_count * '\u2588'
                no_life_chars = (10 - life_chars_count) * '\u2591'
                life_bar = '\u2665 {}{}'.format(life_chars, no_life_chars)
            else:
                life_bar = '\u2620 [dead]'

            hero_stats = '{bar}({life}) {name}'.format(bar=life_bar,
                                                       name=hero.name,
                                                       life=hero.life)

            screen += '\n' + colored(hero_stats,
                                     settings.TEAM_COLORS[hero.team])

        # print events (of last step) for debugging
        if self.debug:
            screen += u'\n'
            screen += u'\n'.join([colored('{}: {}'.format(thing.name, event),
                                          settings.TEAM_COLORS[thing.team])
                                  for t, thing, event in self.world.events
                                  if t == self.world.t])
        os.system('clear')
        print(screen)

    def destroyed_ancients(self):
        """Which ancients have been destroyed?"""
        return [ancient for ancient in self.ancients.values()
                if ancient.life <= 0]

    def game_ended(self):
        """Has the game ended?"""
        return len(self.destroyed_ancients()) > 0

    def game_result(self):
        """Was the game won?"""
        return '\n'.join('Team {} lost!'.format(ancient.team)
                         for ancient in self.destroyed_ancients())
<commit_msg>Stop game on end<commit_after>import os
import time

from termcolor import colored

from tota.world import World
from tota.things import Ancient, Hero, Creep
from tota.utils import closes_empty_position
from tota import settings

def get_hero_function(name):
    module = __import__('tota.heroes.' + name, fromlist=['create', ])
    create_function = getattr(module, 'create')

    return create_function()

class Game:
    """An instance of game controls the flow of the game.

       This includes player and creeps spawning, game main loop, deciding when
       to stop, importing map data, drawing each update, etc.
    """
    def __init__(self, radiant_heroes, dire_heroes, map_file_path, world_size,
                 debug=False, use_basic_icons=False):
        self.radiant_heroes = radiant_heroes
        self.dire_heroes = dire_heroes
        self.map_file_path = map_file_path
        self.debug = debug
        self.use_basic_icons = use_basic_icons

        self.heroes = []
        self.ancients = {}

        self.world = World(world_size, debug=debug)

        self.initialize_world_map()
        self.cache_ancients()
        self.initialize_heroes()

    def initialize_world_map(self):
        with open(self.map_file_path, encoding='utf-8') as map_file:
            map_text = map_file.read()
            self.world.import_map(map_text)

    def cache_ancients(self):
        def get_ancient(team):
            ancients = [thing for thing in self.world.things.values()
                        if isinstance(thing, Ancient) and thing.team == team]
            if not ancients:
                message = "Can't find the ancient for the {} team".format(team)
                raise Exception(message)
            elif len(ancients) > 1:
                message = "Team {} has 2 ancients".format(team)
                raise Exception(message)
            else:
                return ancients[0]

        for team in (settings.TEAM_DIRE, settings.TEAM_RADIANT):
            self.ancients[team] = get_ancient(team)

    def initialize_heroes(self):
        teams = {
            settings.TEAM_DIRE: self.dire_heroes,
            settings.TEAM_RADIANT: self.radiant_heroes,
        }
        for team, heroes in teams.items():
            for hero_name in heroes:
                hero = Hero(name=hero_name,
                            team=team,
                            act_function=get_hero_function(hero_name))
                self.heroes.append(hero)
                self.spawn_near_ancient(hero)

    def spawn_near_ancient(self, thing):
        """Spawn players or creeps near their ancient."""
        # start searching from the ancient position, outwards, until an empty
        # space is found, using breadth first graph search
        ancient = self.ancients[thing.team]
        spawn_at = closes_empty_position(ancient, self.world)
        if spawn_at:
            self.world.spawn(thing, spawn_at)
        else:
            message = "Can't spawn {} near its ancient".format(thing.name)
            raise Exception(message)

    def position_draw(self, position):
        """Get the string to draw for a given position of the world."""
        # decorations first, then things over them
        thing = self.world.things.get(position)

        if thing is not None:
            if self.use_basic_icons:
                icon = thing.ICON_BASIC
            else:
                icon = thing.ICON
            return colored(icon, settings.TEAM_COLORS[thing.team])
        else:
            return ' '

    def play(self, frames_per_second=2.0):
        """Game main loop, ending in a game result with description."""
        while True:
            # spawn creep wave
            if self.world.t % settings.CREEP_WAVE_COOLDOWN == 0:
                for team in (settings.TEAM_RADIANT, settings.TEAM_DIRE):
                    for i in range(settings.CREEP_WAVE_SIZE):
                        creep = Creep(team)
                        self.spawn_near_ancient(creep)

            self.world.step()

            # maintain the flow of zombies if necessary
            self.draw()

            if self.debug:
                input()
            else:
                time.sleep(1.0 / frames_per_second)

            if self.game_ended():
                description = self.game_result()
                print('')
                print(description)

                return description

    def draw(self):
        """Draw the world."""
        screen = ''

        # print the world
        screen += '\n'.join(u''.join(self.position_draw((x, y))
                                     for x in range(self.world.size[0]))
                            for y in range(self.world.size[1]))

        # game stats
        screen += '\nticks:{}'.format(self.world.t)

        # print hero stats
        for hero in sorted(self.heroes, key=lambda x: x.name):
            if hero.life > 0:
                # a small "health bar" with unicode chars, from 0 to 10 chars
                life_chars_count = int((10.0 / hero.max_life) * hero.life)
                life_chars = life_chars_count * '\u2588'
                no_life_chars = (10 - life_chars_count) * '\u2591'
                life_bar = '\u2665 {}{}'.format(life_chars, no_life_chars)
            else:
                life_bar = '\u2620 [dead]'

            hero_stats = '{bar}({life}) {name}'.format(bar=life_bar,
                                                       name=hero.name,
                                                       life=hero.life)

            screen += '\n' + colored(hero_stats,
                                     settings.TEAM_COLORS[hero.team])

        # print events (of last step) for debugging
        if self.debug:
            screen += u'\n'
            screen += u'\n'.join([colored('{}: {}'.format(thing.name, event),
                                          settings.TEAM_COLORS[thing.team])
                                  for t, thing, event in self.world.events
                                  if t == self.world.t])
        os.system('clear')
        print(screen)

    def destroyed_ancients(self):
        """Which ancients have been destroyed?"""
        return [ancient for ancient in self.ancients.values()
                if ancient.life <= 0]

    def game_ended(self):
        """Has the game ended?"""
        return len(self.destroyed_ancients()) > 0

    def game_result(self):
        """Was the game won?"""
        return '\n'.join('Team {} lost!'.format(ancient.team)
                         for ancient in self.destroyed_ancients())
<|endoftext|>


<commit_before>import numpy as np

from warnings import warn, filterwarnings, catch_warnings, simplefilter

# plotting
import matplotlib.pyplot as plt
from matplotlib import cm as mplcm
from matplotlib import gridspec
import matplotlib.ticker as mticker

# astropy ecosystem
from astropy import constants as c, units as u, table as t
from astropy.io import fits
from astropy import wcs
from astropy import coordinates as coord
from astropy.wcs.utils import pixel_to_skycoord

import os
import sys

# sklearn
from sklearn.neighbors import KNeighborsRegressor

# local
from importer import *
import read_results
import spectrophot

# personal
import manga_tools as m
import spec_tools

spec_unit = 1e-17 * u.erg / u.s / u.cm**2. / u.AA
l_unit = u.AA
bandpass_sol_l_unit = u.def_unit(
    s='bandpass_solLum', format={'latex': r'\overbar{\mathcal{L}_{\odot}}'},
    prefixes=False)
m_to_l_unit = 1. * u.Msun / bandpass_sol_l_unit

band_ix = dict(zip('FNugriz', range(len('FNugriz'))))

def infer_masked(ml, ml_mask, interior_mask):
    '''
    infer the masked values in the interior of an IFU (foreground stars, dropped fibers)
    '''

    ml_final = 1. * ml

    # coordinate arrays
    II, JJ = np.meshgrid(*list(map(np.arange, ml.shape)), indexing='ij')

    # set up KNN regressor
    knn = knn_regr(trn_coords=[II, JJ], trn_vals=ml, good_trn=~ml_mask)
    ml_final[interior_mask] = infer_from_knn(knn=knn, coords=(II, JJ))[interior_mask]

    return ml_final

def estimate_total_stellar_mass(results, pca_system, drp, dap, drpall_row, dapall_row,
                                cosmo, band='i', missing_mass_kwargs={}):
    '''
    find the total stellar mass of a galaxy with incomplete measurements
    '''

    # stellar mass to light ratio
    ml = results.cubechannel('ML{}'.format(band), 0)
    badpdf = results.cubechannel('GOODFRAC', 2) < 1.0e-4
    ml_mask = np.logical_or.reduce((results.mask, badpdf))

    # infer values in interior spaxels affected by one of the following:
    # bad PDF, foreground star, dead fiber
    interior_mask = np.logical_or.reduce((
        badpdf, (m.mask_from_maskbits(drp['MASK'].data, [3]).sum(axis=0) > 0),
        (m.mask_from_maskbits(drp['MASK'].data, [2]).sum(axis=0) > 0)))

    ml_final = infer_masked(ml, ml_mask, interior_mask)

    # convert spectroscopy to photometry
    results.setup_photometry(pca_system)
    s2p = results.spec2phot
    mag_band = s2p.ABmags['sdss2010-{}'.format(band)] * u.ABmag
    distmod = cosmo.distmod(drpall_row['nsa_zdist'])
    absmag_sun_band = spectrophot.absmag_sun_band[band] * u.ABmag
    bandpass_solLum = 10.**(
        -0.4 * (mag_band - distmod - absmag_sun_band).value) * \
        m.bandpass_sol_l_unit

    # figure out flux deficit in stated bandpass
    # first figure out cosmological correction for H0
    nsa_h = 1.0
    cosmocorr_mag = -5. * np.log10(nsa_h / cosmo.h) * u.mag
    nsa_elpetro_absmag_k = np.array(
        [nsa_absmag(drpall_row, band, 'elpetro') for band in 'FNugriz']) * u.ABmag + \
        cosmocorr_mag
    # then turn into app mag and flux
    nsa_elpetro_appmag_k = nsa_elpetro_absmag_k + distmod
    nsa_elpetro_fnu_k = nsa_elpetro_appmag_k.to(m.Mgy)
    nsa_elpetro_fnu_k_band = nsa_elpetro_appmag_k.to(m.Mgy)[band_ix[band]]

    # tabulate flux
    obs_bandpass_fnu = mag_band.to(m.Mgy)
    inf_ABmag = ~np.isfinite(mag_band)
    exterior_mask = np.logical_or(ml_mask, inf_ABmag) * (~interior_mask)
    flux_in_ifu = obs_bandpass_fnu[~exterior_mask].sum()
    # find missing flux (if any)
    missing_bandpass_fnu = nsa_elpetro_fnu_k_band - flux_in_ifu

    mass_in_ifu = (10.**ml_final * m.m_to_l_unit * bandpass_solLum)[~exterior_mask].sum()

    # calculate luminosity-weighted mass-to-light
    logml_fnuwt = np.average(
        ml_final[~exterior_mask], weights=obs_bandpass_fnu[~exterior_mask])
    ifu_lum = bandpass_solLum[~exterior_mask].sum()

    # if there's no (or negative) missing flux, just return coadded IFU
    if missing_bandpass_fnu <= 0. * m.Mgy:
        outer_logml_ring = -np.inf
        outer_logml_cmlr = -np.inf
        missing_bandpass_solLum = 0. * m.bandpass_sol_l_unit

    else:
        # missing flux in one band, to mag, to sol units
        missing_bandpass_mag = missing_bandpass_fnu.to(u.ABmag)
        missing_bandpass_solLum = 10.**(
            -0.4 * (missing_bandpass_mag - distmod - absmag_sun_band).value) * \
            m.bandpass_sol_l_unit

        # assume missing mass has M/L equal to average of outermost 0.5 Re
        # now find the median of the outer unmasked .5 Re
        reff = np.ma.array(dap['SPX_ELLCOO'].data[1], mask=ml_mask)
        outer_ring = np.logical_and((reff <= reff.max()), (reff >= reff.max() - .5))
        outer_logml_ring = np.median(ml[~ml_mask * outer_ring])

        # apply cmlr
        outer_logml_cmlr = apply_cmlr(
            ifu_s2p=s2p, f_tot=nsa_elpetro_fnu_k, fluxes_keys='FNugriz',
            mlrb=band, exterior_mask=exterior_mask, **missing_mass_kwargs)

    return (mass_in_ifu, 10.**logml_fnuwt, ifu_lum.value,
            10.**outer_logml_ring, 10.**outer_logml_cmlr, missing_bandpass_solLum.value)

def knn_regr(trn_coords, trn_vals, good_trn, k=8):
    '''
    return a trained estimator for k-nearest-neighbors

    - trn_coords: list containing row-coordinate map and col-coordinate map
    - trn_vals: map of values used for training
    - good_trn: binary map (True signifies good data)
    '''
    II, JJ = trn_coords
    good = good_trn.flatten()
    coo = np.column_stack([II.flatten()[good], JJ.flatten()[good]])
    vals = trn_vals.flatten()[good]

    knn = KNeighborsRegressor(
        n_neighbors=k, weights='uniform', p=2)
    knn.fit(coo, vals)

    return knn

def infer_from_knn(knn, coords):
    '''
    use KNN regressor to infer values over a grid
    '''
    II, JJ = coords
    coo = np.column_stack([II.flatten(), JJ.flatten()])
    vals = knn.predict(coo).reshape(II.shape)

    return vals

def apply_cmlr(ifu_s2p, cb1, cb2, mlrb, cmlr_poly, f_tot, exterior_mask,
               fluxes_keys='FNugriz'):
    '''
    apply a color-mass-to-light relation
    '''
    f_tot_d = dict(zip(fluxes_keys, f_tot))

    # find missing flux in color-band 1
    fb1_ifu = (ifu_s2p.ABmags['sdss2010-{}'.format(cb1)] * u.ABmag)[~exterior_mask].to(m.Mgy).sum()
    dfb1 = f_tot_d[cb1] - fb1_ifu
    # find missing flux in color-band 2
    fb2_ifu = (ifu_s2p.ABmags['sdss2010-{}'.format(cb2)] * u.ABmag)[~exterior_mask].to(m.Mgy).sum()
    dfb2 = f_tot_d[cb2] - fb2_ifu

    # if there's no missing flux in one/both bands, then this method fails
    if (dfb1.value <= 0.) or (dfb2.value <= 0.):
        return -np.inf

    c = dfb1.to(u.ABmag) - dfb2.to(u.ABmag)

    logml = np.polyval(p=cmlr_poly, x=c.value)

    return logml

def nsa_mass(drpall_row, band, kind='elpetro'):
    # kind is elpetro or sersic
    mass = drpall_row['nsa_{}_mass'.format(kind)][band_ix[band]]
    return mass

def nsa_flux(drpall_row, band, kind='elpetro'):
    # kind is petro, elpetro, or sersic
    flux = drpall_row['nsa_{}_flux'.format(kind)][band_ix[band]]
    return flux

def nsa_absmag(drpall_row, band, kind='elpetro'):
    # kind is petro, elpetro, or sersic
    flux = drpall_row['nsa_{}_absmag'.format(kind)][band_ix[band]]
    return flux
<commit_msg>refactor stellar mass aggregation into a class<commit_after>import numpy as np
from scipy.special import expit
from scipy.optimize import curve_fit

from warnings import warn, filterwarnings, catch_warnings, simplefilter
from functools import lru_cache

# plotting
import matplotlib.pyplot as plt
from matplotlib import cm as mplcm
from matplotlib import gridspec
import matplotlib.ticker as mticker

# astropy ecosystem
from astropy import constants as c, units as u, table as t
from astropy.io import fits
from astropy import wcs
from astropy import coordinates as coord
from astropy.wcs.utils import pixel_to_skycoord

import os
import sys

# sklearn
from sklearn.neighbors import KNeighborsRegressor

# local
from importer import *
import read_results
import spectrophot

# personal
import manga_tools as m
import spec_tools

spec_unit = 1e-17 * u.erg / u.s / u.cm**2. / u.AA
l_unit = u.AA
bandpass_sol_l_unit = u.def_unit(
    s='bandpass_solLum', format={'latex': r'\overbar{\mathcal{L}_{\odot}}'},
    prefixes=False)
m_to_l_unit = 1. * u.Msun / bandpass_sol_l_unit

band_ix = dict(zip('FNugriz', range(len('FNugriz'))))

sdss_bands = 'ugriz'
nsa_bands = 'FNugriz'

class Sigmoid(object):
    p0 = [70., .1, -5., 20.]

    def __init__(self, vscale, hscale, xoffset, yoffset):
        self.vscale, self.hscale = vscale, hscale
        self.xoffset, self.yoffset = xoffset, yoffset

    @staticmethod
    def sigmoid(x, vscale, hscale, xoffset, yoffset):
        return vscale * expit(x / hscale + xoffset) + yoffset

    @classmethod
    def from_points(cls, x, y):
        params, *_ = curve_fit(f=Sigmoid.sigmoid, xdata=x, ydata=y,
                                p0=Sigmoid.p0)
        return cls(*params)

    def __call__(self, x):
        return self.sigmoid(x, self.vscale, self.hscale, self.xoffset, self.yoffset)

    def __repr__(self):
        return 'Sigmoid function: \
                <vscale = {:.02e}, hscale = {:.02e}, xoffset = {:.02e}, yoffset = {:.02e}>'.format(
                    self.vscale, self.hscale, self.xoffset, self.yoffset)

ba_to_majaxis_angle = Sigmoid.from_points(
    [-1000., 0.2, 0.45, 0.65, 0.9, 1000.], [20., 30., 50., 70., 90., 100.])

def infer_masked(q_trn, bad_trn, infer_here):
    '''
    infer the masked values in the interior of an IFU (foreground stars, dropped fibers)
    '''

    q_final = 1. * q_trn

    # coordinate arrays
    II, JJ = np.meshgrid(*list(map(np.arange, q_trn.shape)), indexing='ij')

    # set up KNN regressor
    knn = knn_regr(trn_coords=[II, JJ], trn_vals=q_trn, good_trn=~bad_trn)
    q_final[infer_here] = infer_from_knn(knn=knn, coords=(II, JJ))[infer_here]

    return q_final

def ifu_bandmag(s2p, b, low_or_no_cov, drp3dmask_interior):
    '''
    flux in bandpass, inferring at masked spaxels
    '''
    mag_band = s2p.ABmags['sdss2010-{}'.format(b)]
    nolight = ~np.isfinite(mag_band)
    # "interpolate" over spaxels with foreground stars or other non-inference-related masks
    mag_band = infer_masked(
        q_trn=mag_band, bad_trn=np.logical_or.reduce((low_or_no_cov, drp3dmask_interior, nolight)),
        infer_here=drp3dmask_interior)
    mag_band[nolight] = np.inf
    return mag_band

def bandpass_flux_to_solarunits(sun_flux_band):
    '''
    equivalency for bandpass fluxes and solar units
    '''
    sun_flux_band_Mgy = sun_flux_band.to(m.Mgy).value
    def convert_flux_to_solar(f):
        s = f / sun_flux_band_Mgy
        return s

    def convert_solar_to_flux(s):
        f = s * sun_flux_band_Mgy
        return f

    return [(m.Mgy, m.bandpass_sol_l_unit, convert_flux_to_solar, convert_solar_to_flux)]

class StellarMass(object):
    '''
    calculating galaxy stellar mass with incomplete measurements
    '''
    bands = 'griz'
    bands_ixs = dict(zip(bands, range(len(bands))))
    absmag_sun = np.array([spectrophot.absmag_sun_band[b] for b in bands]) * u.ABmag

    def __init__(self, results, pca_system, drp, dap, drpall_row, cosmo, mlband='i'):
        self.results = results
        self.pca_system = pca_system
        self.drp = drp
        self.dap = dap
        self.drpall_row = drpall_row
        self.cosmo = cosmo
        self.mlband = mlband

        with catch_warnings():
            simplefilter('ignore')
            self.results.setup_photometry(pca_system)

        self.s2p = results.spec2phot

        # stellar mass to light ratio
        self.ml0 = results.cubechannel('ML{}'.format(mlband), 0)
        self.badpdf = results.cubechannel('GOODFRAC', 2) < 1.0e-4
        self.ml_mask = np.logical_or.reduce((self.results.mask, self.badpdf))

        # infer values in interior spaxels affected by one of the following:
        # bad PDF, foreground star, dead fiber
        self.low_or_no_cov = m.mask_from_maskbits(
            self.drp['MASK'].data, [0, 1]).mean(axis=0) > .3
        self.drp3dmask_interior = m.mask_from_maskbits(
            self.drp['MASK'].data, [2, 3]).mean(axis=0) > .3
        self.interior_mask = np.logical_or.reduce((self.badpdf, self.drp3dmask_interior))

        self.logml_final = infer_masked(
            q_trn=self.ml0, bad_trn=self.ml_mask,
            infer_here=self.interior_mask) * u.dex(m.m_to_l_unit)

    @property
    @lru_cache(maxsize=128)
    def distmod(self):
        return self.cosmo.distmod(self.drpall_row['nsa_zdist'])

    @property
    @lru_cache(maxsize=128)
    def nsa_absmags(self):
        absmags = np.array([nsa_absmag(self.drpall_row, band, kind='elpetro')
                            for band in self.bands]) * (u.ABmag - u.MagUnit(u.littleh**2))
        return absmags

    @property
    @lru_cache(maxsize=128)
    def nsa_absmags_cosmocorr(self):
        return self.nsa_absmags.to(u.ABmag, u.with_H0(self.cosmo.H0))

    @property
    @lru_cache(maxsize=128)
    def mag_bands(self):
        return np.array([ifu_bandmag(self.s2p, b, self.low_or_no_cov, self.drp3dmask_interior)
                         for b in self.bands]) * u.ABmag

    @property
    @lru_cache(maxsize=128)
    def flux_bands(self):
        return self.mag_bands.to(m.Mgy)

    @property
    @lru_cache(maxsize=128)
    def absmag_bands(self):
        return self.mag_bands - self.distmod

    @property
    @lru_cache(maxsize=128)
    def ifu_flux_bands(self):
        return self.flux_bands.sum(axis=(1, 2))

    @property
    @lru_cache(maxsize=128)
    def ifu_mag_bands(self):
        return self.ifu_flux_bands.to(u.ABmag)

    @property
    @lru_cache(maxsize=128)
    def sollum_bands(self):
        return self.absmag_bands.to(
            u.dex(m.bandpass_sol_l_unit),
            bandpass_flux_to_solarunits(self.absmag_sun[..., None, None]))

    @property
    @lru_cache(maxsize=128)
    def logml_fnuwt(self):
        return np.average(
            self.logml_final.value,
            weights=self.flux_bands[self.bands_ixs[self.mlband]].value) * self.logml_final.unit

    @property
    @lru_cache(maxsize=128)
    def mstar(self):
        return (self.sollum_bands + self.logml_final).to(u.Msun)

    @property
    @lru_cache(maxsize=128)
    def mstar_in_ifu(self):
        return self.mstar.sum(axis=(1, 2))

    def to_table(self):
        '''
        make table of stellar-mass results

        [plateifu, [flux_ifusummed_band1, flux_ifusummed_band2], ...,
         [flux_nsa_band1, flux_nsa_band2], ...,
         [dflux_(nsa-ifu)_band1, dflux_(nsa-ifu)_band2], ...,
         mass_in_ifu, logml_apercorr_ring, logml_apercorr_cmlr, logml_fluxwtd]
        '''

        tab = t.Table()
        tab['plateifu'] = [self.drpall_row['plateifu']]

        # tabulate mass in IFU
        tab['mass_in_ifu'] = self.mstar_in_ifu[None, ...]

        # calculate and store missing luminosities in solar units
        flux_outside_ifu = (self.nsa_absmags_cosmocorr + self.distmod).to(m.Mgy) - self.ifu_flux_bands
        mag_outside_ifu = flux_outside_ifu.to(u.ABmag)
        absmag_outside_ifu = mag_outside_ifu - self.distmod
        sollum_outside_ifu = absmag_outside_ifu.to(
            u.dex(m.bandpass_sol_l_unit), bandpass_flux_to_solarunits(self.absmag_sun))
        tab['missing_lum'] = sollum_outside_ifu[None, ...]
        tab['missing_lum'].meta['band'] = self.bands

        tab['ml_ring'] = self.ml_ring

        tab['ml_fluxwt'] = self.logml_fnuwt
        tab['ml_fluxwt'].meta['band'] = self.mlband

        tab['ifu_lum'] = (self.ifu_mag_bands - self.distmod).to(
            u.dex(m.bandpass_sol_l_unit), bandpass_flux_to_solarunits(self.absmag_sun))[None, ...]
        tab['ifu_lum'].meta['band'] = self.mlband

        return tab

    @property
    @lru_cache(maxsize=128)
    def ml_ring(self):
        '''
        "ring" aperture-correction
        '''
        phi = self.dap['SPX_ELLCOO'].data[2, ...]
        angle_from_majoraxis = np.minimum.reduce(
            (np.abs(phi), np.abs(180. - phi), np.abs(360. - phi)))
        # how close to major axis must a spaxel be in order to consider it?
        close_to_majaxis = (angle_from_majoraxis <= ba_to_majaxis_angle(
            self.drpall_row['nsa_elpetro_ba']))
        reff = np.ma.array(
            self.dap['SPX_ELLCOO'].data[1], mask=np.logical_or(self.ml_mask, ~close_to_majaxis))
        outer_ring = np.logical_and.reduce((
            (reff <= reff.max()), (reff >= reff.max() - .5)))
        outer_logml_ring = np.median(self.ml0[~self.ml_mask * outer_ring]) * self.logml_final.unit

        return outer_logml_ring

def knn_regr(trn_coords, trn_vals, good_trn, k=8):
    '''
    return a trained estimator for k-nearest-neighbors

    - trn_coords: list containing row-coordinate map and col-coordinate map
    - trn_vals: map of values used for training
    - good_trn: binary map (True signifies good data)
    '''
    II, JJ = trn_coords
    good = good_trn.flatten()
    coo = np.column_stack([II.flatten()[good], JJ.flatten()[good]])
    vals = trn_vals.flatten()[good]

    knn = KNeighborsRegressor(
        n_neighbors=k, weights='uniform', p=2)
    knn.fit(coo, vals)

    return knn

def infer_from_knn(knn, coords):
    '''
    use KNN regressor to infer values over a grid
    '''
    II, JJ = coords
    coo = np.column_stack([II.flatten(), JJ.flatten()])
    vals = knn.predict(coo).reshape(II.shape)

    return vals

def apply_cmlr(ifu_s2p, cb1, cb2, mlrb, cmlr_poly, f_tot, exterior_mask,
               fluxes_keys='FNugriz'):
    '''
    apply a color-mass-to-light relation
    '''
    f_tot_d = dict(zip(fluxes_keys, f_tot))

    # find missing flux in color-band 1
    fb1_ifu = (ifu_s2p.ABmags['sdss2010-{}'.format(cb1)] * u.ABmag)[~exterior_mask].to(m.Mgy).sum()
    dfb1 = f_tot_d[cb1] - fb1_ifu
    # find missing flux in color-band 2
    fb2_ifu = (ifu_s2p.ABmags['sdss2010-{}'.format(cb2)] * u.ABmag)[~exterior_mask].to(m.Mgy).sum()
    dfb2 = f_tot_d[cb2] - fb2_ifu

    # if there's no missing flux in one/both bands, then this method fails
    if (dfb1.value <= 0.) or (dfb2.value <= 0.):
        return -np.inf

    c = dfb1.to(u.ABmag) - dfb2.to(u.ABmag)

    logml = np.polyval(p=cmlr_poly, x=c.value)

    return logml

def nsa_mass(drpall_row, band, kind='elpetro'):
    # kind is elpetro or sersic
    mass = drpall_row['nsa_{}_mass'.format(kind)][band_ix[band]]
    return mass

def nsa_flux(drpall_row, band, kind='elpetro'):
    # kind is petro, elpetro, or sersic
    flux = drpall_row['nsa_{}_flux'.format(kind)][band_ix[band]]
    return flux

def nsa_absmag(drpall_row, band, kind='elpetro'):
    # kind is petro, elpetro, or sersic
    flux = drpall_row['nsa_{}_absmag'.format(kind)][band_ix[band]]
    return flux
<|endoftext|>


<commit_before>from __future__ import with_statement
import sys, os, re
import py
import tox
from tox._config import DepConfig

class CreationConfig:
    def __init__(self, md5, python, version, distribute, sitepackages, deps):
        self.md5 = md5
        self.python = python
        self.version = version
        self.distribute = distribute
        self.sitepackages = sitepackages
        self.deps = deps

    def writeconfig(self, path):
        lines = ["%s %s" % (self.md5, self.python)]
        lines.append("%s %d %d" % (self.version, self.distribute,
                        self.sitepackages))
        for dep in self.deps:
            lines.append("%s %s" % dep)
        path.ensure()
        path.write("\n".join(lines))

    @classmethod
    def readconfig(cls, path):
        try:
            lines = path.readlines(cr=0)
            value = lines.pop(0).split(None, 1)
            md5, python = value
            version, distribute, sitepackages = lines.pop(0).split(None, 2)
            distribute = bool(int(distribute))
            sitepackages = bool(int(sitepackages))
            deps = []
            for line in lines:
                md5, depstring = line.split(None, 1)
                deps.append((md5, depstring))
            return CreationConfig(md5, python, version,
                        distribute, sitepackages, deps)
        except KeyboardInterrupt:
            raise
        except:
            return None

    def matches(self, other):
        return (other and self.md5 == other.md5
           and self.python == other.python
           and self.version == other.version
           and self.distribute == other.distribute
           and self.sitepackages == other.sitepackages
           and self.deps == other.deps)

class VirtualEnv(object):
    def __init__(self, envconfig=None, session=None):
        self.envconfig = envconfig
        self.session = session
        self.path = envconfig.envdir
        self.path_config = self.path.join(".tox-config1")

    @property
    def name(self):
        return self.envconfig.envname

    def __repr__(self):
        return "<VirtualEnv at %r>" %(self.path)

    def getcommandpath(self, name=None, venv=True, cwd=None):
        if name is None:
            return self.envconfig.envpython
        name = str(name)
        if os.path.isabs(name):
            return name
        if os.path.split(name)[0] == ".":
            p = cwd.join(name)
            if p.check():
                return str(p)
        p = py.path.local.sysfind(name)
        if p is None:
            raise tox.exception.InvocationError("could not find executable %r"
                % (name,))
        if p.relto(self.envconfig.envdir):
            return p
        if venv:
            self.session.report.warning(
                "test command found but not installed in testenv\n"
                "  cmd: %s\n"
                "  env: %s\n"
                "Maybe forgot to specify a dependency?" % (p,
                self.envconfig.envdir))
        return str(p) # will not be rewritten for reporting

    def _ispython3(self):
        return "python3" in str(self.envconfig.basepython)

    def update(self, action=None):
        """ return status string for updating actual venv to match configuration.
            if status string is empty, all is ok.
        """
        if action is None:
            action = self.session.newaction(self, "update")
        report = self.session.report
        name = self.envconfig.envname
        rconfig = CreationConfig.readconfig(self.path_config)
        if not self.envconfig.recreate and rconfig and \
            rconfig.matches(self._getliveconfig()):
            action.info("reusing", self.envconfig.envdir)
            return
        if rconfig is None:
            action.setactivity("create", self.envconfig.envdir)
        else:
            action.setactivity("recreate", self.envconfig.envdir)
        try:
            self.create(action)
        except tox.exception.UnsupportedInterpreter:
            return sys.exc_info()[1]
        except tox.exception.InterpreterNotFound:
            return sys.exc_info()[1]
        try:
            self.install_deps(action)
        except tox.exception.InvocationError:
            v = sys.exc_info()[1]
            return "could not install deps %s" %(self.envconfig.deps,)

    def _getliveconfig(self):
        python = self.getconfigexecutable()
        md5 = getdigest(python)
        version = tox.__version__
        distribute = self.envconfig.distribute
        sitepackages = self.envconfig.sitepackages
        deps = []
        for dep in self._getresolvedeps():
            raw_dep = dep.name
            md5 = getdigest(raw_dep)
            deps.append((md5, raw_dep))
        return CreationConfig(md5, python, version,
                        distribute, sitepackages, deps)

    def _getresolvedeps(self):
        l = []
        for dep in self.envconfig.deps:
            if dep.indexserver is None:
                res = self.session._resolve_pkg(dep.name)
                if res != dep.name:
                    dep = dep.__class__(res)
            l.append(dep)
        return l

    def getconfigexecutable(self):
        python = self.envconfig.basepython
        if not python:
            python = sys.executable
        x = find_executable(str(python))
        if x:
            x = x.realpath()
        return x

    def getsupportedinterpreter(self):
        if sys.platform == "win32" and self.envconfig.basepython and \
                "jython" in self.envconfig.basepython:
            raise tox.exception.UnsupportedInterpreter(
                "Jython/Windows does not support installing scripts")
        config_executable = self.getconfigexecutable()
        if not config_executable:
            raise tox.exception.InterpreterNotFound(self.envconfig.basepython)
        return config_executable

    def create(self, action=None):
        #if self.getcommandpath("activate").dirpath().check():
        #    return
        if action is None:
            action = self.session.newaction(self, "create")
        config_interpreter = self.getsupportedinterpreter()
        f, path, _ = py.std.imp.find_module("virtualenv")
        f.close()
        venvscript = path.rstrip("co")
        #venvscript = py.path.local(tox.__file__).dirpath("virtualenv.py")
        args = [config_interpreter, venvscript]
        if not self._ispython3() and self.envconfig.distribute:
            args.append('--distribute')
        if self.envconfig.sitepackages:
            args.append('--system-site-packages')
        #if sys.platform == "win32":
        #    f, path, _ = py.std.imp.find_module("virtualenv")
        #    f.close()
        #    args[:1] = [str(config_interpreter), str(path)]
        #else:
        self.session.make_emptydir(self.path)
        basepath = self.path.dirpath()
        basepath.ensure(dir=1)
        args.append(self.path.basename)
        self._pcall(args, venv=False, action=action, cwd=basepath)
        self.just_created = True

    def install_sdist(self, sdistpath, action):
        assert action is not None
        if getattr(self, 'just_created', False):
            action.setactivity("sdist-inst", sdistpath)
            self._getliveconfig().writeconfig(self.path_config)
            extraopts = []
        else:
            action.setactivity("sdist-reinst", sdistpath)
            extraopts = ['-U', '--no-deps']
        self._install([sdistpath], extraopts=extraopts, action=action)

    def install_deps(self, action=None):
        if action is None:
            action = self.session.newaction(self, "install_deps")
        deps = self._getresolvedeps()
        if deps:
            depinfo = ", ".join(map(str, deps))
            action.setactivity("installdeps",
                "%s" % depinfo)
            self._install(deps, action=action)

    def _commoninstallopts(self, indexserver):
        l = []
        if indexserver:
            l += ["-i", indexserver]
        return l

    def easy_install(self, args, indexserver=None):
        argv = ["easy_install"] + self._commoninstallopts(indexserver) + args
        self._pcall(argv, cwd=self.envconfig.envlogdir)

    def pip_install(self, args, indexserver=None, action=None):
        argv = ["pip", "install"] + self._commoninstallopts(indexserver)
        if self.envconfig.downloadcache:
            self.envconfig.downloadcache.ensure(dir=1)
            argv.append("--download-cache=%s" %
                self.envconfig.downloadcache)
        for x in ('PIP_RESPECT_VIRTUALENV', 'PIP_REQUIRE_VIRTUALENV'):
            try:
                del os.environ[x]
            except KeyError:
                pass
        argv += args
        env = dict(PYTHONIOENCODING='utf_8')
        self._pcall(argv, cwd=self.envconfig.envlogdir, extraenv=env,
            action=action)

    def _install(self, deps, extraopts=None, action=None):
        if not deps:
            return
        d = {}
        l = []
        for dep in deps:
            if isinstance(dep, (str, py.path.local)):
                dep = DepConfig(str(dep), None)
            assert isinstance(dep, DepConfig), dep
            if dep.indexserver is None:
                ixserver = self.envconfig.config.indexserver['default']
            else:
                ixserver = dep.indexserver
            d.setdefault(ixserver, []).append(dep.name)
            if ixserver not in l:
                l.append(ixserver)
            assert ixserver.url is None or isinstance(ixserver.url, str)

        extraopts = extraopts or []
        for ixserver in l:
            args = d[ixserver] + extraopts
            self.pip_install(args, ixserver.url, action)

    def _getenv(self):
        env = self.envconfig.setenv
        if env:
            env_arg = os.environ.copy()
            env_arg.update(env)
        else:
            env_arg = None
        return env_arg

    def test(self, redirect=False):
        action = self.session.newaction(self, "runtests")
        with action:
            self.session.make_emptydir(self.envconfig.envtmpdir)
            cwd = self.envconfig.changedir
            for i, argv in enumerate(self.envconfig.commands):
                action.setactivity("runtests", "commands[%s]" % i)
                try:
                    self._pcall(argv, cwd=cwd, action=action, redirect=redirect)
                except tox.exception.InvocationError:
                    self.session.report.error(str(sys.exc_info()[1]))
                    return True

    def _pcall(self, args, venv=True, cwd=None, extraenv={},
            action=None, redirect=True):
        try:
            del os.environ['PYTHONDONTWRITEBYTECODE']
        except KeyError:
            pass
        assert cwd
        cwd.ensure(dir=1)
        old = self.patchPATH()
        try:
            args[0] = self.getcommandpath(args[0], venv, cwd)
            env = self._getenv() or os.environ.copy()
            env.update(extraenv)
            return action.popen(args, cwd=cwd, env=env, redirect=redirect)
        finally:
            os.environ['PATH'] = old

    def patchPATH(self):
        oldPATH = os.environ['PATH']
        bindir = str(self.envconfig.envbindir)
        os.environ['PATH'] = os.pathsep.join([bindir, oldPATH])
        return oldPATH

def getdigest(path):
    path = py.path.local(path)
    if not path.check(file=1):
        return "0" * 32
    return path.computehash()

if sys.platform != "win32":
    def find_executable(name):
        return py.path.local.sysfind(name)

else:
    # Exceptions to the usual windows mapping
    win32map = {
            'python': sys.executable,
            'jython': "c:\jython2.5.1\jython.bat",
    }
    def find_executable(name):
        p = py.path.local(name)
        if p.check(file=1):
            return p
        actual = None
        # Is this a standard PythonX.Y name?
        m = re.match(r"python(\d)\.(\d)", name)
        if m:
            # The standard names are in predictable places.
            actual = r"c:\python%s%s\python.exe" % m.groups()
        if not actual:
            actual = win32map.get(name, None)
        if actual:
            actual = py.path.local(actual)
            if actual.check():
                return actual
<commit_msg>Fallback to py.exe launcher to locate Python versions on Windows<commit_after>from __future__ import with_statement
import sys, os, re
import py
import tox
from tox._config import DepConfig

class CreationConfig:
    def __init__(self, md5, python, version, distribute, sitepackages, deps):
        self.md5 = md5
        self.python = python
        self.version = version
        self.distribute = distribute
        self.sitepackages = sitepackages
        self.deps = deps

    def writeconfig(self, path):
        lines = ["%s %s" % (self.md5, self.python)]
        lines.append("%s %d %d" % (self.version, self.distribute,
                        self.sitepackages))
        for dep in self.deps:
            lines.append("%s %s" % dep)
        path.ensure()
        path.write("\n".join(lines))

    @classmethod
    def readconfig(cls, path):
        try:
            lines = path.readlines(cr=0)
            value = lines.pop(0).split(None, 1)
            md5, python = value
            version, distribute, sitepackages = lines.pop(0).split(None, 2)
            distribute = bool(int(distribute))
            sitepackages = bool(int(sitepackages))
            deps = []
            for line in lines:
                md5, depstring = line.split(None, 1)
                deps.append((md5, depstring))
            return CreationConfig(md5, python, version,
                        distribute, sitepackages, deps)
        except KeyboardInterrupt:
            raise
        except:
            return None

    def matches(self, other):
        return (other and self.md5 == other.md5
           and self.python == other.python
           and self.version == other.version
           and self.distribute == other.distribute
           and self.sitepackages == other.sitepackages
           and self.deps == other.deps)

class VirtualEnv(object):
    def __init__(self, envconfig=None, session=None):
        self.envconfig = envconfig
        self.session = session
        self.path = envconfig.envdir
        self.path_config = self.path.join(".tox-config1")

    @property
    def name(self):
        return self.envconfig.envname

    def __repr__(self):
        return "<VirtualEnv at %r>" %(self.path)

    def getcommandpath(self, name=None, venv=True, cwd=None):
        if name is None:
            return self.envconfig.envpython
        name = str(name)
        if os.path.isabs(name):
            return name
        if os.path.split(name)[0] == ".":
            p = cwd.join(name)
            if p.check():
                return str(p)
        p = py.path.local.sysfind(name)
        if p is None:
            raise tox.exception.InvocationError("could not find executable %r"
                % (name,))
        if p.relto(self.envconfig.envdir):
            return p
        if venv:
            self.session.report.warning(
                "test command found but not installed in testenv\n"
                "  cmd: %s\n"
                "  env: %s\n"
                "Maybe forgot to specify a dependency?" % (p,
                self.envconfig.envdir))
        return str(p) # will not be rewritten for reporting

    def _ispython3(self):
        return "python3" in str(self.envconfig.basepython)

    def update(self, action=None):
        """ return status string for updating actual venv to match configuration.
            if status string is empty, all is ok.
        """
        if action is None:
            action = self.session.newaction(self, "update")
        report = self.session.report
        name = self.envconfig.envname
        rconfig = CreationConfig.readconfig(self.path_config)
        if not self.envconfig.recreate and rconfig and \
            rconfig.matches(self._getliveconfig()):
            action.info("reusing", self.envconfig.envdir)
            return
        if rconfig is None:
            action.setactivity("create", self.envconfig.envdir)
        else:
            action.setactivity("recreate", self.envconfig.envdir)
        try:
            self.create(action)
        except tox.exception.UnsupportedInterpreter:
            return sys.exc_info()[1]
        except tox.exception.InterpreterNotFound:
            return sys.exc_info()[1]
        try:
            self.install_deps(action)
        except tox.exception.InvocationError:
            v = sys.exc_info()[1]
            return "could not install deps %s" %(self.envconfig.deps,)

    def _getliveconfig(self):
        python = self.getconfigexecutable()
        md5 = getdigest(python)
        version = tox.__version__
        distribute = self.envconfig.distribute
        sitepackages = self.envconfig.sitepackages
        deps = []
        for dep in self._getresolvedeps():
            raw_dep = dep.name
            md5 = getdigest(raw_dep)
            deps.append((md5, raw_dep))
        return CreationConfig(md5, python, version,
                        distribute, sitepackages, deps)

    def _getresolvedeps(self):
        l = []
        for dep in self.envconfig.deps:
            if dep.indexserver is None:
                res = self.session._resolve_pkg(dep.name)
                if res != dep.name:
                    dep = dep.__class__(res)
            l.append(dep)
        return l

    def getconfigexecutable(self):
        python = self.envconfig.basepython
        if not python:
            python = sys.executable
        x = find_executable(str(python))
        if x:
            x = x.realpath()
        return x

    def getsupportedinterpreter(self):
        if sys.platform == "win32" and self.envconfig.basepython and \
                "jython" in self.envconfig.basepython:
            raise tox.exception.UnsupportedInterpreter(
                "Jython/Windows does not support installing scripts")
        config_executable = self.getconfigexecutable()
        if not config_executable:
            raise tox.exception.InterpreterNotFound(self.envconfig.basepython)
        return config_executable

    def create(self, action=None):
        #if self.getcommandpath("activate").dirpath().check():
        #    return
        if action is None:
            action = self.session.newaction(self, "create")
        config_interpreter = self.getsupportedinterpreter()
        f, path, _ = py.std.imp.find_module("virtualenv")
        f.close()
        venvscript = path.rstrip("co")
        #venvscript = py.path.local(tox.__file__).dirpath("virtualenv.py")
        args = [config_interpreter, venvscript]
        if not self._ispython3() and self.envconfig.distribute:
            args.append('--distribute')
        if self.envconfig.sitepackages:
            args.append('--system-site-packages')
        #if sys.platform == "win32":
        #    f, path, _ = py.std.imp.find_module("virtualenv")
        #    f.close()
        #    args[:1] = [str(config_interpreter), str(path)]
        #else:
        self.session.make_emptydir(self.path)
        basepath = self.path.dirpath()
        basepath.ensure(dir=1)
        args.append(self.path.basename)
        self._pcall(args, venv=False, action=action, cwd=basepath)
        self.just_created = True

    def install_sdist(self, sdistpath, action):
        assert action is not None
        if getattr(self, 'just_created', False):
            action.setactivity("sdist-inst", sdistpath)
            self._getliveconfig().writeconfig(self.path_config)
            extraopts = []
        else:
            action.setactivity("sdist-reinst", sdistpath)
            extraopts = ['-U', '--no-deps']
        self._install([sdistpath], extraopts=extraopts, action=action)

    def install_deps(self, action=None):
        if action is None:
            action = self.session.newaction(self, "install_deps")
        deps = self._getresolvedeps()
        if deps:
            depinfo = ", ".join(map(str, deps))
            action.setactivity("installdeps",
                "%s" % depinfo)
            self._install(deps, action=action)

    def _commoninstallopts(self, indexserver):
        l = []
        if indexserver:
            l += ["-i", indexserver]
        return l

    def easy_install(self, args, indexserver=None):
        argv = ["easy_install"] + self._commoninstallopts(indexserver) + args
        self._pcall(argv, cwd=self.envconfig.envlogdir)

    def pip_install(self, args, indexserver=None, action=None):
        argv = ["pip", "install"] + self._commoninstallopts(indexserver)
        if self.envconfig.downloadcache:
            self.envconfig.downloadcache.ensure(dir=1)
            argv.append("--download-cache=%s" %
                self.envconfig.downloadcache)
        for x in ('PIP_RESPECT_VIRTUALENV', 'PIP_REQUIRE_VIRTUALENV'):
            try:
                del os.environ[x]
            except KeyError:
                pass
        argv += args
        env = dict(PYTHONIOENCODING='utf_8')
        self._pcall(argv, cwd=self.envconfig.envlogdir, extraenv=env,
            action=action)

    def _install(self, deps, extraopts=None, action=None):
        if not deps:
            return
        d = {}
        l = []
        for dep in deps:
            if isinstance(dep, (str, py.path.local)):
                dep = DepConfig(str(dep), None)
            assert isinstance(dep, DepConfig), dep
            if dep.indexserver is None:
                ixserver = self.envconfig.config.indexserver['default']
            else:
                ixserver = dep.indexserver
            d.setdefault(ixserver, []).append(dep.name)
            if ixserver not in l:
                l.append(ixserver)
            assert ixserver.url is None or isinstance(ixserver.url, str)

        extraopts = extraopts or []
        for ixserver in l:
            args = d[ixserver] + extraopts
            self.pip_install(args, ixserver.url, action)

    def _getenv(self):
        env = self.envconfig.setenv
        if env:
            env_arg = os.environ.copy()
            env_arg.update(env)
        else:
            env_arg = None
        return env_arg

    def test(self, redirect=False):
        action = self.session.newaction(self, "runtests")
        with action:
            self.session.make_emptydir(self.envconfig.envtmpdir)
            cwd = self.envconfig.changedir
            for i, argv in enumerate(self.envconfig.commands):
                action.setactivity("runtests", "commands[%s]" % i)
                try:
                    self._pcall(argv, cwd=cwd, action=action, redirect=redirect)
                except tox.exception.InvocationError:
                    self.session.report.error(str(sys.exc_info()[1]))
                    return True

    def _pcall(self, args, venv=True, cwd=None, extraenv={},
            action=None, redirect=True):
        try:
            del os.environ['PYTHONDONTWRITEBYTECODE']
        except KeyError:
            pass
        assert cwd
        cwd.ensure(dir=1)
        old = self.patchPATH()
        try:
            args[0] = self.getcommandpath(args[0], venv, cwd)
            env = self._getenv() or os.environ.copy()
            env.update(extraenv)
            return action.popen(args, cwd=cwd, env=env, redirect=redirect)
        finally:
            os.environ['PATH'] = old

    def patchPATH(self):
        oldPATH = os.environ['PATH']
        bindir = str(self.envconfig.envbindir)
        os.environ['PATH'] = os.pathsep.join([bindir, oldPATH])
        return oldPATH

def getdigest(path):
    path = py.path.local(path)
    if not path.check(file=1):
        return "0" * 32
    return path.computehash()

if sys.platform != "win32":
    def find_executable(name):
        return py.path.local.sysfind(name)

else:
    # Exceptions to the usual windows mapping
    win32map = {
            'python': sys.executable,
            'jython': "c:\jython2.5.1\jython.bat",
    }
    def find_executable(name):
        p = py.path.local(name)
        if p.check(file=1):
            return p
        actual = None
        # Is this a standard PythonX.Y name?
        m = re.match(r"python(\d)\.(\d)", name)
        if m:
            # The standard names are in predictable places.
            actual = r"c:\python%s%s\python.exe" % m.groups()
        if not actual:
            actual = win32map.get(name, None)
        if actual:
            actual = py.path.local(actual)
            if actual.check():
                return actual
        # The standard executables can be found as a last resort via the
        # Python launcher py.exe
        if m:
            ver = "-%s.%s" %m.groups()
            script = "import sys; print(sys.executable)"
            py_exe = py.path.local.sysfind('py')
            if py_exe:
                try:
                    exe = py_exe.sysexec(ver, '-c', script).strip()
                except py.process.cmdexec.Error:
                    exe = None
                if exe:
                    exe = py.path.local(exe)
                    if exe.check():
                        return exe
<|endoftext|>


<commit_before>from abc import ABCMeta

from six import with_metaclass

from eventsourcing.application.policies import PersistencePolicy
from eventsourcing.domain.model.entity import VersionedEntity
from eventsourcing.domain.model.events import Logged
from eventsourcing.domain.model.snapshot import Snapshot
from eventsourcing.infrastructure.eventstore import EventStore
from eventsourcing.infrastructure.sequenceditemmapper import SequencedItemMapper
from eventsourcing.utils.transcoding import ObjectJSONDecoder, ObjectJSONEncoder

class ApplicationWithEventStores(with_metaclass(ABCMeta)):
    """
    Event sourced application object class.

    Can construct events stores using given active records.
    Supports three different event stores: for log events,
    for entity events, and for snapshot events.
    """
    def __init__(self, entity_active_record_strategy=None,
                 log_active_record_strategy=None,
                 snapshot_active_record_strategy=None,
                 always_encrypt=False, cipher=None,
                 with_data_integrity=False):

        self.entity_event_store = None
        if entity_active_record_strategy:
            self.entity_event_store = self.construct_event_store(
                event_sequence_id_attr='originator_id',
                event_position_attr='originator_version',
                active_record_strategy=entity_active_record_strategy,
                always_encrypt=always_encrypt,
                cipher=cipher,
                with_data_integrity=with_data_integrity,
            )

        self.log_event_store = None
        if log_active_record_strategy:
            self.log_event_store = self.construct_event_store(
                event_sequence_id_attr='originator_id',
                event_position_attr='timestamp',
                active_record_strategy=log_active_record_strategy,
                always_encrypt=always_encrypt,
                cipher=cipher,
                with_data_integrity=with_data_integrity,
            )

        self.snapshot_event_store = None
        if snapshot_active_record_strategy:
            self.snapshot_event_store = self.construct_event_store(
                event_sequence_id_attr='originator_id',
                event_position_attr='originator_version',
                active_record_strategy=snapshot_active_record_strategy,
                always_encrypt=always_encrypt,
                cipher=cipher,
                with_data_integrity=with_data_integrity,
            )

    def construct_event_store(self, event_sequence_id_attr, event_position_attr, active_record_strategy,
                              always_encrypt=False, cipher=None, with_data_integrity=False):
        sequenced_item_mapper = self.construct_sequenced_item_mapper(
            sequenced_item_class=active_record_strategy.sequenced_item_class,
            event_sequence_id_attr=event_sequence_id_attr,
            event_position_attr=event_position_attr,
            always_encrypt=always_encrypt,
            cipher=cipher,
            with_data_integrity=with_data_integrity,
        )
        event_store = EventStore(
            active_record_strategy=active_record_strategy,
            sequenced_item_mapper=sequenced_item_mapper,
        )
        return event_store

    def construct_sequenced_item_mapper(self, sequenced_item_class, event_sequence_id_attr, event_position_attr,
                                        json_encoder_class=ObjectJSONEncoder, json_decoder_class=ObjectJSONDecoder,
                                        always_encrypt=False, cipher=None, with_data_integrity=False):
        return SequencedItemMapper(
            sequenced_item_class=sequenced_item_class,
            sequence_id_attr_name=event_sequence_id_attr,
            position_attr_name=event_position_attr,
            json_encoder_class=json_encoder_class,
            json_decoder_class=json_decoder_class,
            always_encrypt=always_encrypt,
            cipher=cipher,
            with_data_integrity=with_data_integrity,
        )

    def close(self):
        self.entity_event_store = None
        self.log_event_store = None
        self.snapshot_event_store = None

    def __enter__(self):
        return self

    def __exit__(self, *_):
        self.close()

class ApplicationWithPersistencePolicies(ApplicationWithEventStores):
    def __init__(self, **kwargs):
        super(ApplicationWithPersistencePolicies, self).__init__(**kwargs)
        self.entity_persistence_policy = self.construct_entity_persistence_policy()
        self.snapshot_persistence_policy = self.construct_snapshot_persistence_policy()
        self.log_persistence_policy = self.construct_log_persistence_policy()

    def construct_entity_persistence_policy(self):
        if self.entity_event_store:
            return PersistencePolicy(
                event_store=self.entity_event_store,
                event_type=VersionedEntity.Event,
            )

    def construct_snapshot_persistence_policy(self):
        if self.snapshot_event_store:
            return PersistencePolicy(
                event_store=self.snapshot_event_store,
                event_type=Snapshot,
            )

    def construct_log_persistence_policy(self):
        if self.log_event_store:
            return PersistencePolicy(
                event_store=self.log_event_store,
                event_type=Logged,
            )

    def close(self):
        if self.entity_persistence_policy is not None:
            self.entity_persistence_policy.close()
            self.entity_persistence_policy = None
        if self.snapshot_persistence_policy is not None:
            self.snapshot_persistence_policy.close()
            self.snapshot_persistence_policy = None
        if self.log_persistence_policy is not None:
            self.log_persistence_policy.close()
            self.log_persistence_policy = None
        super(ApplicationWithPersistencePolicies, self).close()
<commit_msg>Fixed typo.<commit_after>from abc import ABCMeta

from six import with_metaclass

from eventsourcing.application.policies import PersistencePolicy
from eventsourcing.domain.model.entity import VersionedEntity
from eventsourcing.domain.model.events import Logged
from eventsourcing.domain.model.snapshot import Snapshot
from eventsourcing.infrastructure.eventstore import EventStore
from eventsourcing.infrastructure.sequenceditemmapper import SequencedItemMapper
from eventsourcing.utils.transcoding import ObjectJSONDecoder, ObjectJSONEncoder

class ApplicationWithEventStores(with_metaclass(ABCMeta)):
    """
    Event sourced application object class.

    Can construct event stores using given active records.
    Supports three different event stores: for log events,
    for entity events, and for snapshot events.
    """
    def __init__(self, entity_active_record_strategy=None,
                 log_active_record_strategy=None,
                 snapshot_active_record_strategy=None,
                 always_encrypt=False, cipher=None,
                 with_data_integrity=False):

        self.entity_event_store = None
        if entity_active_record_strategy:
            self.entity_event_store = self.construct_event_store(
                event_sequence_id_attr='originator_id',
                event_position_attr='originator_version',
                active_record_strategy=entity_active_record_strategy,
                always_encrypt=always_encrypt,
                cipher=cipher,
                with_data_integrity=with_data_integrity,
            )

        self.log_event_store = None
        if log_active_record_strategy:
            self.log_event_store = self.construct_event_store(
                event_sequence_id_attr='originator_id',
                event_position_attr='timestamp',
                active_record_strategy=log_active_record_strategy,
                always_encrypt=always_encrypt,
                cipher=cipher,
                with_data_integrity=with_data_integrity,
            )

        self.snapshot_event_store = None
        if snapshot_active_record_strategy:
            self.snapshot_event_store = self.construct_event_store(
                event_sequence_id_attr='originator_id',
                event_position_attr='originator_version',
                active_record_strategy=snapshot_active_record_strategy,
                always_encrypt=always_encrypt,
                cipher=cipher,
                with_data_integrity=with_data_integrity,
            )

    def construct_event_store(self, event_sequence_id_attr, event_position_attr, active_record_strategy,
                              always_encrypt=False, cipher=None, with_data_integrity=False):
        sequenced_item_mapper = self.construct_sequenced_item_mapper(
            sequenced_item_class=active_record_strategy.sequenced_item_class,
            event_sequence_id_attr=event_sequence_id_attr,
            event_position_attr=event_position_attr,
            always_encrypt=always_encrypt,
            cipher=cipher,
            with_data_integrity=with_data_integrity,
        )
        event_store = EventStore(
            active_record_strategy=active_record_strategy,
            sequenced_item_mapper=sequenced_item_mapper,
        )
        return event_store

    def construct_sequenced_item_mapper(self, sequenced_item_class, event_sequence_id_attr, event_position_attr,
                                        json_encoder_class=ObjectJSONEncoder, json_decoder_class=ObjectJSONDecoder,
                                        always_encrypt=False, cipher=None, with_data_integrity=False):
        return SequencedItemMapper(
            sequenced_item_class=sequenced_item_class,
            sequence_id_attr_name=event_sequence_id_attr,
            position_attr_name=event_position_attr,
            json_encoder_class=json_encoder_class,
            json_decoder_class=json_decoder_class,
            always_encrypt=always_encrypt,
            cipher=cipher,
            with_data_integrity=with_data_integrity,
        )

    def close(self):
        self.entity_event_store = None
        self.log_event_store = None
        self.snapshot_event_store = None

    def __enter__(self):
        return self

    def __exit__(self, *_):
        self.close()

class ApplicationWithPersistencePolicies(ApplicationWithEventStores):
    def __init__(self, **kwargs):
        super(ApplicationWithPersistencePolicies, self).__init__(**kwargs)
        self.entity_persistence_policy = self.construct_entity_persistence_policy()
        self.snapshot_persistence_policy = self.construct_snapshot_persistence_policy()
        self.log_persistence_policy = self.construct_log_persistence_policy()

    def construct_entity_persistence_policy(self):
        if self.entity_event_store:
            return PersistencePolicy(
                event_store=self.entity_event_store,
                event_type=VersionedEntity.Event,
            )

    def construct_snapshot_persistence_policy(self):
        if self.snapshot_event_store:
            return PersistencePolicy(
                event_store=self.snapshot_event_store,
                event_type=Snapshot,
            )

    def construct_log_persistence_policy(self):
        if self.log_event_store:
            return PersistencePolicy(
                event_store=self.log_event_store,
                event_type=Logged,
            )

    def close(self):
        if self.entity_persistence_policy is not None:
            self.entity_persistence_policy.close()
            self.entity_persistence_policy = None
        if self.snapshot_persistence_policy is not None:
            self.snapshot_persistence_policy.close()
            self.snapshot_persistence_policy = None
        if self.log_persistence_policy is not None:
            self.log_persistence_policy.close()
            self.log_persistence_policy = None
        super(ApplicationWithPersistencePolicies, self).close()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# Copyright (C) 2003-2005 Edgewall Software
# Copyright (C) 2003-2004 Jonas Borgström <jonas@edgewall.com>
# Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Jonas Borgström <jonas@edgewall.com>
#         Christopher Lenz <cmlenz@gmx.de>

__all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface',
           'TracError']

class TracError(Exception):
    """Exception base class for errors in Trac."""

    def __init__(self, message, title=None, show_traceback=False):
        Exception.__init__(self, message)
        self.message = message
        self.title = title
        self.show_traceback = show_traceback

class Interface(object):
    """Marker base class for extension point interfaces."""

class ExtensionPoint(property):
    """Marker class for extension points in components."""

    def __init__(self, interface):
        """Create the extension point.

        @param interface: the `Interface` subclass that defines the protocol
            for the extension point
        """
        property.__init__(self, self.extensions)
        self.interface = interface
        self.__doc__ = 'List of components that implement `%s`' % \
                       self.interface.__name__

    def extensions(self, component):
        """Return a list of components that declare to implement the extension
        point interface."""
        extensions = ComponentMeta._registry.get(self.interface, [])
        return filter(None, [component.compmgr[cls] for cls in extensions])

    def __repr__(self):
        """Return a textual representation of the extension point."""
        return '<ExtensionPoint %s>' % self.interface.__name__

class ComponentMeta(type):
    """Meta class for components.

    Takes care of component and extension point registration.
    """
    _components = []
    _registry = {}

    def __new__(cls, name, bases, d):
        """Create the component class."""

        d['_implements'] = _implements[:]
        del _implements[:]

        new_class = type.__new__(cls, name, bases, d)
        if name == 'Component':
            # Don't put the Component base class in the registry
            return new_class

        # Only override __init__ for Components not inheriting ComponentManager
        if True not in [issubclass(x, ComponentManager) for x in bases]:
            # Allow components to have a no-argument initializer so that
            # they don't need to worry about accepting the component manager
            # as argument and invoking the super-class initializer
            init = d.get('__init__')
            if not init:
                # Because we're replacing the initializer, we need to make sure
                # that any inherited initializers are also called.
                for init in [b.__init__._original for b in new_class.mro()
                             if issubclass(b, Component)
                             and '__init__' in b.__dict__]:
                    break
            def maybe_init(self, compmgr, init=init, cls=new_class):
                if cls not in compmgr.components:
                    compmgr.components[cls] = self
                    if init:
                        init(self)
            maybe_init._original = init
            new_class.__init__ = maybe_init

        if d.get('abstract'):
            # Don't put abstract component classes in the registry
            return new_class

        ComponentMeta._components.append(new_class)
        for interface in d.get('_implements', []):
            ComponentMeta._registry.setdefault(interface, []).append(new_class)
        for base in [base for base in bases if hasattr(base, '_implements')]:
            for interface in base._implements:
                ComponentMeta._registry.setdefault(interface, []).append(new_class)

        return new_class

_implements = []

def implements(*interfaces):
    """Can be used in the class definiton of `Component` subclasses to declare
    the extension points that are extended.
    """
    _implements.extend(interfaces)

class Component(object):
    """Base class for components.

    Every component can declare what extension points it provides, as well as
    what extension points of other components it extends.
    """
    __metaclass__ = ComponentMeta

    def __new__(cls, *args, **kwargs):
        """Return an existing instance of the component if it has already been
        activated, otherwise create a new instance.
        """
        # If this component is also the component manager, just invoke that
        if issubclass(cls, ComponentManager):
            self = super(Component, cls).__new__(cls)
            self.compmgr = self
            return self

        # The normal case where the component is not also the component manager
        compmgr = args[0]
        self = compmgr.components.get(cls)
        if self is None:
            self = super(Component, cls).__new__(cls)
            self.compmgr = compmgr
            compmgr.component_activated(self)
        return self

class ComponentManager(object):
    """The component manager keeps a pool of active components."""

    def __init__(self):
        """Initialize the component manager."""
        self.components = {}
        self.enabled = {}
        if isinstance(self, Component):
            self.components[self.__class__] = self

    def __contains__(self, cls):
        """Return wether the given class is in the list of active components."""
        return cls in self.components

    def __getitem__(self, cls):
        """Activate the component instance for the given class, or return the
        existing the instance if the component has already been activated."""
        if cls not in self.enabled:
            self.enabled[cls] = self.is_component_enabled(cls)
        if not self.enabled[cls]:
            return None
        component = self.components.get(cls)
        if not component:
            if cls not in ComponentMeta._components:
                raise TracError, 'Component "%s" not registered' % cls.__name__
            try:
                component = cls(self)
            except TypeError, e:
                raise TracError, 'Unable to instantiate component %r (%s)' \
                                 % (cls, e)
        return component

    def component_activated(self, component):
        """Can be overridden by sub-classes so that special initialization for
        components can be provided.
        """

    def is_component_enabled(self, cls):
        """Can be overridden by sub-classes to veto the activation of a
        component.

        If this method returns False, the component with the given class will
        not be available.
        """
        return True
<commit_msg>Enable subclasses of the `TracError` exception to setup their title on the class level, plus some minor style fixes.<commit_after># -*- coding: utf-8 -*-
#
# Copyright (C) 2003-2005 Edgewall Software
# Copyright (C) 2003-2004 Jonas Borgström <jonas@edgewall.com>
# Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Jonas Borgström <jonas@edgewall.com>
#         Christopher Lenz <cmlenz@gmx.de>

__all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface',
           'TracError']

class TracError(Exception):
    """Exception base class for errors in Trac."""

    title = 'Trac Error'

    def __init__(self, message, title=None, show_traceback=False):
        Exception.__init__(self, message)
        self.message = message
        if title:
            self.title = title
        self.show_traceback = show_traceback

class Interface(object):
    """Marker base class for extension point interfaces."""

class ExtensionPoint(property):
    """Marker class for extension points in components."""

    def __init__(self, interface):
        """Create the extension point.

        @param interface: the `Interface` subclass that defines the protocol
            for the extension point
        """
        property.__init__(self, self.extensions)
        self.interface = interface
        self.__doc__ = 'List of components that implement `%s`' % \
                       self.interface.__name__

    def extensions(self, component):
        """Return a list of components that declare to implement the extension
        point interface."""
        extensions = ComponentMeta._registry.get(self.interface, [])
        return filter(None, [component.compmgr[cls] for cls in extensions])

    def __repr__(self):
        """Return a textual representation of the extension point."""
        return '<ExtensionPoint %s>' % self.interface.__name__

class ComponentMeta(type):
    """Meta class for components.

    Takes care of component and extension point registration.
    """
    _components = []
    _registry = {}

    def __new__(cls, name, bases, d):
        """Create the component class."""

        d['_implements'] = _implements[:]
        del _implements[:]

        new_class = type.__new__(cls, name, bases, d)
        if name == 'Component':
            # Don't put the Component base class in the registry
            return new_class

        # Only override __init__ for Components not inheriting ComponentManager
        if True not in [issubclass(x, ComponentManager) for x in bases]:
            # Allow components to have a no-argument initializer so that
            # they don't need to worry about accepting the component manager
            # as argument and invoking the super-class initializer
            init = d.get('__init__')
            if not init:
                # Because we're replacing the initializer, we need to make sure
                # that any inherited initializers are also called.
                for init in [b.__init__._original for b in new_class.mro()
                             if issubclass(b, Component)
                             and '__init__' in b.__dict__]:
                    break
            def maybe_init(self, compmgr, init=init, cls=new_class):
                if cls not in compmgr.components:
                    compmgr.components[cls] = self
                    if init:
                        init(self)
            maybe_init._original = init
            new_class.__init__ = maybe_init

        if d.get('abstract'):
            # Don't put abstract component classes in the registry
            return new_class

        ComponentMeta._components.append(new_class)
        registry = ComponentMeta._registry
        for interface in d.get('_implements', []):
            registry.setdefault(interface, []).append(new_class)
        for base in [base for base in bases if hasattr(base, '_implements')]:
            for interface in base._implements:
                registry.setdefault(interface, []).append(new_class)

        return new_class

_implements = []

def implements(*interfaces):
    """Can be used in the class definiton of `Component` subclasses to declare
    the extension points that are extended.
    """
    _implements.extend(interfaces)

class Component(object):
    """Base class for components.

    Every component can declare what extension points it provides, as well as
    what extension points of other components it extends.
    """
    __metaclass__ = ComponentMeta

    def __new__(cls, *args, **kwargs):
        """Return an existing instance of the component if it has already been
        activated, otherwise create a new instance.
        """
        # If this component is also the component manager, just invoke that
        if issubclass(cls, ComponentManager):
            self = super(Component, cls).__new__(cls)
            self.compmgr = self
            return self

        # The normal case where the component is not also the component manager
        compmgr = args[0]
        self = compmgr.components.get(cls)
        if self is None:
            self = super(Component, cls).__new__(cls)
            self.compmgr = compmgr
            compmgr.component_activated(self)
        return self

class ComponentManager(object):
    """The component manager keeps a pool of active components."""

    def __init__(self):
        """Initialize the component manager."""
        self.components = {}
        self.enabled = {}
        if isinstance(self, Component):
            self.components[self.__class__] = self

    def __contains__(self, cls):
        """Return wether the given class is in the list of active components."""
        return cls in self.components

    def __getitem__(self, cls):
        """Activate the component instance for the given class, or return the
        existing the instance if the component has already been activated."""
        if cls not in self.enabled:
            self.enabled[cls] = self.is_component_enabled(cls)
        if not self.enabled[cls]:
            return None
        component = self.components.get(cls)
        if not component:
            if cls not in ComponentMeta._components:
                raise TracError('Component "%s" not registered' % cls.__name__)
            try:
                component = cls(self)
            except TypeError, e:
                raise TracError('Unable to instantiate component %r (%s)' %
                                (cls, e))
        return component

    def component_activated(self, component):
        """Can be overridden by sub-classes so that special initialization for
        components can be provided.
        """

    def is_component_enabled(self, cls):
        """Can be overridden by sub-classes to veto the activation of a
        component.

        If this method returns False, the component with the given class will
        not be available.
        """
        return True
<|endoftext|>


<commit_before>from django.contrib.flatpages.models import FlatPage
from django.utils.translation import ugettext_lazy as _

from authority import permissions

class FlatPagePermission(permissions.BasePermission):
    """
    This class contains a bunch of checks:

    1. the default checks 'add_flatpage', 'browse_flatpage',
       'change_flatpage' and 'delete_flatpage'
    2. the custom checks:
        a) 'review_flatpage', which is similar to the default checks
        b) 'top_secret', which is represented by the top_secret method

    You can use those checks in your views directly like:

        def review_flatpage(request, url):
            flatpage = get_object_or_404(url__contains=url)
            check = FlatPagePermission(request.user)
            if check.review_flatpage(obj=flatpage):
                print "yay, you can review this flatpage!"
            return flatpage(request, url)

    Or you can use this permission in your templates like this:

        {% ifhasperm "flatpage_permission.review_flatpage" request.user flatpage %}
            Yes, you are allowed to review flatpage '{{ flatpage }}', aren't you?
        {% else %}
            Nope, sorry. You aren't allowed to review this flatpage.
        {% endifhasperm %}
    """
    model = FlatPage
    label = 'flatpage_permission'
    checks = ('review', 'top_secret')

    def top_secret(self, flatpage=None):
        if flatpage and flatpage.registration_required:
            return self.browse_flatpage(obj=flatpage)
        return False
    #top_secret.verbose_name=_('Is allowed to see top secret flatpages')
<commit_msg>Added an example of the decorator to the docstring of the example view. Fixed verbose name of top_secret permission check of example app.<commit_after>from django.contrib.flatpages.models import FlatPage
from django.utils.translation import ugettext_lazy as _

from authority import permissions

class FlatPagePermission(permissions.BasePermission):
    """
    This class contains a bunch of checks:

    1. the default checks 'add_flatpage', 'browse_flatpage',
       'change_flatpage' and 'delete_flatpage'
    2. the custom checks:
        a) 'review_flatpage', which is similar to the default checks
        b) 'top_secret', which is represented by the top_secret method

    You can use those checks in your views directly like:

        def review_flatpage(request, url):
            flatpage = get_object_or_404(url__contains=url)
            check = FlatPagePermission(request.user)
            if check.review_flatpage(obj=flatpage):
                print "yay, you can review this flatpage!"
            return flatpage(request, url)

    Or the same view using the decorator permission_required:

        @permission_required('flatpage_permission.review_flatpage', ('flatpages.flatpage', 'url__contains'))
        def review_flatpage(request, url):
            print "yay, you can review this flatpage!"
            return flatpage(request, url)

    Or you can use this permission in your templates like this:

        {% ifhasperm "flatpage_permission.review_flatpage" request.user flatpage %}
            Yes, you are allowed to review flatpage '{{ flatpage }}', aren't you?
        {% else %}
            Nope, sorry. You aren't allowed to review this flatpage.
        {% endifhasperm %}
    """
    model = FlatPage
    label = 'flatpage_permission'
    checks = ('review', 'top_secret')

    def top_secret(self, flatpage=None):
        if flatpage and flatpage.registration_required:
            return self.browse_flatpage(obj=flatpage)
        return False
    top_secret.verbose_name=_('Is allowed to see top secret flatpages')
<|endoftext|>


<commit_before>from bs4 import BeautifulSoup
from urllib2 import urlopen
from datetime import datetime
import csv
import sys
import os
import smtplib
import config

## ============================================================================
##                          Configurable Variables
## ============================================================================
# Addresses to which results should be emailed
EMAIL_ADDRESSES = [ "benjamin.hipple@gmail.com",
                  ]

# Search queries to execute
QUERIES = ["bicycle 49cm", "bicycle 50cm"]

# Maximum price; items with no price will still be shown
MAX_PRICE = 1200

# Craigslist search URL
BASE_URL = ('http://newyork.craigslist.org/search/'
            '?sort=rel&areaID=11&subAreaID=&query={0}&catAbb=sss')

# Sender email and password are included from config.py
## ============================================================================

def parseResults(search_term):
    results = []
    search_term = search_term.strip().replace(' ', '+')
    search_url = BASE_URL.format(search_term)
    soup = BeautifulSoup(urlopen(search_url).read())
    rows = soup.find('div', 'content').find_all('p', 'row')
    for row in rows:
        url = 'http://newyork.craigslist.org' + row.a['href']

        price = row.find('span', class_='price') or ""
        if price != "": price = price.get_text()
        create_date = row.find('time').get('datetime')
        title = row.find_all('a')[1].get_text()
        results.append({'url': url, 'price': price, 'create_date': create_date, 'title': title})
    return results

def writeResults(results):
    """Writes list of dictionaries to file."""
    fields = results[0].keys()
    with open('results.csv', 'w') as f:
        dw = csv.DictWriter(f, fieldnames=fields, delimiter='|')
        dw.writer.writerow(dw.fieldnames)
        dw.writerows(results)

def filterToNewPosts(results):
    current_posts = [x['url'] for x in results]
    fields = results[0].keys()
    if not os.path.exists('results.csv'):
        return True

    with open('results.csv', 'r') as f:
        reader = csv.DictReader(f, fieldnames=fields, delimiter='|')
        seen_posts = [row['url'] for row in reader]

    newPosts = filter(lambda post: post['url'] not in seen_posts, results)
    return newPosts

def sendEmail(addr, msg):
    fromaddr = "Craigslist Checker"
    toaddrs = addr
    msg = ("From: {0}\r\nTo: {1}\r\n\r\n{2}").format(fromaddr, toaddrs, msg)
    server = smtplib.SMTP('smtp.gmail.com:587')
    server.starttls()
    server.login(config.email['username'], config.email['password'])
    server.sendmail(fromaddr, toaddrs, msg)
    server.quit()

def formatMsg(results):
    message = "Hey - there are new Craigslist posts!"

    message = message + "\n\n" + "\n".join(map(lambda x: x['title'] + "\n" + x['url'] +
        "\n" + x['price'] + "\n", results))

    return message

def getCurrentTime():
    return datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')

if __name__ == '__main__':

    results = []
    map(lambda term: results.extend(parseResults(term)), QUERIES)
    results = filter(lambda res: res['price'] == "" or int(res['price'][1:]) <= MAX_PRICE, results)
    # Send the SMS message if there are new results
    newPosts = filterToNewPosts(results)
    if len(newPosts):
        message = formatMsg(newPosts)

        print "[{0}] There are new results - sending email message".format(getCurrentTime())
        map(lambda addr: sendEmail(addr, message), EMAIL_ADDRESSES)
        writeResults(results)
    else:
        print "[{0}] No new results - will try again later".format(getCurrentTime())
<commit_msg>Switch search query<commit_after>from bs4 import BeautifulSoup
from urllib2 import urlopen
from datetime import datetime
import csv
import sys
import os
import smtplib
import config

## ============================================================================
##                          Configurable Variables
## ============================================================================
# Addresses to which results should be emailed
EMAIL_ADDRESSES = [ "benjamin.hipple@gmail.com",
                  ]

# Search queries to execute
QUERIES = ["bicycle 60cm"]

# Maximum price; items with no price will still be shown
MAX_PRICE = 1200

# Craigslist search URL
BASE_URL = ('http://newyork.craigslist.org/search/'
            '?sort=rel&areaID=11&subAreaID=&query={0}&catAbb=sss')

# Sender email and password are included from config.py
## ============================================================================

def parseResults(search_term):
    results = []
    search_term = search_term.strip().replace(' ', '+')
    search_url = BASE_URL.format(search_term)
    soup = BeautifulSoup(urlopen(search_url).read())
    rows = soup.find('div', 'content').find_all('p', 'row')
    for row in rows:
        url = 'http://newyork.craigslist.org' + row.a['href']

        price = row.find('span', class_='price') or ""
        if price != "": price = price.get_text()
        create_date = row.find('time').get('datetime')
        title = row.find_all('a')[1].get_text()
        results.append({'url': url, 'price': price, 'create_date': create_date, 'title': title})
    return results

def writeResults(results):
    """Writes list of dictionaries to file."""
    fields = results[0].keys()
    with open('results.csv', 'w') as f:
        dw = csv.DictWriter(f, fieldnames=fields, delimiter='|')
        dw.writer.writerow(dw.fieldnames)
        dw.writerows(results)

def filterToNewPosts(results):
    current_posts = [x['url'] for x in results]
    fields = results[0].keys()
    if not os.path.exists('results.csv'):
        return True

    with open('results.csv', 'r') as f:
        reader = csv.DictReader(f, fieldnames=fields, delimiter='|')
        seen_posts = [row['url'] for row in reader]

    newPosts = filter(lambda post: post['url'] not in seen_posts, results)
    return newPosts

def sendEmail(addr, msg):
    fromaddr = "Craigslist Checker"
    toaddrs = addr
    msg = ("From: {0}\r\nTo: {1}\r\n\r\n{2}").format(fromaddr, toaddrs, msg)
    server = smtplib.SMTP('smtp.gmail.com:587')
    server.starttls()
    server.login(config.email['username'], config.email['password'])
    server.sendmail(fromaddr, toaddrs, msg)
    server.quit()

def formatMsg(results):
    message = "Hey - there are new Craigslist posts!"

    message = message + "\n\n" + "\n".join(map(lambda x: x['title'] + "\n" + x['url'] +
        "\n" + x['price'] + "\n", results))

    return message

def getCurrentTime():
    return datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')

if __name__ == '__main__':

    results = []
    map(lambda term: results.extend(parseResults(term)), QUERIES)
    results = filter(lambda res: res['price'] == "" or int(res['price'][1:]) <= MAX_PRICE, results)
    # Send the SMS message if there are new results
    newPosts = filterToNewPosts(results)
    if len(newPosts):
        message = formatMsg(newPosts)

        print "[{0}] There are new results - sending email message".format(getCurrentTime())
        map(lambda addr: sendEmail(addr, message), EMAIL_ADDRESSES)
        writeResults(results)
    else:
        print "[{0}] No new results - will try again later".format(getCurrentTime())
<|endoftext|>