<commit_before>from math import ceil

from hwt.hdl.operator import isConst
from hwtHls.clk_math import start_clk, end_clk
from hwtHls.codeOps import HlsConst
from hwtHls.hls import Hls

class UnresolvedChild(Exception):
    """
    Exception raised when children should be lazyloaded first
    """
    pass

class TimeConstraintError(Exception):
    """
    Exception raised when it is not possble to satisfy timing constraints
    """
    pass

def child_asap_time(ch):
    if ch.asap_end is None:
        if isinstance(ch, HlsConst):
            return 0
        else:
            raise UnresolvedChild()
    else:
        return ch.asap_end

def parent_alap_time(ch):
    if ch.alap_start is None:
        if isinstance(ch, HlsConst):
            return 0
        else:
            raise UnresolvedChild()
    else:
        return ch.alap_start

def asap_filter_inputs(inputs, realInputs):
    newlyDiscoveredInputs = set()
    # init start times, filter inputs
    for node in inputs:
        if not node.fixed_schedulation and not node.dependsOn:
            node.asap_start = 0.0
            node.asap_end = node.latency_pre + node.latency_post

        for n in node.usedBy:
            if n.fixed_schedulation:
                newlyDiscoveredInputs.update(n)
            else:
                realInputs.add(n)

    if newlyDiscoveredInputs:
        asap_filter_inputs(newlyDiscoveredInputs, realInputs)

def asap(inputs, outputs, clk_period):
    """
    As Soon As Possible scheduler

    :return: maximum schedueled timme, decorate nodes
        with asap_start,end time
    """
    # [TODO] cycle delays/latencies

    maxTime = 0
    unresolved = set()
    asap_filter_inputs(inputs, unresolved)

    # walk from inputs to outputs and decorate nodes with time
    while unresolved:
        nextUnresolved = set()
        for node in unresolved:
            try:
                node_t = max(map(child_asap_time, node.dependsOn))
            except UnresolvedChild:
                # skip this node because we will find it
                # after its dependency will be completed
                # (unresolved children will be resolved and it will
                # run resolution for this node again)
                continue
            else:
                # Remaining time until clock tick
                remaining_time = clk_period - (node_t % clk_period)
                if node.latency_pre > remaining_time:
                    # Operation would exceed clock cycle -> align to clock
                    # rising edge
                    node_t += remaining_time
                    if node.latency_pre + node.latency_post >= clk_period:
                        raise TimeConstraintError(
                            "Impossible scheduling, clk_period too low for ",
                            node.latency_pre, node.latency_post, node)

            node.asap_start = node_t
            node.asap_end = node_t + node.latency_pre
            asap_filter_inputs((node, ), nextUnresolved)

            for prev in node.dependsOn:
                if prev.asap_end is None and isinstance(prev, HlsConst):
                    prev.asap_start = prev.asap_end = node.asap_start

            maxTime = max(maxTime, node.asap_end)

        unresolved = nextUnresolved

    # some of nodes does not have to be discovered because
    # they have no connection to any input
    for node in outputs:
        if node.asap_start is None:
            assert isConst(node.what), node
            node.asap_start = 0
            node.asap_end = 0
            node.what.asap_start = 0
            node.what.asap_end = 0

    return maxTime

def alap_filter_outputs(outputs, realOutputs, minimum_latency):
    newlyDiscovered = set()
    for node in outputs:
        if node.fixed_schedulation:
            assert node.asap_end <= minimum_latency
        elif not node.usedBy:
            node.alap_end = minimum_latency
            node.alap_start = node.alap_end - node.latency_pre

        for n in node.dependsOn:
            if n.fixed_schedulation:
                newlyDiscovered.update(n.dependsOn)
            else:
                realOutputs.add(n)

    if newlyDiscovered:
        asap_filter_inputs(newlyDiscovered, realOutputs)

def alap(outputs, clk_period, minimum_latency):
    """
    As Late As Possible scheduler + remove nodes which are not effecting
    any output

    :param minimum_latency: Minimum hls latency returned by ASAP
    """
    # [TODO] cycle delays/latencies
    unresolved = set()
    alap_filter_outputs(outputs, unresolved, minimum_latency)
    # walk from outputs to inputs and note time
    while unresolved:
        nextUnresolved = set()

        for node in unresolved:
            try:
                if node.usedBy:
                    node_end_t = min(map(parent_alap_time, node.usedBy))
                else:
                    node_end_t = minimum_latency
            except UnresolvedChild:
                # skip this node because we will find it
                # after its dependency will be completed
                # (unresolved children will be resolved and it will
                # run resolution for this node again)
                continue
            else:
                if node.latency_pre != 0:
                    clk_start = start_clk(
                        node_end_t - node.latency_pre, clk_period)
                    clk_end = end_clk(node_end_t, clk_period)

                    if clk_start != clk_end:
                        assert clk_end > clk_start and clk_end - clk_start <= 1, (
                            clk_start, clk_end, node)
                        node_end_t = clk_end * clk_period

            node.alap_end = node_end_t
            node.alap_start = node_end_t - node.latency_pre
            alap_filter_outputs((node, ), nextUnresolved, minimum_latency)
            # nextUnresolved.update(
            #    [n for n in node.dependsOn if not n.fixed_schedulation])

        unresolved = nextUnresolved

class HlsScheduler():
    def __init__(self, parentHls: Hls):
        self.parentHls = parentHls

    def apply_scheduelization_dict(self, sched):
        """
        :pram sched: dict {node: (startTime, endTime)}
        """
        clk_period = self.parentHls.clk_period
        maxTime = max(map(lambda x: x[1], sched.values()))

        if maxTime == 0:
            clk_count = 1
        else:
            clk_count = ceil(maxTime / clk_period)

        # render nodes in clk_periods
        schedulization = [[] for _ in range(clk_count)]
        constants = set()
        for node in self.parentHls.nodes:
            if isinstance(node, HlsConst):
                # constants has time specified by it's user
                constants.add(node)
            else:
                time_start, time_end = sched[node]
                assert (time_start is not None
                        and time_start >= 0
                        and time_start <= time_end), (
                    node, time_start, time_end)

            schedulization[int(time_start * clk_period)].append(node)
            node.scheduledIn = time_start
            node.scheduledInEnd = time_end
            assert node.scheduledIn <= node.scheduledInEnd

        for node in constants:
            time_start, time_end = node.scheduledIn, node.scheduledInEnd
            schedulization[int(time_start * clk_period)].append(node)

        self.schedulization = schedulization

    def schedule(self):
        hls = self.parentHls
        maxTime = asap(hls.inputs, hls.outputs, hls.clk_period)
        alap(hls.outputs, self.parentHls.clk_period, maxTime)
        sched = {n: (n.alap_start, n.alap_end)
                 for n in hls.nodes}

        self.apply_scheduelization_dict(sched)
<commit_msg>optimize asap/alap_filter_inputs<commit_after>from math import ceil

from hwt.hdl.operator import isConst
from hwtHls.clk_math import start_clk, end_clk
from hwtHls.codeOps import HlsConst
from hwtHls.hls import Hls

class UnresolvedChild(Exception):
    """
    Exception raised when children should be lazyloaded first
    """
    pass

class TimeConstraintError(Exception):
    """
    Exception raised when it is not possble to satisfy timing constraints
    """
    pass

def child_asap_time(ch):
    if ch.asap_end is None:
        if isinstance(ch, HlsConst):
            return 0
        else:
            raise UnresolvedChild()
    else:
        return ch.asap_end

def parent_alap_time(ch):
    if ch.alap_start is None:
        if isinstance(ch, HlsConst):
            return 0
        else:
            raise UnresolvedChild()
    else:
        return ch.alap_start

def asap_filter_inputs(inputs, realInputs):
    newlyDiscoveredInputs = set()
    # init start times, filter inputs
    for node in inputs:
        if not node.fixed_schedulation and not node.dependsOn:
            node.asap_start = 0.0
            node.asap_end = node.latency_pre + node.latency_post

        for n in node.usedBy:
            if n.fixed_schedulation:
                newlyDiscoveredInputs.add(n)
            elif n.asap_start is not None:
                continue
            else:
                realInputs.add(n)

    if newlyDiscoveredInputs:
        asap_filter_inputs(newlyDiscoveredInputs, realInputs)

def asap(inputs, outputs, clk_period):
    """
    As Soon As Possible scheduler

    :return: maximum schedueled timme, decorate nodes
        with asap_start,end time
    """
    # [TODO] cycle delays/latencies
    #print("asap")
    maxTime = 0
    unresolved = set()
    asap_filter_inputs(inputs, unresolved)

    # walk from inputs to outputs and decorate nodes with time
    while unresolved:
        nextUnresolved = set()
        for node in unresolved:
            try:
                node_t = max(map(child_asap_time, node.dependsOn))
            except UnresolvedChild:
                # skip this node because we will find it
                # after its dependency will be completed
                # (unresolved children will be resolved and it will
                # run resolution for this node again)
                continue
            else:
                # Remaining time until clock tick
                remaining_time = clk_period - (node_t % clk_period)
                if node.latency_pre > remaining_time:
                    # Operation would exceed clock cycle -> align to clock
                    # rising edge
                    node_t += remaining_time
                    if node.latency_pre + node.latency_post >= clk_period:
                        raise TimeConstraintError(
                            "Impossible scheduling, clk_period too low for ",
                            node.latency_pre, node.latency_post, node)

            assert not node.fixed_schedulation
            node.asap_start = node_t
            node.asap_end = node_t + node.latency_pre
            #print(node.__class__.__name__,
            #      node.asap_start / clk_period, node.asap_end / clk_period)
            asap_filter_inputs((node, ), nextUnresolved)

            for prev in node.dependsOn:
                if prev.asap_end is None and isinstance(prev, HlsConst):
                    prev.asap_start = prev.asap_end = node.asap_start

            maxTime = max(maxTime, node.asap_end)

        unresolved = nextUnresolved

    # some of nodes does not have to be discovered because
    # they have no connection to any input
    for node in outputs:
        if node.asap_start is None:
            assert isConst(node.what), node
            node.asap_start = 0
            node.asap_end = 0
            node.what.asap_start = 0
            node.what.asap_end = 0

    return maxTime

def alap_filter_outputs(outputs, realOutputs, minimum_latency):
    newlyDiscovered = set()
    for node in outputs:
        if node.fixed_schedulation:
            assert node.alap_end <= minimum_latency, (
                node.alap_end, minimum_latency)
        elif not node.usedBy:
            node.alap_end = minimum_latency
            node.alap_start = node.alap_end - node.latency_pre

        for n in node.dependsOn:
            if n.fixed_schedulation:
                newlyDiscovered.add(n)
            elif n.alap_start is not None:
                continue
            else:
                realOutputs.add(n)

    if newlyDiscovered:
        asap_filter_inputs(newlyDiscovered, realOutputs)

def alap(outputs, clk_period, minimum_latency):
    """
    As Late As Possible scheduler + remove nodes which are not effecting
    any output

    :param minimum_latency: Minimum hls latency returned by ASAP
    """
    # print("alap")
    # [TODO] cycle delays/latencies
    unresolved = set()
    # round to end of last cycle
    _minimum_latency = minimum_latency
    minimum_latency = (end_clk(minimum_latency, clk_period) + 1) * clk_period
    # print(_minimum_latency, minimum_latency)
    alap_filter_outputs(outputs, unresolved, minimum_latency)
    # walk from outputs to inputs and note time
    while unresolved:
        nextUnresolved = set()

        for node in unresolved:
            try:
                if node.usedBy:
                    node_end_t = min(map(parent_alap_time, node.usedBy))
                else:
                    node_end_t = minimum_latency
            except UnresolvedChild:
                # skip this node because we will find it
                # after its dependency will be completed
                # (unresolved children will be resolved and it will
                # run resolution for this node again)
                continue
            else:
                if node.latency_pre != 0:
                    clk_start = start_clk(
                        node_end_t - node.latency_pre, clk_period)
                    clk_end = end_clk(node_end_t, clk_period)

                    if clk_start != clk_end:
                        assert clk_end > clk_start and clk_end - clk_start <= 1, (
                            clk_start, clk_end, node)
                        node_end_t = clk_end * clk_period

            assert not node.fixed_schedulation
            node.alap_end = node_end_t
            node.alap_start = node_end_t - node.latency_pre
            # print(node.__class__.__name__,
            #       node.alap_start / clk_period, node.alap_end / clk_period)
            alap_filter_outputs((node, ), nextUnresolved, minimum_latency)

        unresolved = nextUnresolved

class HlsScheduler():
    def __init__(self, parentHls: Hls):
        self.parentHls = parentHls

    def apply_scheduelization_dict(self, sched):
        """
        :pram sched: dict {node: (startTime, endTime)}
        """
        clk_period = self.parentHls.clk_period
        maxTime = max(map(lambda x: x[1], sched.values()))

        if maxTime == 0:
            clk_count = 1
        else:
            clk_count = ceil(maxTime / clk_period)
        # print(clk_count)
        # render nodes in clk_periods
        schedulization = [[] for _ in range(clk_count + 1)]
        constants = set()
        for node in self.parentHls.nodes:
            if isinstance(node, HlsConst):
                # constants has time specified by it's user
                constants.add(node)
            else:
                time_start, time_end = sched[node]
                assert (time_start is not None
                        and time_start >= 0
                        and time_start <= time_end), (
                    node, time_start, time_end)

            clk_index = start_clk(time_start, clk_period)
            # print(clk_index)
            schedulization[clk_index].append(node)
            node.scheduledIn = time_start
            node.scheduledInEnd = time_end
            assert node.scheduledIn <= node.scheduledInEnd

        for node in constants:
            time_start, time_end = node.scheduledIn, node.scheduledInEnd
            clk_index = start_clk(time_start, clk_period)
            schedulization[clk_index].append(node)

        self.schedulization = schedulization

    def schedule(self):
        hls = self.parentHls
        maxTime = asap(hls.inputs, hls.outputs, hls.clk_period)
        alap(hls.outputs, self.parentHls.clk_period, maxTime)
        sched = {n: (n.alap_start, n.alap_end)
                 for n in hls.nodes}

        self.apply_scheduelization_dict(sched)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# coding=utf-8
#   Python Script
#
#   Copyright © Manoel Vilela
#
#

from pygame.locals import K_ESCAPE, KEYDOWN, QUIT
from automaton import Ant, Track
import motion
import pygame
import random
import colors
import grid

FPS = 30

class AntSimulation(object):

    tracks = []
    ants = []

    def __init__(self, width, heigth, fps, n_ants=4):
        self.width = width
        self.heigth = heigth
        self.running = True
        self.fps = fps
        self.n_ants = n_ants
        self.setup()

    def setup(self):
        pygame.init()
        self.screen = pygame.display.set_mode(self.screen_size)
        self.clock = pygame.time.Clock()
        for _ in range(self.n_ants):
            color = random.choice(colors.VISIBLES)
            self.ants.append(Ant(0, 0, color))

    @property
    def screen_size(self):
        return self.width, self.heigth

    def event_handler(self, event):
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            self.running = False
        elif event.type == QUIT:
            self.running = False

    def random_move(self, entity):
        x, y = random.choice(list(motion.DIRECTIONS.values()))

        if all((0 <= entity.x + x < self.width,
                0 <= entity.y + y < self.heigth)):
            entity.move(x, y)
        else:
            self.random_move(entity)

    def draw_ants(self):
        for ant in self.ants:
            if not any([track.collide(ant) for track in self.tracks]):
                track = Track.footprint(ant)
                track.draw(self.screen)
                self.tracks.append(track)
            self.random_move(ant)
            ant.draw(self.screen)

    def draw_tracks(self):
        for track in self.tracks:
            track.draw(self.screen)

    def main_loop(self):
        while self.running:
            for event in pygame.event.get():
                self.event_handler(event)

            self.screen.fill(colors.BLACK)
            self.draw_tracks()
            self.draw_ants()
            pygame.display.flip()
            self.clock.tick(self.fps)

    @classmethod
    def run(cls):
        w, h = grid.GRID_SIZE
        weigth, heigth = w * grid.BLOCKSIZE, h * grid.BLOCKSIZE
        game = cls(weigth, heigth, FPS)
        game.main_loop()
        pygame.quit()
        return game.tracks

if __name__ == '__main__':
    from pprint import pprint
    pprint(sorted(AntSimulation.run(), key=lambda self: (self.x, self.y)))
<commit_msg>Add event K_SPACE to stop for one second and other changes<commit_after>#!/usr/bin/env python
# coding=utf-8
#   Python Script
#
#   Copyright © Manoel Vilela
#
#

from pygame.locals import K_ESCAPE, KEYDOWN, QUIT, K_SPACE
from automaton import Ant, Track
import motion
import pygame
import random
import colors
import grid
import time

FPS = 30

class AntSimulation(object):

    tracks = []
    ants = []

    def __init__(self, width, heigth, fps, n_ants=4):
        self.width = width
        self.heigth = heigth
        self.running = True
        self.fps = fps
        self.n_ants = n_ants
        self.setup()

    def setup(self):
        pygame.init()
        self.screen = pygame.display.set_mode(self.screen_size)
        self.clock = pygame.time.Clock()
        for _ in range(self.n_ants):
            color = random.choice(colors.VISIBLES)
            self.ants.append(Ant(0, 0, color))

    @property
    def screen_size(self):
        return self.width, self.heigth

    def event_handler(self, event):
        if event.type == QUIT:
            self.running = False
        elif event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                self.running = False
            elif event.key == K_SPACE:
                time.sleep(1)

    def random_move(self, entity):
        x, y = random.choice(list(motion.DIRECTIONS.values()))

        moveble = all((0 <= entity.x + x < self.width,
                       0 <= entity.y + y < self.heigth))

        entity.move(x, y) if moveble else self.random_move(entity)

    def draw_ants(self):
        for ant in self.ants:
            if not any([track.collide(ant) for track in self.tracks]):
                track = Track.footprint(ant)
                track.draw(self.screen)
                self.tracks.append(track)
            self.random_move(ant)
            ant.draw(self.screen)

    def update(self):
        pygame.display.flip()

    def draw_tracks(self):
        for track in self.tracks:
            track.draw(self.screen)

    def main_loop(self):
        while self.running:
            for event in pygame.event.get():
                self.event_handler(event)

            self.screen.fill(colors.BLACK)
            self.draw_tracks()
            self.draw_ants()
            self.update()
            self.clock.tick(self.fps)

    @classmethod
    def run(cls):
        w, h = grid.GRID_SIZE
        weigth, heigth = w * grid.BLOCKSIZE, h * grid.BLOCKSIZE
        game = cls(weigth, heigth, FPS)
        game.main_loop()
        pygame.quit()
        return game.tracks

if __name__ == '__main__':
    from pprint import pprint
    pprint(sorted(AntSimulation.run(), key=lambda self: self.position))
<|endoftext|>


<commit_before>'''
Created on May 20, 2014

@author: rd
'''
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2012 Nebula, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from collections import defaultdict

from django.conf import settings
from django.core.urlresolvers import reverse
from django.template import defaultfilters as filters
from django.utils.http import urlencode
from django.utils.translation import ugettext_lazy as _

from horizon import tables
from horizon.utils.memoized import memoized  # noqa

from openstack_dashboard import api
from openstack_dashboard.api import base

from openstack_dashboard.api import glint

import requests,json,logging

NOT_LAUNCHABLE_FORMATS = ['aki', 'ari']

site_data=[]
site_index=0

#logging.basicConfig(filename='hor.log',level=eval('Info'),format='%(asctime)s %(message)s')

class LaunchImage(tables.LinkAction):
    name = "launch_image"
    verbose_name = _("Launch")
    url = "horizon:project:instances:launch"
    classes = ("btn-launch", "ajax-modal")
    policy_rules = (("compute", "compute:create"),)

    def get_link_url(self, datum):
        base_url = reverse(self.url)

        if get_image_type(datum) == "image":
            source_type = "image_id"
        else:
            source_type = "instance_snapshot_id"

        params = urlencode({"source_type": source_type,
                            "source_id": self.table.get_object_id(datum)})
        return "?".join([base_url, params])

    def allowed(self, request, image=None):
        if image and image.container_format not in NOT_LAUNCHABLE_FORMATS:
            return image.status in ("active",)
        return False

class AddCredential(tables.LinkAction):
    #name = "credential"
    #verbose_name = _("Add Credential")
    #url = "horizon:project:images:images:addcredential"
    #classes = ("ajax-modal", "btn-edit")
    #policy_rules = (("credential", "add_credential"),)
    name = "credential"
    verbose_name = _("AddCredential")
    url = "horizon:project:images:images:addcredential"
    classes = ("ajax-modal", "btn-edit")
    policy_rules = (("credential", "add_credential"),)

    def allowed(self,request,repo=None):
        result = glint.get_glint_url_and_token(request)
        attr=dir(repo)
        #print "Should credential be Add and Edit %s repo %s attr:%s"%(result,repo,attr)
        data_json = requests.post("%shascredential/"%result['url'],data={"SITE_ID":repo.id,"USER_ID":request.user,"USER_TOKEN":"%s"%result['token'],"USER_TENANT":request.user.token.tenant['name']},cookies=None).text
        print "Allow the cred button says %s"%data_json
        self.verbose_name = _("AddCredential")
        return True

class DeleteSite(tables.DeleteAction):
    data_type_singular = _("Repository")
    data_type_plural = _("Repository")
    policy_rules = (("site", "delete_site"),)

    def allowed(self, request, site=None):
        # Protected images can not be deleted.
        print("check if delete site is allowed")
        #if site and site.protected:
        #    return False
        #if site:
        #    return site.owner == request.user.tenant_id
        # Return True to allow table-level bulk delete action to appear.
        return True

    def delete(self, request, obj_id):
        print("delete Site %s"%obj_id)
        result = glint.get_glint_url_and_token(request)
        data_json = requests.post("%sdeletesite/"%result['url'],data={"SITE_ID":obj_id,"USER_ID":request.user,"USER_TOKEN":"%s"%result['token'],"USER_TENANT":request.user.token.tenant['name']},cookies=None).text
        #data_obj = json.loads(data_json)
        print "Received back %s"%data_json

class CreateSite(tables.LinkAction):
    name = "create"
    verbose_name = _("Add Repository")
    url = "horizon:project:images:images:createsite"
    classes = ("ajax-modal", "btn-create")
    policy_rules = (("site", "create_site"),)

class EditImage(tables.LinkAction):
    name = "edit"
    verbose_name = _("Edit")
    url = "horizon:project:images:images:update"
    classes = ("ajax-modal", "btn-edit")
    policy_rules = (("image", "modify_image"),)

    def allowed(self, request, image=None):
        #if image:
        ##    return image.status in ("active",) and \
        #        image.owner == request.user.tenant_id
        # We don't have bulk editing, so if there isn't an image that's
        # authorized, don't allow the action.
        return True

class CreateVolumeFromImage(tables.LinkAction):
    name = "create_volume_from_image"
    verbose_name = _("Create Volume")
    url = "horizon:project:volumes:volumes:create"
    classes = ("ajax-modal", "btn-camera")
    policy_rules = (("volume", "volume:create"),)

    def get_link_url(self, datum):
        base_url = reverse(self.url)
        params = urlencode({"image_id": self.table.get_object_id(datum)})
        return "?".join([base_url, params])

    def allowed(self, request, image=None):
        if (image and image.container_format not in NOT_LAUNCHABLE_FORMATS
                and base.is_service_enabled(request, 'volume')):
            return image.status == "active"
        return False

def filter_tenants():
    return getattr(settings, 'IMAGES_LIST_FILTER_TENANTS', [])

@memoized
def filter_tenant_ids():
    return map(lambda ft: ft['tenant'], filter_tenants())

class OwnerFilter(tables.FixedFilterAction):
    def get_fixed_buttons(self):
        def make_dict(text, tenant, icon):
            return dict(text=text, value=tenant, icon=icon)

        buttons = [make_dict(_('Project'), 'project', 'icon-home')]
        for button_dict in filter_tenants():
            new_dict = button_dict.copy()
            new_dict['value'] = new_dict['tenant']
            buttons.append(new_dict)
        buttons.append(make_dict(_('Shared with Me'), 'shared', 'icon-share'))
        buttons.append(make_dict(_('Public'), 'public', 'icon-fire'))
        return buttons

    def categorize(self, table, images):
        user_tenant_id = table.request.user.tenant_id
        tenants = defaultdict(list)
        for im in images:
            categories = get_image_categories(im, user_tenant_id)
            for category in categories:
                tenants[category].append(im)
        return tenants

def get_image_categories(im, user_tenant_id):
    categories = []
    if im.is_public:
        categories.append('public')
    if im.owner == user_tenant_id:
        categories.append('project')
    elif im.owner in filter_tenant_ids():
        categories.append(im.owner)
    elif not im.is_public:
        categories.append('shared')
    return categories

def get_image_name(image):
    return getattr(image, "name", None) or image.id

def get_site_url(site):
    return site.url

def get_site_authport(site):
    return site.authport

def get_site_type(site):
    return site.type

def get_site_name(site):
    #print "site data %s"%site.site_name
    #site_index++
    return site.site_name

def get_image_type(image):
    return getattr(image, "properties", {}).get("image_type", "image")

def get_format(image):
    format = getattr(image, "disk_format", "")
    # The "container_format" attribute can actually be set to None,
    # which will raise an error if you call upper() on it.
    if format is not None:
        return format.upper()

class UpdateSiteRow(tables.Row):
    ajax = True

    def get_data(self, request, site_id):
        #image = api.glance.image_get(request, image_id)
        #print "get site %s"%site_id
        site = site_data[site_id]
        #site_id=site_id+1
        return site

    def load_cells(self, site=None):
        #print "loading %s"%image
        super(UpdateSiteRow, self).load_cells(site)
        # Tag the row with the image category for client-side filtering.
        site = self.datum
       # print "load data"
        #my_tenant_id = self.table.request.user.tenant_id
        #image_categories = get_image_categories(image, my_tenant_id)
        #for category in image_categories:
        #    self.classes.append('category-' + category)

class UpdateRow(tables.Row):
    ajax = True

    def get_data(self, request, image_id):
        image = api.glance.image_get(request, image_id)
        return image

    def load_cells(self, image=None):
        super(UpdateRow, self).load_cells(image)
        # Tag the row with the image category for client-side filtering.
        image = self.datum
        my_tenant_id = self.table.request.user.tenant_id
        image_categories = get_image_categories(image, my_tenant_id)
        for category in image_categories:
            self.classes.append('category-' + category)

class SitesTable(tables.DataTable):
    #STATUS_CHOICES = (
    #    ("active", True),
    #    ("saving", None),
    #    ("queued", None),
    #    ("pending_delete", None),
    #    ("killed", False),
    #    ("deleted", False),
    #)
    name = tables.Column(get_site_name, verbose_name=_("Name"))
    site_url = tables.Column(get_site_url, verbose_name=_("Cloud URL"))
    auth_port = tables.Column(get_site_authport, verbose_name=_("Auth Port"))
    site_type = tables.Column(get_site_type, verbose_name=_("Cloud Type"))
    #status = tables.Column("status",
    #                       filters=(filters.title,),
    #                       verbose_name=_("Status"),
    #                       status=True,
    #                       status_choices=STATUS_CHOICES)
    #public = tables.Column("is_public",
    #                       verbose_name=_("Public"),
    #                       empty_value=False,
    #                       filters=(filters.yesno, filters.capfirst))
    #protected = tables.Column("protected",
    #                          verbose_name=_("Protected"),
    #                          empty_value=False,
    #                          filters=(filters.yesno, filters.capfirst))

    class Meta:
        name = "sites"
        row_class = UpdateSiteRow
        #status_columns = ["status"]
        verbose_name = _("Repositories")
        table_actions = ( CreateSite, DeleteSite )
        row_actions = ( AddCredential,DeleteSite ,  )
        pagination_param = "site_marker"
<commit_msg>modified image dist page<commit_after>'''
Created on May 20, 2014

@author: rd
'''
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2012 Nebula, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from collections import defaultdict

from django.conf import settings
from django.core.urlresolvers import reverse
from django.template import defaultfilters as filters
from django.utils.http import urlencode
from django.utils.translation import ugettext_lazy as _

from horizon import tables
from horizon.utils.memoized import memoized  # noqa

from openstack_dashboard import api
from openstack_dashboard.api import base

from openstack_dashboard.api import glint

import requests,json,logging

NOT_LAUNCHABLE_FORMATS = ['aki', 'ari']

site_data=[]
site_index=0

#logging.basicConfig(filename='hor.log',level=eval('Info'),format='%(asctime)s %(message)s')

class LaunchImage(tables.LinkAction):
    name = "launch_image"
    verbose_name = _("Launch")
    url = "horizon:project:instances:launch"
    classes = ("btn-launch", "ajax-modal")
    policy_rules = (("compute", "compute:create"),)

    def get_link_url(self, datum):
        base_url = reverse(self.url)

        if get_image_type(datum) == "image":
            source_type = "image_id"
        else:
            source_type = "instance_snapshot_id"

        params = urlencode({"source_type": source_type,
                            "source_id": self.table.get_object_id(datum)})
        return "?".join([base_url, params])

    def allowed(self, request, image=None):
        if image and image.container_format not in NOT_LAUNCHABLE_FORMATS:
            return image.status in ("active",)
        return False

class AddCredential(tables.LinkAction):
    #name = "credential"
    #verbose_name = _("Add Credential")
    #url = "horizon:project:images:images:addcredential"
    #classes = ("ajax-modal", "btn-edit")
    #policy_rules = (("credential", "add_credential"),)
    name = "credential"
    verbose_name = _("AddCredential")
    url = "horizon:project:images:images:addcredential"
    classes = ("ajax-modal", "btn-edit")
    policy_rules = (("credential", "add_credential"),)

    def allowed(self,request,repo=None):
        result = glint.get_glint_url_and_token(request)
        #attr=dir(repo)
        print "Should credential be Add and Edit %s repo %s attr:%s"%(result,repo.id)
        data_json = requests.post("%shascredential/"%result['url'],data={"SITE_ID":repo.id,"USER_ID":request.user,"USER_TOKEN":"%s"%result['token'],"USER_TENANT":request.user.token.tenant['name']},cookies=None).text
        print "Allow the cred button says %s"%data_json
        self.verbose_name = _("AddCredential")
        return True

class DeleteSite(tables.DeleteAction):
    data_type_singular = _("Repository")
    data_type_plural = _("Repository")
    policy_rules = (("site", "delete_site"),)

    def allowed(self, request, site=None):
        # Protected images can not be deleted.
        print("check if delete site is allowed")
        #if site and site.protected:
        #    return False
        #if site:
        #    return site.owner == request.user.tenant_id
        # Return True to allow table-level bulk delete action to appear.
        return True

    def delete(self, request, obj_id):
        print("delete Site %s"%obj_id)
        result = glint.get_glint_url_and_token(request)
        data_json = requests.post("%sdeletesite/"%result['url'],data={"SITE_ID":obj_id,"USER_ID":request.user,"USER_TOKEN":"%s"%result['token'],"USER_TENANT":request.user.token.tenant['name']},cookies=None).text
        #data_obj = json.loads(data_json)
        print "Received back %s"%data_json

class CreateSite(tables.LinkAction):
    name = "create"
    verbose_name = _("Add Repository")
    url = "horizon:project:images:images:createsite"
    classes = ("ajax-modal", "btn-create")
    policy_rules = (("site", "create_site"),)

class EditImage(tables.LinkAction):
    name = "edit"
    verbose_name = _("Edit")
    url = "horizon:project:images:images:update"
    classes = ("ajax-modal", "btn-edit")
    policy_rules = (("image", "modify_image"),)

    def allowed(self, request, image=None):
        #if image:
        ##    return image.status in ("active",) and \
        #        image.owner == request.user.tenant_id
        # We don't have bulk editing, so if there isn't an image that's
        # authorized, don't allow the action.
        return True

class CreateVolumeFromImage(tables.LinkAction):
    name = "create_volume_from_image"
    verbose_name = _("Create Volume")
    url = "horizon:project:volumes:volumes:create"
    classes = ("ajax-modal", "btn-camera")
    policy_rules = (("volume", "volume:create"),)

    def get_link_url(self, datum):
        base_url = reverse(self.url)
        params = urlencode({"image_id": self.table.get_object_id(datum)})
        return "?".join([base_url, params])

    def allowed(self, request, image=None):
        if (image and image.container_format not in NOT_LAUNCHABLE_FORMATS
                and base.is_service_enabled(request, 'volume')):
            return image.status == "active"
        return False

def filter_tenants():
    return getattr(settings, 'IMAGES_LIST_FILTER_TENANTS', [])

@memoized
def filter_tenant_ids():
    return map(lambda ft: ft['tenant'], filter_tenants())

class OwnerFilter(tables.FixedFilterAction):
    def get_fixed_buttons(self):
        def make_dict(text, tenant, icon):
            return dict(text=text, value=tenant, icon=icon)

        buttons = [make_dict(_('Project'), 'project', 'icon-home')]
        for button_dict in filter_tenants():
            new_dict = button_dict.copy()
            new_dict['value'] = new_dict['tenant']
            buttons.append(new_dict)
        buttons.append(make_dict(_('Shared with Me'), 'shared', 'icon-share'))
        buttons.append(make_dict(_('Public'), 'public', 'icon-fire'))
        return buttons

    def categorize(self, table, images):
        user_tenant_id = table.request.user.tenant_id
        tenants = defaultdict(list)
        for im in images:
            categories = get_image_categories(im, user_tenant_id)
            for category in categories:
                tenants[category].append(im)
        return tenants

def get_image_categories(im, user_tenant_id):
    categories = []
    if im.is_public:
        categories.append('public')
    if im.owner == user_tenant_id:
        categories.append('project')
    elif im.owner in filter_tenant_ids():
        categories.append(im.owner)
    elif not im.is_public:
        categories.append('shared')
    return categories

def get_image_name(image):
    return getattr(image, "name", None) or image.id

def get_site_url(site):
    return site.url

def get_site_authport(site):
    return site.authport

def get_site_type(site):
    return site.type

def get_site_name(site):
    #print "site data %s"%site.site_name
    #site_index++
    return site.site_name

def get_image_type(image):
    return getattr(image, "properties", {}).get("image_type", "image")

def get_format(image):
    format = getattr(image, "disk_format", "")
    # The "container_format" attribute can actually be set to None,
    # which will raise an error if you call upper() on it.
    if format is not None:
        return format.upper()

class UpdateSiteRow(tables.Row):
    ajax = True

    def get_data(self, request, site_id):
        #image = api.glance.image_get(request, image_id)
        #print "get site %s"%site_id
        site = site_data[site_id]
        #site_id=site_id+1
        return site

    def load_cells(self, site=None):
        #print "loading %s"%image
        super(UpdateSiteRow, self).load_cells(site)
        # Tag the row with the image category for client-side filtering.
        site = self.datum
       # print "load data"
        #my_tenant_id = self.table.request.user.tenant_id
        #image_categories = get_image_categories(image, my_tenant_id)
        #for category in image_categories:
        #    self.classes.append('category-' + category)

class UpdateRow(tables.Row):
    ajax = True

    def get_data(self, request, image_id):
        image = api.glance.image_get(request, image_id)
        return image

    def load_cells(self, image=None):
        super(UpdateRow, self).load_cells(image)
        # Tag the row with the image category for client-side filtering.
        image = self.datum
        my_tenant_id = self.table.request.user.tenant_id
        image_categories = get_image_categories(image, my_tenant_id)
        for category in image_categories:
            self.classes.append('category-' + category)

class SitesTable(tables.DataTable):
    #STATUS_CHOICES = (
    #    ("active", True),
    #    ("saving", None),
    #    ("queued", None),
    #    ("pending_delete", None),
    #    ("killed", False),
    #    ("deleted", False),
    #)
    name = tables.Column(get_site_name, verbose_name=_("Name"))
    site_url = tables.Column(get_site_url, verbose_name=_("Cloud URL"))
    auth_port = tables.Column(get_site_authport, verbose_name=_("Auth Port"))
    site_type = tables.Column(get_site_type, verbose_name=_("Cloud Type"))
    #status = tables.Column("status",
    #                       filters=(filters.title,),
    #                       verbose_name=_("Status"),
    #                       status=True,
    #                       status_choices=STATUS_CHOICES)
    #public = tables.Column("is_public",
    #                       verbose_name=_("Public"),
    #                       empty_value=False,
    #                       filters=(filters.yesno, filters.capfirst))
    #protected = tables.Column("protected",
    #                          verbose_name=_("Protected"),
    #                          empty_value=False,
    #                          filters=(filters.yesno, filters.capfirst))

    class Meta:
        name = "sites"
        row_class = UpdateSiteRow
        #status_columns = ["status"]
        verbose_name = _("Repositories")
        table_actions = ( CreateSite, DeleteSite )
        row_actions = ( AddCredential,DeleteSite ,  )
        pagination_param = "site_marker"
<|endoftext|>


<commit_before>from datetime import datetime
import json

from freezegun import freeze_time

from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test.utils import override_settings
from django.utils import timezone

from bulbs.content.models import Tag
from bulbs.utils.test import BaseIndexableTestCase, make_content

from example.testcontent.models import TestContentObj

@override_settings(BETTY_IMAGE_URL='http://images.onionstatic.com/onion')
class GlanceFeedTestCase(BaseIndexableTestCase):

    maxDiff = None  # Show full diffs on error

    def get_feed(self, status_code=200, *args, **kwargs):
        TestContentObj.search_objects.refresh()
        resp = Client().get(reverse('glance-feed'), kwargs, SERVER_NAME='www.theonion.com')
        self.assertEqual(status_code, resp.status_code)
        if resp.status_code == 200:
            self.assertEqual('application/json', resp['content-type'])
            return json.loads(resp.content.decode('utf-8'))

    def test_empty(self):
        resp = self.get_feed()
        self.assertEqual(resp, {'count': 0,
                                'next': None,
                                'previous': None,
                                'results': []})

    @freeze_time('2016-5-3 10:11:12')
    def test_single_item(self):
        content = make_content(TestContentObj,
                               id=52852,
                               title='The Pros And Cons Of Taking A Gap Year',
                               published=datetime(2016, 5, 2, 14, 43, 0, tzinfo=timezone.utc),
                               thumbnail_override=53338)
        for name in ['College', 'Technology']:
            content.tags.add(Tag.objects.create(name=name))
        content.save()

        resp = self.get_feed()
        self.assertEqual(
            resp,
            {
                'count': 1,
                'next': None,
                'previous': None,
                'results': [{
                    'type': 'post',
                    'id': 52852,
                    'title': 'The Pros And Cons Of Taking A Gap Year',
                    'link': 'http://www.theonion.com/detail/52852/',
                    'modified': '2016-05-03T10:11:12+00:00',
                    'published': '2016-05-02T14:43:00+00:00',
                    'slug': 'the-pros-and-cons-of-taking-a-gap-year',
                    'featured_media': {
                        'type': 'image',
                        'image': 'http://images.onionstatic.com/onion/5333/8/16x9/600.jpg',
                        'markup': ''
                    },
                    'authors': ["America's Finest News Source"],
                    'tags': {
                        'section': ['College', 'Technology']
                    }
                }]
            })

    def test_pagination(self):
        make_content(TestContentObj,
                     published=datetime(2016, 5, 2, 14, 43, 0, tzinfo=timezone.utc),
                     _quantity=11)

        resp = self.get_feed(page=1, page_size=5)
        self.assertEqual(11, resp['count'])
        self.assertEqual(5, len(resp['results']))

        resp = self.get_feed(page=2, page_size=5)
        self.assertEqual(5, len(resp['results']))

        resp = self.get_feed(page=3, page_size=5)
        self.assertEqual(1, len(resp['results']))

    def test_pagination_bounds_404(self):
        # One page past last should trigger 404
        make_content(TestContentObj,
                     published=datetime(2016, 5, 2, 14, 43, 0, tzinfo=timezone.utc))
        self.get_feed(page=2, page_size=1, status_code=404)

    def test_sort_last_modified(self):
        now = timezone.now()
        content = make_content(TestContentObj, published=now, _quantity=5)
        # Stagger "last_modified" (an "auto_now" field)
        for c, offset in zip(content, [0, 4, 1, 3, 2]):
            with freeze_time(now - timezone.timedelta(hours=offset)):
                c.save()

        resp = self.get_feed()
        self.assertEqual([content[i].id for i in [0, 2, 4, 3, 1]],
                         [c['id'] for c in resp['results']])

    def test_filter_published(self):
        content = make_content(TestContentObj, published=None)
        self.assertEqual(0, self.get_feed()['count'])
        content.published = timezone.now() - timezone.timedelta(hours=1)
        content.save()
        self.assertEqual(1, self.get_feed()['count'])
<commit_msg>Fix flaky test<commit_after>from datetime import datetime
import json

from freezegun import freeze_time

from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test.utils import override_settings
from django.utils import timezone

from bulbs.content.models import Tag
from bulbs.utils.test import BaseIndexableTestCase, make_content

from example.testcontent.models import TestContentObj

@override_settings(BETTY_IMAGE_URL='http://images.onionstatic.com/onion')
class GlanceFeedTestCase(BaseIndexableTestCase):

    maxDiff = None  # Show full diffs on error

    def get_feed(self, status_code=200, *args, **kwargs):
        TestContentObj.search_objects.refresh()
        resp = Client().get(reverse('glance-feed'), kwargs, SERVER_NAME='www.theonion.com')
        self.assertEqual(status_code, resp.status_code)
        if resp.status_code == 200:
            self.assertEqual('application/json', resp['content-type'])
            return json.loads(resp.content.decode('utf-8'))

    def test_empty(self):
        resp = self.get_feed()
        self.assertEqual(resp, {'count': 0,
                                'next': None,
                                'previous': None,
                                'results': []})

    @freeze_time('2016-5-3 10:11:12')
    def test_single_item(self):
        content = make_content(TestContentObj,
                               id=52852,
                               title='The Pros And Cons Of Taking A Gap Year',
                               published=datetime(2016, 5, 2, 14, 43, 0, tzinfo=timezone.utc),
                               thumbnail_override=53338)
        for name in ['College', 'Technology']:
            content.tags.add(Tag.objects.create(name=name))
        content.save()

        resp = self.get_feed()
        self.assertEqual(
            resp,
            {
                'count': 1,
                'next': None,
                'previous': None,
                'results': [{
                    'type': 'post',
                    'id': 52852,
                    'title': 'The Pros And Cons Of Taking A Gap Year',
                    'link': 'http://www.theonion.com/detail/52852/',
                    'modified': '2016-05-03T10:11:12+00:00',
                    'published': '2016-05-02T14:43:00+00:00',
                    'slug': 'the-pros-and-cons-of-taking-a-gap-year',
                    'featured_media': {
                        'type': 'image',
                        'image': 'http://images.onionstatic.com/onion/5333/8/16x9/600.jpg',
                        'markup': ''
                    },
                    'authors': ["America's Finest News Source"],
                    'tags': {
                        'section': ['College', 'Technology']
                    }
                }]
            })

    def test_pagination(self):
        make_content(TestContentObj,
                     published=datetime(2016, 5, 2, 14, 43, 0, tzinfo=timezone.utc),
                     _quantity=11)

        resp = self.get_feed(page=1, page_size=5)
        self.assertEqual(11, resp['count'])
        self.assertEqual(5, len(resp['results']))

        resp = self.get_feed(page=2, page_size=5)
        self.assertEqual(5, len(resp['results']))

        resp = self.get_feed(page=3, page_size=5)
        self.assertEqual(1, len(resp['results']))

    def test_pagination_bounds_404(self):
        # One page past last should trigger 404
        make_content(TestContentObj,
                     published=datetime(2016, 5, 2, 14, 43, 0, tzinfo=timezone.utc))
        self.get_feed(page=2, page_size=1, status_code=404)

    def test_sort_last_modified(self):
        now = timezone.now()
        content = make_content(TestContentObj,
                               published=now - timezone.timedelta(hours=1),
                               _quantity=5)
        # Stagger "last_modified" (an "auto_now" field)
        for c, offset in zip(content, [0, 4, 1, 3, 2]):
            with freeze_time(now - timezone.timedelta(hours=offset)):
                c.save()

        resp = self.get_feed()
        self.assertEqual([content[i].id for i in [0, 2, 4, 3, 1]],
                         [c['id'] for c in resp['results']])

    def test_filter_published(self):
        content = make_content(TestContentObj, published=None)
        self.assertEqual(0, self.get_feed()['count'])
        content.published = timezone.now() - timezone.timedelta(hours=1)
        content.save()
        self.assertEqual(1, self.get_feed()['count'])
<|endoftext|>


<commit_before>#! /usr/bin/env python

import time
import smact
import itertools
from sys import stdout

from smact.screening import pauling_test
from multiprocessing import Pool

element_list = smact.ordered_elements(1, 103)
elements = smact.element_dictionary(element_list)

max_n = 4
neutral_stoichiometries_threshold = 8
pauling_test_threshold = 0.0

# Number of times to report progress during the counting loop.

count_progress_interval = 100

# Parameters for the threaded version of the code.

mp_use = True
mp_processes = 4
mp_chunk_size = 10

def print_status(text):
    "Refresh progress meter on one line"
    stdout.write(text + '\r')
    stdout.flush()

def count_iter(iterator):
    """Efficiently count number of items in an iterator"""
    return sum(1 for _ in iterator)

def count_element_combination(args):
    """Count the oxidation state combinations for a given set of elements.

    The arguments are grouped together into a single tuple. This allows use
    with the mapping functions of the multiprocessing.Pool class.

    The format of the tuple should be:
    (element_combination, n, neutral_stoichs_lookup)
    where element_combination is a tuple of smact.Element objects,
    n is the number of species to be included in a compound (e.g. n=3 for
    AxByCz materials), neutral_stoichs_lookup is a dictionary of
    the number of permitted neutral stoichiometry combinations given a sorted
    list of oxidation states.

    """
    element_combination, n, neutral_stoichs_lookup = args

    count = 0

    # Create a list of all the unique ionic species,
    # each represented as (symbol, state, eneg)
    oxidation_states_list = [
        (element.symbol, oxidation_state, element.pauling_eneg)
            for element in element_combination
                for oxidation_state in element.oxidation_states
        ]

    for state_combination in itertools.combinations(oxidation_states_list, n):
        symbols = [x[0] for x in state_combination]
        oxidation_states = [x[1] for x in state_combination]
        pauling_electronegativities = [x[2] for x in state_combination]

        if pauling_test(symbols, oxidation_states, pauling_electronegativities,
                        threshold=pauling_test_threshold,
                        repeat_anions=True, repeat_cations=True):
            count += neutral_stoichs_lookup[tuple(sorted(oxidation_states))]

    return count

def main():
    """
    Count element combinations which satisfy charge neutrality and Pauling
    electronegativity constraints.
    """

    # Obtain the unique oxidation states across all the elements considered.
    oxidation_states = set(
        oxidation_state for element in elements.values()
            for oxidation_state in element.oxidation_states
        )

    # List unique oxidation-state combinations for each set of
    # n-element combinations
    oxidation_state_combinations = {
        n: list(itertools.combinations_with_replacement(oxidation_states, n))
            for n in range(2, max_n + 1)
    }

    # Sort combinations and cast to tuples --
    # these will be used as keys to a lookup table below.
    oxidation_state_combinations = {
        key: [tuple(sorted(item)) for item in value]
            for key, value in oxidation_state_combinations.items()
        }

    # Print the number of combinations of oxidation states for each value
    # of n to be analysed. Note that this will include ridiculous combinations
    # such as (+1, +2, +1)
    print "Combinations of known oxidation states:"

    for i in range(2, max_n + 1):
        print "m = {0}: {1}".format(i, len(oxidation_state_combinations[i]))

    print ""

    # Initialise a thread pool for multi-threaded calculations if required
    thread_pool = Pool(processes=mp_processes) if mp_use else None

    for n in range(2, max_n + 1):
        # Build lookup table with the number of charge-neutral stoichiometries
        # for each combination of oxidation-states.
        # Uses the tuples in oxidation_state_combinations as keys.
        # For combinations where all the states are positive or negative, the
        # number will be zero.

        # This code is rather ugly, consisting of nested functions inside a
        #  list comprehension. This is done in order to minimise memory access
        # but is equivalent to:
        #
        # neutral_stoichiometries = {}
        # for oxidation_states in oxidation_state_combinations[n]:
        #     count = count_iter(smact.neutral_ratios_iter(oxidation_states,
        #                        threshold=neutral_stoichiometries_threshold))
        #     neutral_stoichiometries.update({oxidation_states: count})

        neutral_stoichiometries = {
            oxidation_states: count_iter(smact.neutral_ratios_iter(
                oxidation_states, threshold=neutral_stoichiometries_threshold))
                for oxidation_states in oxidation_state_combinations[n]
            }

        start_time = time.time()

        # Count the number of element combinations - this is needed for the
        # progress indicator.

        combination_count = sum(
            count_iter(itertools.combinations(element_list, i))
            for i in range(2, n + 1))

        print("Counting ({0} element combinations)"
              "...".format(combination_count))

        # Combinations are counted in chunks set by count_progress_interval.
        # In Python 2.7 the // symbol is "integer division" which rounds
        # downwards to the nearest integer.

        batch_size = combination_count // count_progress_interval
        data_pointer = 0

        # Set up a generator expression to return combinations of elements.
        # Generators are evaluated lazily in Python, which avoids keeping all
        # the combinations in memory - doing so can require quite a lot for
        # large n (~300 Mb for quaternaries).  To count the combinations in
        # chunks, a second generator expression is used in the while loop
        # (below) which calls next() on the generator the required number of
        # times.  As well as keeping memory usage fairly constant, this seems
        # to carry little, if any, CPU overhead compared to creating and
        # slicing a list.  So, it's perhaps a bit "filthy", but...

        combination_generator = (
            [elements[symbol] for symbol in element_combination]
            for i in range(2, n + 1)
            for element_combination in itertools.combinations(element_list, i))

        # Count and sum charge-neutral combinations of oxidation states for
        # each of the combinations in element_combinations.

        count = 0

        while data_pointer < combination_count:
            iterations = min(batch_size, combination_count - data_pointer)

            imap_arg_generator = ((next(combination_generator),
                                   n, neutral_stoichiometries)
                                  for i in range(0, iterations))

            if mp_use:
                # Threaded code path -- iteration over element combinations is
                # done using the multiprocessing.Pool.imap_unordered()
                # function.

                count = count + sum(thread_pool.imap_unordered(
                                        count_element_combination,
                                        imap_arg_generator,
                                        chunksize=mp_chunk_size))
            else:
                # Serial code path -- iteration over element combinations is
                # done using the itertools.imap() function.

                count = count + sum(itertools.imap(count_element_combination,
                                                   imap_arg_generator))

            # After each chunk, report the % progress, elapsed time and an
            # estimate of the remaining time.  The smact.pauling_test() calls
            # take a variable amount of time, so the estimate of the remaining
            # time is not always accurate, particularly for the first few
            # cycles.

            data_pointer = data_pointer + iterations

            percent_done = 100 * float(data_pointer) / float(combination_count)

            time_elapsed = time.time() - start_time
            time_remaining = (combination_count * (time_elapsed / data_pointer)
                              - time_elapsed)

            print_status("  -> {0}/{1} done ({2:.2f} %); {3:.2f} s elapsed, "
                         "~{4:.2f} s remaining".format(data_pointer,
                                                       combination_count,
                                                       percent_done,
                                                       time_elapsed,
                                                       time_remaining))

        print ""

        total_time = time.time() - start_time

        # Print results and total time for counting.

        print("Number of charge-neutral stoichiometries for combinations "
              "of {0} elements".format(n))
        print("(using known oxidation states, not including zero): "
              "{0}".format(count))
        print ""

        print "Total time for counting: {0:.3f} sec".format(total_time)
        print ""

if __name__ == '__main__':
    main()
<commit_msg>fix mixed_ions_on_MP-v2.py<commit_after>#! /usr/bin/env python

import time
import smact
import itertools
from sys import stdout

from smact.screening import pauling_test
from multiprocessing import Pool

element_list = smact.ordered_elements(1, 103)
elements = smact.element_dictionary(element_list)

max_n = 4
neutral_stoichiometries_threshold = 8
pauling_test_threshold = 0.0

# Number of times to report progress during the counting loop.

count_progress_interval = 100

# Parameters for the threaded version of the code.

mp_use = True
mp_processes = 4
mp_chunk_size = 10

def print_status(text):
    "Refresh progress meter on one line"
    stdout.write(text + '\r')
    stdout.flush()

def count_iter(iterator):
    """Efficiently count number of items in an iterator"""
    return sum(1 for _ in iterator)

def count_element_combination(args):
    """Count the oxidation state combinations for a given set of elements.

    The arguments are grouped together into a single tuple. This allows use
    with the mapping functions of the multiprocessing.Pool class.

    The format of the tuple should be:
    (element_combination, n, neutral_stoichs_lookup)
    where element_combination is a tuple of smact.Element objects,
    n is the number of species to be included in a compound (e.g. n=3 for
    AxByCz materials), neutral_stoichs_lookup is a dictionary of
    the number of permitted neutral stoichiometry combinations given a sorted
    list of oxidation states.

    """
    element_combination, n, neutral_stoichs_lookup = args

    count = 0

    # Create a list of all the unique ionic species,
    # each represented as (symbol, state, eneg)
    oxidation_states_list = [
        (element.symbol, oxidation_state, element.pauling_eneg)
            for element in element_combination
                for oxidation_state in element.oxidation_states
        ]

    for state_combination in itertools.combinations(oxidation_states_list, n):
        symbols = [x[0] for x in state_combination]
        oxidation_states = [x[1] for x in state_combination]
        pauling_electronegativities = [x[2] for x in state_combination]

        if pauling_test(oxidation_states, pauling_electronegativities, symbols = symbols,
                        threshold=pauling_test_threshold,
                        repeat_anions=True, repeat_cations=True):
            count += neutral_stoichs_lookup[tuple(sorted(oxidation_states))]
    return count

def main():
    """
    Count element combinations which satisfy charge neutrality and Pauling
    electronegativity constraints.
    """

    # Obtain the unique oxidation states across all the elements considered.
    oxidation_states = set(
        oxidation_state for element in elements.values()
            for oxidation_state in element.oxidation_states
        )

    # List unique oxidation-state combinations for each set of
    # n-element combinations
    oxidation_state_combinations = {
        n: list(itertools.combinations_with_replacement(oxidation_states, n))
            for n in range(2, max_n + 1)
    }

    # Sort combinations and cast to tuples --
    # these will be used as keys to a lookup table below.
    oxidation_state_combinations = {
        key: [tuple(sorted(item)) for item in value]
            for key, value in oxidation_state_combinations.items()
        }

    # Print the number of combinations of oxidation states for each value
    # of n to be analysed. Note that this will include ridiculous combinations
    # such as (+1, +2, +1)
    print "Combinations of known oxidation states:"

    for i in range(2, max_n + 1):
        print "m = {0}: {1}".format(i, len(oxidation_state_combinations[i]))

    print ""

    # Initialise a thread pool for multi-threaded calculations if required
    thread_pool = Pool(processes=mp_processes) if mp_use else None

    for n in range(2, max_n + 1):
        # Build lookup table with the number of charge-neutral stoichiometries
        # for each combination of oxidation-states.
        # Uses the tuples in oxidation_state_combinations as keys.
        # For combinations where all the states are positive or negative, the
        # number will be zero.

        # This code is rather ugly, consisting of nested functions inside a
        #  list comprehension. This is done in order to minimise memory access
        # but is equivalent to:
        #
        # neutral_stoichiometries = {}
        # for oxidation_states in oxidation_state_combinations[n]:
        #     count = count_iter(smact.neutral_ratios_iter(oxidation_states,
        #                        threshold=neutral_stoichiometries_threshold))
        #     neutral_stoichiometries.update({oxidation_states: count})

        neutral_stoichiometries = {
            oxidation_states: count_iter(smact.neutral_ratios_iter(
                oxidation_states, threshold=neutral_stoichiometries_threshold))
                for oxidation_states in oxidation_state_combinations[n]
            }

        start_time = time.time()

        # Count the number of element combinations - this is needed for the
        # progress indicator.

        combination_count = sum(
            count_iter(itertools.combinations(element_list, i))
            for i in range(2, n + 1))

        print("Counting ({0} element combinations)"
              "...".format(combination_count))

        # Combinations are counted in chunks set by count_progress_interval.
        # In Python 2.7 the // symbol is "integer division" which rounds
        # downwards to the nearest integer.

        batch_size = combination_count // count_progress_interval
        data_pointer = 0

        # Set up a generator expression to return combinations of elements.
        # Generators are evaluated lazily in Python, which avoids keeping all
        # the combinations in memory - doing so can require quite a lot for
        # large n (~300 Mb for quaternaries).  To count the combinations in
        # chunks, a second generator expression is used in the while loop
        # (below) which calls next() on the generator the required number of
        # times.  As well as keeping memory usage fairly constant, this seems
        # to carry little, if any, CPU overhead compared to creating and
        # slicing a list.  So, it's perhaps a bit "filthy", but...

        combination_generator = (
            [elements[symbol] for symbol in element_combination]
            for i in range(2, n + 1)
            for element_combination in itertools.combinations(element_list, i))

        # Count and sum charge-neutral combinations of oxidation states for
        # each of the combinations in element_combinations.

        count = 0

        while data_pointer < combination_count:
            iterations = min(batch_size, combination_count - data_pointer)

            imap_arg_generator = ((next(combination_generator),
                                   n, neutral_stoichiometries)
                                  for i in range(0, iterations))

            if mp_use:
                # Threaded code path -- iteration over element combinations is
                # done using the multiprocessing.Pool.imap_unordered()
                # function.

                count = count + sum(thread_pool.imap_unordered(
                                        count_element_combination,
                                        imap_arg_generator,
                                        chunksize=mp_chunk_size))
            else:
                # Serial code path -- iteration over element combinations is
                # done using the itertools.imap() function.

                count = count + sum(itertools.imap(count_element_combination,
                                                   imap_arg_generator))

            # After each chunk, report the % progress, elapsed time and an
            # estimate of the remaining time.  The smact.pauling_test() calls
            # take a variable amount of time, so the estimate of the remaining
            # time is not always accurate, particularly for the first few
            # cycles.

            data_pointer = data_pointer + iterations

            percent_done = 100 * float(data_pointer) / float(combination_count)

            time_elapsed = time.time() - start_time
            time_remaining = (combination_count * (time_elapsed / data_pointer)
                              - time_elapsed)

            print_status("  -> {0}/{1} done ({2:.2f} %); {3:.2f} s elapsed, "
                         "~{4:.2f} s remaining".format(data_pointer,
                                                       combination_count,
                                                       percent_done,
                                                       time_elapsed,
                                                       time_remaining))

        print ""

        total_time = time.time() - start_time

        # Print results and total time for counting.

        print("Number of charge-neutral stoichiometries for combinations "
              "of {0} elements".format(n))
        print("(using known oxidation states, not including zero): "
              "{0}".format(count))
        print ""

        print "Total time for counting: {0:.3f} sec".format(total_time)
        print ""

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>"""
Multiple linear regression
==========================

_thumb: .45, .45
"""
import seaborn as sns
sns.set()

# Load the example tips dataset
iris = sns.load_dataset("iris")

# Plot tip as a function of toal bill across days
g = sns.lmplot(x="sepal_length", y="sepal_width", hue="species",
               truncate=True, size=5, data=iris)

# Use more informative axis labels than are provided by default
g.set_axis_labels("Sepal length (mm)", "Sepal width (mm)")
<commit_msg>update comments in regression example<commit_after>"""
Multiple linear regression
==========================

_thumb: .45, .45
"""
import seaborn as sns
sns.set()

# Load the iris dataset
iris = sns.load_dataset("iris")

# Plot sepal with as a function of sepal_length across days
g = sns.lmplot(x="sepal_length", y="sepal_width", hue="species",
               truncate=True, size=5, data=iris)

# Use more informative axis labels than are provided by default
g.set_axis_labels("Sepal length (mm)", "Sepal width (mm)")
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: UTF-8 -*-
__author__ = "Alexandre D'Hondt"
__version__ = "1.0"
__copyright__ = "AGPLv3 (http://www.gnu.org/licenses/agpl.html)"
__training__ = "ZSIS CTF - Trivia - Shining (4 points)"
__doc__ = """
This tool allows to recursively decompress an archive according to various
 formats relying on many Linux decompression tools.
"""

import glob
import shutil
from subprocess import check_output, PIPE
from tinyscript import *

TMP_DIR = ".tmp"

def decompress(f):
    logger.info("Decompressing '{}'...".format(f))
    ft = check_output(['file', f]).split(':', 1)[1].strip()
    logger.debug(ft)
    if ft.startswith("bzip2 compressed data"):
        old = set(os.listdir("."))
        _ = check_output(["bzip2", "-df", f], stderr=PIPE)
        return False, list(set(os.listdir(".")) - old)[0]
    elif ft.startswith("POSIX tar archive"):
        return False, check_output(["tar", "-xvf", f]).strip()
    elif ft.startswith("RAR archive data"):
        return False, check_output(["unrar", "e", f], stderr=PIPE) \
               .split("Extracting  ", 1)[1].split("        ", 1)[0].strip()
    elif ft.startswith("XZ compressed data"):
        if not f.endswith(".xz"):
            shutil.move(f, f + ".xz")
        _ = check_output(["unxz", "-df", f + ".xz"], stderr=PIPE)
        return False, f
    elif ft.startswith("ARJ archive data"):
        if not f.endswith(".arj"):
            shutil.move(f, f + ".arj")
        return False, check_output(["arj", "e", f + ".arj"], \
                stderr=PIPE).split("Extracting ", 1)[1].split("   ", 1)[0].strip()
    elif ft.startswith("LZMA compressed data"):
        if not f.endswith(".lzma"):
            shutil.move(f, f + ".lzma")
        _ = check_output(["lzma", "-df", f + ".lzma"], stderr=PIPE)
        return False, f
    elif ft.startswith("gzip compressed data"):
        if not f.endswith(".gz"):
            shutil.move(f, f + ".gz")
        _ = check_output(["gunzip", "-df", f + ".gz"], stderr=PIPE)
        return False, f
    elif ft.startswith("7-zip archive data"):
        if not f.endswith(".7z"):
            shutil.move(f, f + ".7z")
        old = set(os.listdir("."))
        _ = check_output(["7za", "e", f + ".7z", "-y"], stderr=PIPE)
        return False, list(set(os.listdir(".")) - old)[0]
    logger.warn("Nothing more to decompress")
    return True, f

if __name__ == '__main__':
    parser.add_argument("archive", help="input archive")
    initialize(globals())
    os.makedirs(TMP_DIR)
    shutil.copy(args.archive, os.path.join(TMP_DIR, args.archive))
    _ = os.getcwd()
    os.chdir(TMP_DIR)
    stop, f = False, args.archive
    while not stop:
        stop, f = decompress(f)
    os.chdir(_)
    shutil.move(os.path.join(TMP_DIR, f), ".")
    shutil.rmtree(TMP_DIR)
<commit_msg>Updated example nested-decompressor<commit_after>#!/usr/bin/env python
# -*- coding: UTF-8 -*-
__author__ = "Alexandre D'Hondt"
__version__ = "1.2"
__copyright__ = "AGPLv3 (http://www.gnu.org/licenses/agpl.html)"
__training__ = "ZSIS CTF - Trivia - Shining (4 points)"
__doc__ = """
This tool allows to recursively decompress an archive, using multiple Linux decompression
 tools. It currently supports the following tools:
- bzip2
- tar
- unrar
- unxz
- arj
- lzma
- gunzip
- 7za
- unzip
"""
__examples__ = ["test.zip"]

# --------------------- IMPORTS SECTION ---------------------
import shutil
from collections import deque
from subprocess import check_output, PIPE
from tinyscript import *

# -------------------- FUNCTIONS SECTION --------------------
def _log_filetype(filename, magic=None):
    try:
        file_out = check_output(['file', filename]).strip()
        logger.debug(filename if magic is None else \
                     "{} ({})".format(file_out, magic))
    except:
        pass

def decompress(filename):
    logger.info("Decompressing '{}'...".format(filename))
    ft = check_output(['file', filename]).split(':', 1)[1].strip()
    logger.debug(ft)
    if ft.startswith("bzip2 compressed data"):
        old = set(os.listdir("."))
        _ = check_output(["bzip2", "-df", filename], stderr=PIPE)
        return list(set(os.listdir(".")) - old)[0]
    elif ft.startswith("POSIX tar archive"):
        return check_output(["tar", "-xvf", filename]).strip()
    elif ft.startswith("RAR archive data"):
        return check_output(["unrar", "e", filename], stderr=PIPE) \
               .split("Extracting  ", 1)[1].split("        ", 1)[0].strip()
    elif ft.startswith("XZ compressed data"):
        if not filename.endswith(".xz"):
            shutil.move(filename, filename + ".xz")
        _ = check_output(["unxz", "-df", filename + ".xz"], stderr=PIPE)
        return filename
    elif ft.startswith("ARJ archive data"):
        if not filename.endswith(".arj"):
            shutil.move(filename, filename + ".arj")
        return check_output(["arj", "e", filename + ".arj"], stderr=PIPE) \
               .split("Extracting ", 1)[1].split("   ", 1)[0].strip()
    elif ft.startswith("LZMA compressed data"):
        if not filename.endswith(".lzma"):
            shutil.move(filename, filename + ".lzma")
        _ = check_output(["lzma", "-df", filename + ".lzma"], stderr=PIPE)
        return filename
    elif ft.startswith("gzip compressed data"):
        if not filename.endswith(".gz"):
            shutil.move(filename, filename + ".gz")
        _ = check_output(["gunzip", "-df", filename + ".gz"], stderr=PIPE)
        return filename
    elif ft.startswith("7-zip archive data"):
        if not filename.endswith(".7z"):
            shutil.move(filename, filename + ".7z")
        old = set(os.listdir("."))
        _ = check_output(["7za", "e", filename + ".7z"], stderr=PIPE)
        return list(set(os.listdir(".")) - old)[0]
    elif ft.startswith("Zip archive data"):
        if not filename.endswith(".zip"):
            shutil.move(filename, filename + ".zip")
        _ = check_output(["unzip", filename], stderr=PIPE)
        for l in _.split('\n'):
            if "extracting" in l:
                return l.split("extracting:", 1)[1].strip()
    logger.warn("Nothing more to decompress")

# ---------------------- MAIN SECTION -----------------------
if __name__ == '__main__':
    parser.add_argument("archive", help="input archive")
    initialize(globals())
    filename = args.archive
    cleanup = deque([], 2)
    # start recursively decompressing the archive
    while True:
        filename = decompress(filename)
        if filename is None:
            try:  # do not cleanup last decompressed file
                cleanup.pop()
            except:
                pass
            break
        cleanup.append(filename)
        if len(cleanup) == 2:
            os.remove(cleanup.popleft())
    # remove all remaining files
    for i in range(len(cleanup)):
        os.remove(cleanup.pop())
<|endoftext|>


<commit_before>import warnings

from cached_property import cached_property

# Create your models here.
from django.db.models import Prefetch
from django_extensions.db.models import TimeStampedModel
from django.utils.translation import ugettext_lazy as _

from django.db import models
from feder.cases.models import Case
from feder.records.registry import record_type_registry

class RecordQuerySet(models.QuerySet):
    def with_select_related_content(self):
        """
        Returns data using joins. Up to one query.
        :return: models.QuerySet
        """
        fields = [
            field.name
            for field in Record._meta.related_objects
            if issubclass(field.related_model, AbstractRecord)
        ]
        return self.select_related(*fields)

    def with_prefetch_related_content(self):
        """
        Returns data using prefetch. As many queries as different data types.
        :return:
        """
        fields = [
            field.related_name
            for field in Record._meta.related_objects
            if issubclass(field.related_model, AbstractRecord)
        ]
        return self.prefetch_related(*fields)

    def with_author(self):
        from feder.letters.models import Letter

        letter_queryset = Letter.objects.with_author().with_attachment().all()
        return self.prefetch_related(
            Prefetch(lookup="letters_letter_related", queryset=letter_queryset)
        ).all()

    def for_milestone(self):
        from feder.letters.models import Letter

        letter_queryset = Letter.objects.for_milestone().all()
        qs = self.exclude(letters_letters__is_spam=Letter.SPAM.spam)
        return qs.prefetch_related(
            Prefetch(lookup="letters_letter_related", queryset=letter_queryset)
        ).all()

    def for_api(self):
        from feder.letters.models import Letter

        letter_queryset = Letter.objects.for_api().all()
        qs = self.exclude(letters_letters__is_spam=Letter.SPAM.spam)
        return qs.prefetch_related(
            Prefetch(lookup="letters_letter_related", queryset=letter_queryset)
        ).all()

class Record(TimeStampedModel):
    case = models.ForeignKey(Case, on_delete=models.CASCADE, null=True)
    objects = RecordQuerySet.as_manager()

    @cached_property
    def content_object(self):
        for field in Record._meta.related_objects:
            if issubclass(field.related_model, AbstractRecord) and hasattr(
                self, field.related_name
            ):
                return getattr(self, field.related_name)

    @property
    def milestone_template(self):
        warnings.warn(
            "Call to deprecated method '{}.content_template'.".format(
                self.__class__.__name__
            ),
            category=DeprecationWarning,
            stacklevel=2,
        )
        return self.type.get_template_milestone_item(self.content_object)

    @property
    def content_template(self):
        return self.type.get_template_content_item(self.content_object)

    def content_type_name(self):
        if self.content_object:
            return self.content_object._meta.model_name

    @property
    def type(self):
        return record_type_registry.get_type(self.content_object)

    class Meta:
        verbose_name = _("Record")
        verbose_name_plural = _("Records")
        ordering = ["created"]

class AbstractRecord(TimeStampedModel):
    record = models.OneToOneField(
        Record,
        on_delete=models.CASCADE,
        related_name="%(app_label)s_%(class)s_related",
        related_query_name="%(app_label)s_%(class)ss",
    )

    @property
    def case(self):
        return self.record.case

    @case.setter
    def case(self, value):
        self.record.case = value

    class Meta:
        abstract = True
        ordering = ["created"]
<commit_msg>Add missing RecordQuerySet.for_user<commit_after>import warnings

from cached_property import cached_property

# Create your models here.
from django.db.models import Prefetch
from django_extensions.db.models import TimeStampedModel
from django.utils.translation import ugettext_lazy as _

from django.db import models
from feder.cases.models import Case
from feder.records.registry import record_type_registry
from feder.cases.models import enforce_quarantined_queryset

class RecordQuerySet(models.QuerySet):
    def with_select_related_content(self):
        """
        Returns data using joins. Up to one query.
        :return: models.QuerySet
        """
        fields = [
            field.name
            for field in Record._meta.related_objects
            if issubclass(field.related_model, AbstractRecord)
        ]
        return self.select_related(*fields)

    def with_prefetch_related_content(self):
        """
        Returns data using prefetch. As many queries as different data types.
        :return:
        """
        fields = [
            field.related_name
            for field in Record._meta.related_objects
            if issubclass(field.related_model, AbstractRecord)
        ]
        return self.prefetch_related(*fields)

    def with_author(self):
        from feder.letters.models import Letter

        letter_queryset = Letter.objects.with_author().with_attachment().all()
        return self.prefetch_related(
            Prefetch(lookup="letters_letter_related", queryset=letter_queryset)
        ).all()

    def for_milestone(self):
        from feder.letters.models import Letter

        letter_queryset = Letter.objects.for_milestone().all()
        qs = self.exclude(letters_letters__is_spam=Letter.SPAM.spam)
        return qs.prefetch_related(
            Prefetch(lookup="letters_letter_related", queryset=letter_queryset)
        ).all()

    def for_api(self):
        from feder.letters.models import Letter

        letter_queryset = Letter.objects.for_api().all()
        qs = self.exclude(letters_letters__is_spam=Letter.SPAM.spam)
        return qs.prefetch_related(
            Prefetch(lookup="letters_letter_related", queryset=letter_queryset)
        ).all()

    def for_user(self, user):
        return enforce_quarantined_queryset(self, user, "case")

class Record(TimeStampedModel):
    case = models.ForeignKey(Case, on_delete=models.CASCADE, null=True)
    objects = RecordQuerySet.as_manager()

    @cached_property
    def content_object(self):
        for field in Record._meta.related_objects:
            if issubclass(field.related_model, AbstractRecord) and hasattr(
                self, field.related_name
            ):
                return getattr(self, field.related_name)

    @property
    def milestone_template(self):
        warnings.warn(
            "Call to deprecated method '{}.content_template'.".format(
                self.__class__.__name__
            ),
            category=DeprecationWarning,
            stacklevel=2,
        )
        return self.type.get_template_milestone_item(self.content_object)

    @property
    def content_template(self):
        return self.type.get_template_content_item(self.content_object)

    def content_type_name(self):
        if self.content_object:
            return self.content_object._meta.model_name

    @property
    def type(self):
        return record_type_registry.get_type(self.content_object)

    class Meta:
        verbose_name = _("Record")
        verbose_name_plural = _("Records")
        ordering = ["created"]

class AbstractRecord(TimeStampedModel):
    record = models.OneToOneField(
        Record,
        on_delete=models.CASCADE,
        related_name="%(app_label)s_%(class)s_related",
        related_query_name="%(app_label)s_%(class)ss",
    )

    @property
    def case(self):
        return self.record.case

    @case.setter
    def case(self, value):
        self.record.case = value

    class Meta:
        abstract = True
        ordering = ["created"]
<|endoftext|>