<commit_before># everything shall start from 0
import itertools
import json
import logging
import multiprocessing
import pprint
import numpy as np
import matplotlib.pyplot as plt
from os import path, environ
from collections import deque
from functools import partial

# Goddam python logger
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setFormatter(
    logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s'))
logger.setLevel(logging.DEBUG)
logger.addHandler(handler)
logger.propagate = False

pp = pprint.PrettyPrinter(indent=2)

plt.rcParams['toolbar'] = 'None'  # mute matplotlib toolbar
plotters = {}  # hash of matplotlib objects for live-plot

PROBLEMS = json.loads(open(
    path.join(path.dirname(__file__), 'assets', 'problems.json')).read())

# the keys need to be implemented by a sys_var
# the constants (capitalized) are problem configs,
# set in assets/problems.json
required_sys_keys = {
    'RENDER',
    'GYM_ENV_NAME',
    'SOLVED_MEAN_REWARD',
    'MAX_STEPS',
    'MAX_EPISODES',
    'MAX_HISTORY',
    'epi',
    'history',
    'mean_rewards',
    'solved'
}

def init_sys_vars(problem_name='CartPole-v0'):
    '''
    init the sys vars for a problem by reading from
    assets/problems.json, then reset the other sys vars
    on reset will add vars: {epi, history, mean_rewards, solved}
    '''
    sys_vars = PROBLEMS[problem_name]
    if environ.get('CI'):
        sys_vars['RENDER'] = False
        sys_vars['MAX_EPISODES'] = 2
    reset_sys_vars(sys_vars)
    init_plotter(sys_vars)
    return sys_vars

def reset_sys_vars(sys_vars):
    '''reset and check RL system vars before each new session'''
    sys_vars['epi'] = 0
    sys_vars['history'] = deque(maxlen=sys_vars.get('MAX_HISTORY'))
    sys_vars['mean_rewards'] = 0
    sys_vars['solved'] = False
    check_sys_vars(sys_vars)
    return sys_vars

def check_sys_vars(sys_vars):
    '''ensure the requried RL system vars are specified'''
    sys_keys = sys_vars.keys()
    assert all(k in sys_keys for k in required_sys_keys)

def get_env_spec(env):
    '''Helper: return the env specs: dims, actions, reward range'''
    return {
        'state_dim': env.observation_space.shape[0],
        'state_bounds': np.transpose(
            [env.observation_space.low, env.observation_space.high]),
        'action_dim': env.action_space.n,
        'actions': list(range(env.action_space.n)),
        'reward_range': env.reward_range
    }

def report_speed(real_time, total_t):
    '''Report on how fast each time step runs'''
    avg_speed = float(real_time)/float(total_t)
    logger.info('Mean speed: {:.4f} s/step'.format(avg_speed))

def update_history(sys_vars,
                   total_t,
                   total_rewards):
    '''
    update the hisory (list of total rewards)
    max len = MAX_HISTORY
    then report status
    '''
    # Perhaps something up with the way append happens and queue is at capacity
    # Simple fix: Removing earliest item first if queue at capacity
    if (len(sys_vars['history']) == sys_vars.get('MAX_HISTORY')):
        sys_vars['history'].popleft()
    sys_vars['history'].append(total_rewards)
    mean_rewards = np.mean(sys_vars['history'])
    solved = (mean_rewards >= sys_vars['SOLVED_MEAN_REWARD'])
    sys_vars['mean_rewards'] = mean_rewards
    sys_vars['solved'] = solved
    live_plot(sys_vars)

    logs = [
        '',
        'Episode: {}, total t: {}, total reward: {}'.format(
            sys_vars['epi'], total_t, total_rewards),
        'Mean rewards over last {} episodes: {:.4f}'.format(
            sys_vars['MAX_HISTORY'], mean_rewards),
        '{:->20}'.format(''),
    ]
    logger.info('\n'.join(logs))
    if solved or (sys_vars['epi'] == sys_vars['MAX_EPISODES'] - 1):
        logger.info('Problem solved? {}'.format(solved))
    return sys_vars

def init_plotter(sys_vars):
    # initialize the plotters
    fig = plt.figure(facecolor='white')

    ax1 = fig.add_subplot(211,
                          frame_on=False,
                          title='total rewards per episode',
                          ylabel='total rewards')
    p1, = ax1.plot([], [])
    plotters['total rewards'] = (ax1, p1)

    ax2 = fig.add_subplot(212,
                          frame_on=False,
                          title='mean rewards over last 100 episodes',
                          ylabel='mean rewards')
    p2, = ax2.plot([], [])
    plotters['mean rewards'] = (ax2, p2)

    plt.ion()  # for live plot

def live_plot(sys_vars):
    '''do live plotting'''
    if not sys_vars['RENDER']:
        return
    ax1, p1 = plotters['total rewards']
    p1.set_xdata(np.arange(len(p1.get_xdata()) + 1))
    p1.set_ydata(np.append(p1.get_ydata(), sys_vars['history'][-1]))
    ax1.relim()
    ax1.autoscale_view(tight=True, scalex=True, scaley=True)

    ax2, p2 = plotters['mean rewards']
    p2.set_xdata(np.arange(len(p2.get_xdata()) + 1))
    p2.set_ydata(np.append(p2.get_ydata(), sys_vars['mean_rewards']))
    ax2.relim()
    ax2.autoscale_view(tight=True, scalex=True, scaley=True)

    plt.draw()
    plt.pause(0.01)

# convert a dict of param ranges into
# a list of cartesian products of param_range
# e.g. {'a': [1,2], 'b': [3]} into
# [{'a': 1, 'b': 3}, {'a': 2, 'b': 3}]
def param_product(param_range):
    keys = param_range.keys()
    range_vals = param_range.values()
    return [dict(zip(keys, vals)) for vals in itertools.product(*range_vals)]

# advanced, experimental code for parallelization
def run_session_average(run_session, sys_vars, param={}):
    '''
    executes the defined run_session function with sys_vars
    run session multiple times for a param
    then average the mean_rewards from them
    '''
    SESSIONS_PER_PARAM = 10
    logger.info(
        'Running average session with param = {}'.format(pp.pformat(param)))
    mean_rewards_history = []
    for i in range(SESSIONS_PER_PARAM):
        run_session(param)
        mean_rewards_history.append(sys_vars['mean_rewards'])
        sessions_mean_rewards = np.mean(mean_rewards_history)
        if sys_vars['solved']:
            break
    logger.info(
        'Sessions mean rewards: {}'.format(sessions_mean_rewards))
    return {'param': param, 'sessions_mean_rewards': sessions_mean_rewards}

def select_best_param(run_session, sys_vars, param_grid):
    '''
    Parameter selection
    by running session average for each param parallel
    executes the defined run_session function with sys_vars
    then sort by highest sessions_mean_rewards first
    return the best
    '''
    NUM_CORES = multiprocessing.cpu_count()
    p = multiprocessing.Pool(NUM_CORES)
    params_means = p.map(
        partial(run_session_average, run_session, sys_vars),
        param_grid)
    params_means.sort(key=lambda pm: pm['sessions_mean_rewards'], reverse=True)
    for pm in params_means:
        logger.debug(pp.pformat(pm))
    return params_means[0]
<commit_msg>hail satan, I mean, turtle, to fix break matplotlib on linux<commit_after># everything shall start from 0
import itertools
import json
import logging
import multiprocessing
import pprint
import turtle  # fix for ubuntu tkinter bug of matplotlib
import numpy as np
import matplotlib.pyplot as plt
from os import path, environ
from collections import deque
from functools import partial

# Goddam python logger
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setFormatter(
    logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s'))
logger.setLevel(logging.DEBUG)
logger.addHandler(handler)
logger.propagate = False

pp = pprint.PrettyPrinter(indent=2)

plt.rcParams['toolbar'] = 'None'  # mute matplotlib toolbar
plotters = {}  # hash of matplotlib objects for live-plot

PROBLEMS = json.loads(open(
    path.join(path.dirname(__file__), 'assets', 'problems.json')).read())

# the keys need to be implemented by a sys_var
# the constants (capitalized) are problem configs,
# set in assets/problems.json
required_sys_keys = {
    'RENDER',
    'GYM_ENV_NAME',
    'SOLVED_MEAN_REWARD',
    'MAX_STEPS',
    'MAX_EPISODES',
    'MAX_HISTORY',
    'epi',
    'history',
    'mean_rewards',
    'solved'
}

def init_sys_vars(problem_name='CartPole-v0'):
    '''
    init the sys vars for a problem by reading from
    assets/problems.json, then reset the other sys vars
    on reset will add vars: {epi, history, mean_rewards, solved}
    '''
    sys_vars = PROBLEMS[problem_name]
    if environ.get('CI'):
        sys_vars['RENDER'] = False
        sys_vars['MAX_EPISODES'] = 2
    reset_sys_vars(sys_vars)
    init_plotter(sys_vars)
    return sys_vars

def reset_sys_vars(sys_vars):
    '''reset and check RL system vars before each new session'''
    sys_vars['epi'] = 0
    sys_vars['history'] = deque(maxlen=sys_vars.get('MAX_HISTORY'))
    sys_vars['mean_rewards'] = 0
    sys_vars['solved'] = False
    check_sys_vars(sys_vars)
    return sys_vars

def check_sys_vars(sys_vars):
    '''ensure the requried RL system vars are specified'''
    sys_keys = sys_vars.keys()
    assert all(k in sys_keys for k in required_sys_keys)

def get_env_spec(env):
    '''Helper: return the env specs: dims, actions, reward range'''
    return {
        'state_dim': env.observation_space.shape[0],
        'state_bounds': np.transpose(
            [env.observation_space.low, env.observation_space.high]),
        'action_dim': env.action_space.n,
        'actions': list(range(env.action_space.n)),
        'reward_range': env.reward_range
    }

def report_speed(real_time, total_t):
    '''Report on how fast each time step runs'''
    avg_speed = float(real_time)/float(total_t)
    logger.info('Mean speed: {:.4f} s/step'.format(avg_speed))

def update_history(sys_vars,
                   total_t,
                   total_rewards):
    '''
    update the hisory (list of total rewards)
    max len = MAX_HISTORY
    then report status
    '''
    # Perhaps something up with the way append happens and queue is at capacity
    # Simple fix: Removing earliest item first if queue at capacity
    if (len(sys_vars['history']) == sys_vars.get('MAX_HISTORY')):
        sys_vars['history'].popleft()
    sys_vars['history'].append(total_rewards)
    mean_rewards = np.mean(sys_vars['history'])
    solved = (mean_rewards >= sys_vars['SOLVED_MEAN_REWARD'])
    sys_vars['mean_rewards'] = mean_rewards
    sys_vars['solved'] = solved
    live_plot(sys_vars)

    logs = [
        '',
        'Episode: {}, total t: {}, total reward: {}'.format(
            sys_vars['epi'], total_t, total_rewards),
        'Mean rewards over last {} episodes: {:.4f}'.format(
            sys_vars['MAX_HISTORY'], mean_rewards),
        '{:->20}'.format(''),
    ]
    logger.info('\n'.join(logs))
    if solved or (sys_vars['epi'] == sys_vars['MAX_EPISODES'] - 1):
        logger.info('Problem solved? {}'.format(solved))
    return sys_vars

def init_plotter(sys_vars):
    # initialize the plotters
    fig = plt.figure(facecolor='white')

    ax1 = fig.add_subplot(211,
                          frame_on=False,
                          title='total rewards per episode',
                          ylabel='total rewards')
    p1, = ax1.plot([], [])
    plotters['total rewards'] = (ax1, p1)

    ax2 = fig.add_subplot(212,
                          frame_on=False,
                          title='mean rewards over last 100 episodes',
                          ylabel='mean rewards')
    p2, = ax2.plot([], [])
    plotters['mean rewards'] = (ax2, p2)

    plt.ion()  # for live plot

def live_plot(sys_vars):
    '''do live plotting'''
    if not sys_vars['RENDER']:
        return
    ax1, p1 = plotters['total rewards']
    p1.set_xdata(np.arange(len(p1.get_xdata()) + 1))
    p1.set_ydata(np.append(p1.get_ydata(), sys_vars['history'][-1]))
    ax1.relim()
    ax1.autoscale_view(tight=True, scalex=True, scaley=True)

    ax2, p2 = plotters['mean rewards']
    p2.set_xdata(np.arange(len(p2.get_xdata()) + 1))
    p2.set_ydata(np.append(p2.get_ydata(), sys_vars['mean_rewards']))
    ax2.relim()
    ax2.autoscale_view(tight=True, scalex=True, scaley=True)

    plt.draw()
    plt.pause(0.01)

# convert a dict of param ranges into
# a list of cartesian products of param_range
# e.g. {'a': [1,2], 'b': [3]} into
# [{'a': 1, 'b': 3}, {'a': 2, 'b': 3}]
def param_product(param_range):
    keys = param_range.keys()
    range_vals = param_range.values()
    return [dict(zip(keys, vals)) for vals in itertools.product(*range_vals)]

# advanced, experimental code for parallelization
def run_session_average(run_session, sys_vars, param={}):
    '''
    executes the defined run_session function with sys_vars
    run session multiple times for a param
    then average the mean_rewards from them
    '''
    SESSIONS_PER_PARAM = 10
    logger.info(
        'Running average session with param = {}'.format(pp.pformat(param)))
    mean_rewards_history = []
    for i in range(SESSIONS_PER_PARAM):
        run_session(param)
        mean_rewards_history.append(sys_vars['mean_rewards'])
        sessions_mean_rewards = np.mean(mean_rewards_history)
        if sys_vars['solved']:
            break
    logger.info(
        'Sessions mean rewards: {}'.format(sessions_mean_rewards))
    return {'param': param, 'sessions_mean_rewards': sessions_mean_rewards}

def select_best_param(run_session, sys_vars, param_grid):
    '''
    Parameter selection
    by running session average for each param parallel
    executes the defined run_session function with sys_vars
    then sort by highest sessions_mean_rewards first
    return the best
    '''
    NUM_CORES = multiprocessing.cpu_count()
    p = multiprocessing.Pool(NUM_CORES)
    params_means = p.map(
        partial(run_session_average, run_session, sys_vars),
        param_grid)
    params_means.sort(key=lambda pm: pm['sessions_mean_rewards'], reverse=True)
    for pm in params_means:
        logger.debug(pp.pformat(pm))
    return params_means[0]
<|endoftext|>


<commit_before>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from numpy.testing import assert_approx_equal, assert_allclose, assert_array_less
from nose.tools import raises, assert_true, assert_equal
from UliEngineering.Physics.NTC import *
from UliEngineering.Exceptions import *
import functools
import numpy as np

class TestNTC(object):
    def test_ntc_resistance(self):
        # Values arbitrarily from Murata NCP15WB473D03RC
        assert_approx_equal(ntc_resistance("47k", "4050K", "25°C"), 47000)
        assert_approx_equal(ntc_resistance("47k", "4050K", "0°C"), 162942.79)
        assert_approx_equal(ntc_resistance("47k", "4050K", "5°C"), 124819.66)
        assert_approx_equal(ntc_resistance("47k", "4050K", "60°C"), 11280)
<commit_msg>Fix wrong unit test value<commit_after>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from numpy.testing import assert_approx_equal, assert_allclose, assert_array_less
from nose.tools import raises, assert_true, assert_equal
from UliEngineering.Physics.NTC import *
from UliEngineering.Exceptions import *
import functools
import numpy as np

class TestNTC(object):
    def test_ntc_resistance(self):
        # Values arbitrarily from Murata NCP15WB473D03RC
        assert_approx_equal(ntc_resistance("47k", "4050K", "25°C"), 47000)
        assert_approx_equal(ntc_resistance("47k", "4050K", "0°C"), 162942.79)
        assert_approx_equal(ntc_resistance("47k", "4050K", "5°C"), 124819.66)
        assert_approx_equal(ntc_resistance("47k", "4050K", "60°C"), 11280.407)
<|endoftext|>


<commit_before>import github3.exceptions

from cumulusci.core.utils import import_global
from cumulusci.core.github import (
    is_label_on_pull_request,
    get_pull_requests_by_head,
    get_pull_requests_with_base_branch,
)
from cumulusci.tasks.release_notes.exceptions import CumulusCIException
from cumulusci.tasks.release_notes.parser import ChangeNotesLinesParser
from cumulusci.tasks.release_notes.parser import GithubLinesParser
from cumulusci.tasks.release_notes.parser import IssuesParser
from cumulusci.tasks.release_notes.provider import StaticChangeNotesProvider
from cumulusci.tasks.release_notes.provider import DirectoryChangeNotesProvider
from cumulusci.tasks.release_notes.provider import GithubChangeNotesProvider

class BaseReleaseNotesGenerator(object):
    def __init__(self):
        self.change_notes = []
        self.empty_change_notes = []
        self.init_parsers()
        self.init_change_notes()

    def __call__(self):
        self._parse_change_notes()
        return self.render()

    def init_change_notes(self):
        self.change_notes = self._init_change_notes()

    def _init_change_notes(self):
        """ Subclasses should override this method to return an initialized
        subclass of BaseChangeNotesProvider """
        return []

    def init_parsers(self):
        """ Initializes the parser instances as the list self.parsers """
        self.parsers = []
        self._init_parsers()

    def _init_parsers(self):
        """ Subclasses should override this method to initialize their
        parsers """
        pass

    def _parse_change_notes(self):
        """ Parses all change_notes in self.change_notes() through all parsers
        in self.parsers """
        for change_note in self.change_notes():
            self._parse_change_note(change_note)

    def _parse_change_note(self, change_note):
        """ Parses an individual change note through all parsers in
        self.parsers. If no lines were added then appends the change
        note to the list of empty PRs"""
        line_added_by_parsers = False
        for parser in self.parsers:
            line_added = parser.parse(change_note)
            if not line_added_by_parsers:
                line_added_by_parsers = line_added

        if not line_added_by_parsers:
            self.empty_change_notes.append(change_note)

    def render(self):
        """ Returns the rendered release notes from all parsers as a string """
        release_notes = []
        for parser in self.parsers:
            parser_content = parser.render()
            if parser_content is not None:
                release_notes.append(parser_content)
        return u"\r\n\r\n".join(release_notes)

class StaticReleaseNotesGenerator(BaseReleaseNotesGenerator):
    def __init__(self, change_notes):
        self._change_notes = change_notes
        super(StaticReleaseNotesGenerator, self).__init__()

    def _init_parsers(self):
        self.parsers.append(ChangeNotesLinesParser(self, "Critical Changes"))
        self.parsers.append(ChangeNotesLinesParser(self, "Changes"))
        self.parsers.append(IssuesParser(self, "Issues Closed"))

    def _init_change_notes(self):
        return StaticChangeNotesProvider(self, self._change_notes)

class DirectoryReleaseNotesGenerator(BaseReleaseNotesGenerator):
    def __init__(self, directory):
        self.directory = directory
        super(DirectoryReleaseNotesGenerator, self).__init__()

    def _init_parsers(self):
        self.parsers.append(ChangeNotesLinesParser(self, "Critical Changes"))
        self.parsers.append(ChangeNotesLinesParser(self, "Changes"))
        self.parsers.append(IssuesParser(self, "Issues Closed"))

    def _init_change_notes(self):
        return DirectoryChangeNotesProvider(self, self.directory)

class ParentPullRequestNotesGenerator(BaseReleaseNotesGenerator):
    """Aggregates notes from child pull requests in to a parent pull request"""

    # Header where unaggregated child pull requests are linked to
    UNAGGREGATED_SECTION_HEADER = "\r\n\r\n# Unaggregated Pull Requests"

    def __init__(self, github, repo, project_config):

        self.repo = repo
        self.github = github
        self.link_pr = True  # create links to pr on parsed change notes
        self.has_issues = True  # need for parsers
        self.do_publish = True  # need for parsers
        self.parser_config = (
            project_config.project__git__release_notes__parsers.values()
        )
        super(ParentPullRequestNotesGenerator, self).__init__()

    def _init_parsers(self):
        """Invoked from Super Class"""
        for cfg in self.parser_config:
            parser_class = import_global(cfg["class_path"])
            self.parsers.append(parser_class(self, cfg["title"]))

        # Additional parser to collect developer notes above tracked headers
        self.parsers.append(GithubLinesParser(self, title=None))
        self.parsers[-1]._in_section = True

    def aggregate_child_change_notes(self, pull_request):
        """Given a pull request, aggregate all change notes from child pull requests.
        Child pull requests are pull requests that have a base branch
        equal to the the given pull request's head."""
        self.change_notes = get_pull_requests_with_base_branch(
            self.repo, pull_request.head.label.split(":")[1]
        )
        if len(self.change_notes) == 0:
            return

        for change_note in self.change_notes:
            self._parse_change_note(change_note)

        body = []
        for parser in self.parsers:
            if parser.title == None:
                parser.title = "Notes From Child PRs"
            parser_content = parser.render()
            if parser_content:
                body.append(parser_content)

        if self.empty_change_notes:
            body.extend(render_empty_pr_section(self.empty_change_notes))
        new_body = "\r\n".join(body)

        if not pull_request.update(body=new_body):
            raise CumulusCIException(
                "Update of pull request #{} failed.".format(pull_request.number)
            )

    def update_unaggregated_pr_header(self, pull_request_to_update, branch_name_to_add):
        """Updates the 'Unaggregated Pull Requests' section header with a link
        to the new child branch pull request"""
        body = pull_request_to_update.body
        if self.UNAGGREGATED_SECTION_HEADER not in body:
            body += self.UNAGGREGATED_SECTION_HEADER

        pull_requests = get_pull_requests_with_base_branch(
            self.repo, branch_name_to_add.split("__")[0], branch_name_to_add
        )

        if len(pull_requests) == 0:
            raise CumulusCIException(
                "No pull request for branch {} found.".format(branch_name_to_add)
            )
        elif len(pull_requests) > 1:
            raise CumulusCIException(
                "Expected one pull request, found {} for branch {}".format(
                    len(pull_requests), branch_name_to_add
                )
            )

        pull_request_link = markdown_link_to_pr(pull_requests[0])
        if pull_request_link not in body:
            body += "\r\n* " + pull_request_link
            pull_request_to_update.update(body=body)
            return

def is_merged(pull_request):
    return pull_request.merged_at is not None

class GithubReleaseNotesGenerator(BaseReleaseNotesGenerator):
    def __init__(
        self,
        github,
        github_info,
        parser_config,
        current_tag,
        last_tag=None,
        link_pr=False,
        publish=False,
        has_issues=True,
        include_empty=False,
    ):
        self.github = github
        self.github_info = github_info
        self.parser_config = parser_config
        self.current_tag = current_tag
        self.last_tag = last_tag
        self.link_pr = link_pr
        self.do_publish = publish
        self.has_issues = has_issues
        self.include_empty_pull_requests = include_empty
        self.lines_parser_class = None
        self.issues_parser_class = None
        super(GithubReleaseNotesGenerator, self).__init__()

    def __call__(self):
        release = self._get_release()
        content = super(GithubReleaseNotesGenerator, self).__call__()
        content = self._update_release_content(release, content)
        if self.do_publish:
            release.edit(body=content)
        return content

    def _init_parsers(self):
        for cfg in self.parser_config:
            parser_class = import_global(cfg["class_path"])
            self.parsers.append(parser_class(self, cfg["title"]))

    def _init_change_notes(self):
        return GithubChangeNotesProvider(self, self.current_tag, self.last_tag)

    def _get_release(self):
        repo = self.get_repo()
        try:
            return repo.release_from_tag(self.current_tag)
        except github3.exceptions.NotFoundError:
            raise CumulusCIException(
                "Release not found for tag: {}".format(self.current_tag)
            )

    def _update_release_content(self, release, content):
        """Merge existing and new release content."""
        new_body = []
        if release.body:
            current_parser = None
            is_start_line = False
            for parser in self.parsers:
                parser.replaced = False

            # update existing sections
            for line in release.body.splitlines():

                if current_parser:
                    if current_parser._is_end_line(current_parser._process_line(line)):
                        parser_content = current_parser.render()
                        if parser_content:
                            # replace existing section with new content
                            new_body.append(parser_content + "\r\n")
                        current_parser = None

                for parser in self.parsers:
                    if (
                        parser._render_header().strip()
                        == parser._process_line(line).strip()
                    ):
                        parser.replaced = True
                        current_parser = parser
                        is_start_line = True
                        break
                    else:
                        is_start_line = False

                if is_start_line:
                    continue
                if current_parser:
                    continue
                else:
                    # preserve existing sections
                    new_body.append(line.strip())

            # catch section without end line
            if current_parser:
                new_body.append(current_parser.render())

            # add new sections at bottom
            for parser in self.parsers:
                parser_content = parser.render()
                if parser_content and not parser.replaced:
                    new_body.append(parser_content + "\r\n")

        else:  # no release.body
            new_body.append(content)

        # add empty PR section
        if self.include_empty_pull_requests:
            new_body.extend(render_empty_pr_section(self.empty_change_notes))
        content = u"\r\n".join(new_body)
        return content

    def get_repo(self):
        return self.github.repository(
            self.github_info["github_owner"], self.github_info["github_repo"]
        )

def render_empty_pr_section(empty_change_notes):
    section_lines = []
    if empty_change_notes:
        section_lines.append("\n# Pull requests with no release notes")
        for change_note in empty_change_notes:
            section_lines.append("\n* {}".format(markdown_link_to_pr(change_note)))
    return section_lines

def markdown_link_to_pr(change_note):
    return "{} [[PR{}]({})]".format(
        change_note.title, change_note.number, change_note.html_url
    )
<commit_msg>filter out merged pull requests<commit_after>import github3.exceptions

from cumulusci.core.utils import import_global
from cumulusci.core.github import (
    is_label_on_pull_request,
    get_pull_requests_by_head,
    get_pull_requests_with_base_branch,
)
from cumulusci.tasks.release_notes.exceptions import CumulusCIException
from cumulusci.tasks.release_notes.parser import ChangeNotesLinesParser
from cumulusci.tasks.release_notes.parser import GithubLinesParser
from cumulusci.tasks.release_notes.parser import IssuesParser
from cumulusci.tasks.release_notes.provider import StaticChangeNotesProvider
from cumulusci.tasks.release_notes.provider import DirectoryChangeNotesProvider
from cumulusci.tasks.release_notes.provider import GithubChangeNotesProvider

class BaseReleaseNotesGenerator(object):
    def __init__(self):
        self.change_notes = []
        self.empty_change_notes = []
        self.init_parsers()
        self.init_change_notes()

    def __call__(self):
        self._parse_change_notes()
        return self.render()

    def init_change_notes(self):
        self.change_notes = self._init_change_notes()

    def _init_change_notes(self):
        """ Subclasses should override this method to return an initialized
        subclass of BaseChangeNotesProvider """
        return []

    def init_parsers(self):
        """ Initializes the parser instances as the list self.parsers """
        self.parsers = []
        self._init_parsers()

    def _init_parsers(self):
        """ Subclasses should override this method to initialize their
        parsers """
        pass

    def _parse_change_notes(self):
        """ Parses all change_notes in self.change_notes() through all parsers
        in self.parsers """
        for change_note in self.change_notes():
            self._parse_change_note(change_note)

    def _parse_change_note(self, change_note):
        """ Parses an individual change note through all parsers in
        self.parsers. If no lines were added then appends the change
        note to the list of empty PRs"""
        line_added_by_parsers = False
        for parser in self.parsers:
            line_added = parser.parse(change_note)
            if not line_added_by_parsers:
                line_added_by_parsers = line_added

        if not line_added_by_parsers:
            self.empty_change_notes.append(change_note)

    def render(self):
        """ Returns the rendered release notes from all parsers as a string """
        release_notes = []
        for parser in self.parsers:
            parser_content = parser.render()
            if parser_content is not None:
                release_notes.append(parser_content)
        return u"\r\n\r\n".join(release_notes)

class StaticReleaseNotesGenerator(BaseReleaseNotesGenerator):
    def __init__(self, change_notes):
        self._change_notes = change_notes
        super(StaticReleaseNotesGenerator, self).__init__()

    def _init_parsers(self):
        self.parsers.append(ChangeNotesLinesParser(self, "Critical Changes"))
        self.parsers.append(ChangeNotesLinesParser(self, "Changes"))
        self.parsers.append(IssuesParser(self, "Issues Closed"))

    def _init_change_notes(self):
        return StaticChangeNotesProvider(self, self._change_notes)

class DirectoryReleaseNotesGenerator(BaseReleaseNotesGenerator):
    def __init__(self, directory):
        self.directory = directory
        super(DirectoryReleaseNotesGenerator, self).__init__()

    def _init_parsers(self):
        self.parsers.append(ChangeNotesLinesParser(self, "Critical Changes"))
        self.parsers.append(ChangeNotesLinesParser(self, "Changes"))
        self.parsers.append(IssuesParser(self, "Issues Closed"))

    def _init_change_notes(self):
        return DirectoryChangeNotesProvider(self, self.directory)

class ParentPullRequestNotesGenerator(BaseReleaseNotesGenerator):
    """Aggregates notes from child pull requests in to a parent pull request"""

    # Header where unaggregated child pull requests are linked to
    UNAGGREGATED_SECTION_HEADER = "\r\n\r\n# Unaggregated Pull Requests"

    def __init__(self, github, repo, project_config):

        self.repo = repo
        self.github = github
        self.link_pr = True  # create links to pr on parsed change notes
        self.has_issues = True  # need for parsers
        self.do_publish = True  # need for parsers
        self.parser_config = (
            project_config.project__git__release_notes__parsers.values()
        )
        super(ParentPullRequestNotesGenerator, self).__init__()

    def _init_parsers(self):
        """Invoked from Super Class"""
        for cfg in self.parser_config:
            parser_class = import_global(cfg["class_path"])
            self.parsers.append(parser_class(self, cfg["title"]))

        # Additional parser to collect developer notes above tracked headers
        self.parsers.append(GithubLinesParser(self, title=None))
        self.parsers[-1]._in_section = True

    def aggregate_child_change_notes(self, pull_request):
        """Given a pull request, aggregate all change notes from child pull requests.
        Child pull requests are pull requests that have a base branch
        equal to the the given pull request's head."""
        self.change_notes = get_pull_requests_with_base_branch(
            self.repo, pull_request.head.ref
        )
        self.change_notes = list(filter(is_merged, self.change_notes))
        if len(self.change_notes) == 0:
            return

        for change_note in self.change_notes:
            self._parse_change_note(change_note)

        body = []
        for parser in self.parsers:
            if parser.title == None:
                parser.title = "Notes From Child PRs"
            parser_content = parser.render()
            if parser_content:
                body.append(parser_content)

        if self.empty_change_notes:
            body.extend(render_empty_pr_section(self.empty_change_notes))
        new_body = "\r\n".join(body)

        if not pull_request.update(body=new_body):
            raise CumulusCIException(
                "Update of pull request #{} failed.".format(pull_request.number)
            )

    def update_unaggregated_pr_header(self, pull_request_to_update, branch_name_to_add):
        """Updates the 'Unaggregated Pull Requests' section header with a link
        to the new child branch pull request"""
        body = pull_request_to_update.body
        if self.UNAGGREGATED_SECTION_HEADER not in body:
            body += self.UNAGGREGATED_SECTION_HEADER

        pull_requests = get_pull_requests_with_base_branch(
            self.repo, branch_name_to_add.split("__")[0], branch_name_to_add
        )

        if len(pull_requests) == 0:
            raise CumulusCIException(
                "No pull request for branch {} found.".format(branch_name_to_add)
            )
        elif len(pull_requests) > 1:
            raise CumulusCIException(
                "Expected one pull request, found {} for branch {}".format(
                    len(pull_requests), branch_name_to_add
                )
            )

        pull_request_link = markdown_link_to_pr(pull_requests[0])
        if pull_request_link not in body:
            body += "\r\n* " + pull_request_link
            pull_request_to_update.update(body=body)
            return

def is_merged(pull_request):
    return pull_request.merged_at is not None

class GithubReleaseNotesGenerator(BaseReleaseNotesGenerator):
    def __init__(
        self,
        github,
        github_info,
        parser_config,
        current_tag,
        last_tag=None,
        link_pr=False,
        publish=False,
        has_issues=True,
        include_empty=False,
    ):
        self.github = github
        self.github_info = github_info
        self.parser_config = parser_config
        self.current_tag = current_tag
        self.last_tag = last_tag
        self.link_pr = link_pr
        self.do_publish = publish
        self.has_issues = has_issues
        self.include_empty_pull_requests = include_empty
        self.lines_parser_class = None
        self.issues_parser_class = None
        super(GithubReleaseNotesGenerator, self).__init__()

    def __call__(self):
        release = self._get_release()
        content = super(GithubReleaseNotesGenerator, self).__call__()
        content = self._update_release_content(release, content)
        if self.do_publish:
            release.edit(body=content)
        return content

    def _init_parsers(self):
        for cfg in self.parser_config:
            parser_class = import_global(cfg["class_path"])
            self.parsers.append(parser_class(self, cfg["title"]))

    def _init_change_notes(self):
        return GithubChangeNotesProvider(self, self.current_tag, self.last_tag)

    def _get_release(self):
        repo = self.get_repo()
        try:
            return repo.release_from_tag(self.current_tag)
        except github3.exceptions.NotFoundError:
            raise CumulusCIException(
                "Release not found for tag: {}".format(self.current_tag)
            )

    def _update_release_content(self, release, content):
        """Merge existing and new release content."""
        new_body = []
        if release.body:
            current_parser = None
            is_start_line = False
            for parser in self.parsers:
                parser.replaced = False

            # update existing sections
            for line in release.body.splitlines():

                if current_parser:
                    if current_parser._is_end_line(current_parser._process_line(line)):
                        parser_content = current_parser.render()
                        if parser_content:
                            # replace existing section with new content
                            new_body.append(parser_content + "\r\n")
                        current_parser = None

                for parser in self.parsers:
                    if (
                        parser._render_header().strip()
                        == parser._process_line(line).strip()
                    ):
                        parser.replaced = True
                        current_parser = parser
                        is_start_line = True
                        break
                    else:
                        is_start_line = False

                if is_start_line:
                    continue
                if current_parser:
                    continue
                else:
                    # preserve existing sections
                    new_body.append(line.strip())

            # catch section without end line
            if current_parser:
                new_body.append(current_parser.render())

            # add new sections at bottom
            for parser in self.parsers:
                parser_content = parser.render()
                if parser_content and not parser.replaced:
                    new_body.append(parser_content + "\r\n")

        else:  # no release.body
            new_body.append(content)

        # add empty PR section
        if self.include_empty_pull_requests:
            new_body.extend(render_empty_pr_section(self.empty_change_notes))
        content = u"\r\n".join(new_body)
        return content

    def get_repo(self):
        return self.github.repository(
            self.github_info["github_owner"], self.github_info["github_repo"]
        )

def render_empty_pr_section(empty_change_notes):
    section_lines = []
    if empty_change_notes:
        section_lines.append("\n# Pull requests with no release notes")
        for change_note in empty_change_notes:
            section_lines.append("\n* {}".format(markdown_link_to_pr(change_note)))
    return section_lines

def markdown_link_to_pr(change_note):
    return "{} [[PR{}]({})]".format(
        change_note.title, change_note.number, change_note.html_url
    )
<|endoftext|>


<commit_before># Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.

from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
import UM.Settings
from UM.Application import Application
import cura.Settings
from UM.Logger import Logger

##    The settingInheritance manager is responsible for checking each setting in order to see if one of the "deeper"
#     containers has a setting function and the topmost one with a value has a value. We need to have this check
#     because some profiles tend to have 'hardcoded' values that break our inheritance. A good example of that are the
#     speed settings. If all the children of print_speed have a single value override, changing the speed won't
#     actually do anything, as only the 'leaf' settings are used by the engine.
class SettingInheritanceManager(QObject):
    def __init__(self, parent = None):
        super().__init__(parent)
        Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
        self._global_container_stack = None
        self._settings_with_inheritance_warning = []
        self._active_container_stack = None
        self._onGlobalContainerChanged()

        cura.Settings.ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
        self._onActiveExtruderChanged()

    settingsWithIntheritanceChanged = pyqtSignal()

    ##  Get the keys of all children settings with an override.
    @pyqtSlot(str, result = "QStringList")
    def getChildrenKeysWithOverride(self, key):
        definitions = self._global_container_stack.getBottom().findDefinitions(key=key)
        if not definitions:
            return
        result = []
        for key in definitions[0].getAllKeys():
            if key in self._settings_with_inheritance_warning:
                result.append(key)
        return result

    @pyqtSlot(str, str, result = "QStringList")
    def getOverridesForExtruder(self, key, extruder_index):
        multi_extrusion = self._global_container_stack.getProperty("machine_extruder_count", "value") > 1
        if not multi_extrusion:
            return self._settings_with_inheritance_warning
        extruder = cura.Settings.ExtruderManager.getInstance().getExtruderStack(extruder_index)
        if not extruder:
            Logger.log("w", "Unable to find extruder for current machine with index %s", extruder_index)
            return []

        definitions = self._global_container_stack.getBottom().findDefinitions(key=key)
        if not definitions:
            return
        result = []
        for key in definitions[0].getAllKeys():
            if self._settingIsOverwritingInheritance(key, extruder):
                result.append(key)

        return result

    @pyqtSlot(str)
    def manualRemoveOverride(self, key):
        if key in self._settings_with_inheritance_warning:
            self._settings_with_inheritance_warning.remove(key)
            self.settingsWithIntheritanceChanged.emit()

    @pyqtSlot()
    def forceUpdate(self):
        self._update()

    def _onActiveExtruderChanged(self):
        new_active_stack = cura.Settings.ExtruderManager.getInstance().getActiveExtruderStack()
        if not new_active_stack:
            new_active_stack = self._global_container_stack

        if new_active_stack != self._active_container_stack:  # Check if changed
            if self._active_container_stack:  # Disconnect signal from old container (if any)
                self._active_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
                self._active_container_stack.containersChanged.disconnect(self._onContainersChanged)

            self._active_container_stack = new_active_stack
            self._active_container_stack.propertyChanged.connect(self._onPropertyChanged)
            self._active_container_stack.containersChanged.connect(self._onContainersChanged)
            self._update()  # Ensure that the settings_with_inheritance_warning list is populated.

    def _onPropertyChanged(self, key, property_name):
        if property_name == "value" and self._global_container_stack:
            definitions = self._global_container_stack.getBottom().findDefinitions(key = key)
            if not definitions:
                return

            has_overwritten_inheritance = self._settingIsOverwritingInheritance(key)

            settings_with_inheritance_warning_changed = False

            # Check if the setting needs to be in the list.
            if key not in self._settings_with_inheritance_warning and has_overwritten_inheritance:
                self._settings_with_inheritance_warning.append(key)
                settings_with_inheritance_warning_changed = True
            elif key in self._settings_with_inheritance_warning and not has_overwritten_inheritance:
                self._settings_with_inheritance_warning.remove(key)
                settings_with_inheritance_warning_changed = True

            # Find the topmost parent (Assumed to be a category)
            parent = definitions[0].parent
            while parent.parent is not None:
                parent = parent.parent

            if parent.key not in self._settings_with_inheritance_warning and has_overwritten_inheritance:
                # Category was not in the list yet, so needs to be added now.
                self._settings_with_inheritance_warning.append(parent.key)
                settings_with_inheritance_warning_changed = True

            elif parent.key in self._settings_with_inheritance_warning and not has_overwritten_inheritance:
                # Category was in the list and one of it's settings is not overwritten.
                if not self._recursiveCheck(parent):  # Check if any of it's children have overwritten inheritance.
                    self._settings_with_inheritance_warning.remove(parent.key)
                    settings_with_inheritance_warning_changed = True

            # Emit the signal if there was any change to the list.
            if settings_with_inheritance_warning_changed:
                self.settingsWithIntheritanceChanged.emit()

    def _recursiveCheck(self, definition):
        for child in definition.children:
            if child.key in self._settings_with_inheritance_warning:
                return True
            if child.children:
                if self._recursiveCheck(child):
                    return True
        return False

    @pyqtProperty("QVariantList", notify = settingsWithIntheritanceChanged)
    def settingsWithInheritanceWarning(self):
        return self._settings_with_inheritance_warning

    ##  Check if a setting has an inheritance function that is overwritten
    def _settingIsOverwritingInheritance(self, key, stack = None):
        has_setting_function = False
        if not stack:
            stack = self._active_container_stack
        containers = []

        ## Check if the setting has a user state. If not, it is never overwritten.
        has_user_state = stack.getProperty(key, "state") == UM.Settings.InstanceState.User
        if not has_user_state:
            return False

        ## If a setting is not enabled, don't label it as overwritten (It's never visible anyway).
        if not stack.getProperty(key, "enabled"):
            return False

        ## Also check if the top container is not a setting function (this happens if the inheritance is restored).
        if isinstance(stack.getTop().getProperty(key, "value"), UM.Settings.SettingFunction):
            return False

        ##  Mash all containers for all the stacks together.
        while stack:
            containers.extend(stack.getContainers())
            stack = stack.getNextStack()
        has_non_function_value = False
        for container in containers:
            try:
                value = container.getProperty(key, "value")
            except AttributeError:
                continue
            if value is not None:
                # If a setting doesn't use any keys, it won't change it's value, so treat it as if it's a fixed value
                has_setting_function = isinstance(value, UM.Settings.SettingFunction) and len(value.getUsedSettingKeys()) > 0
                if key == "prime_tower_size":
                    print(container.getId())
                if has_setting_function is False:
                    has_non_function_value = True
                    continue

            if has_setting_function:
                break  # There is a setting function somewhere, stop looking deeper.
        if key == "prime_tower_size":
            print("YAY", has_setting_function, has_non_function_value)
        return has_setting_function and has_non_function_value

    def _update(self):
        self._settings_with_inheritance_warning = []  # Reset previous data.

        # Check all setting keys that we know of and see if they are overridden.
        for setting_key in self._global_container_stack.getAllKeys():
            override = self._settingIsOverwritingInheritance(setting_key)
            if override:
                self._settings_with_inheritance_warning.append(setting_key)

        # Check all the categories if any of their children have their inheritance overwritten.
        for category in self._global_container_stack.getBottom().findDefinitions(type = "category"):
            if self._recursiveCheck(category):
                self._settings_with_inheritance_warning.append(category.key)

        # Notify others that things have changed.
        self.settingsWithIntheritanceChanged.emit()

    def _onGlobalContainerChanged(self):
        if self._global_container_stack:
            self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
            self._global_container_stack.containersChanged.disconnect(self._onContainersChanged)
        self._global_container_stack = Application.getInstance().getGlobalContainerStack()
        if self._global_container_stack:
            self._global_container_stack.containersChanged.connect(self._onContainersChanged)
            self._global_container_stack.propertyChanged.connect(self._onPropertyChanged)
        self._onActiveExtruderChanged()

    def _onContainersChanged(self, container):
        # TODO: Multiple container changes in sequence now cause quite a few recalculations.
        # This isn't that big of an issue, but it could be in the future.
        self._update()

    @staticmethod
    def createSettingInheritanceManager(engine=None, script_engine=None):
        return SettingInheritanceManager()
<commit_msg>Removed debug prints<commit_after># Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.

from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
import UM.Settings
from UM.Application import Application
import cura.Settings
from UM.Logger import Logger

##    The settingInheritance manager is responsible for checking each setting in order to see if one of the "deeper"
#     containers has a setting function and the topmost one with a value has a value. We need to have this check
#     because some profiles tend to have 'hardcoded' values that break our inheritance. A good example of that are the
#     speed settings. If all the children of print_speed have a single value override, changing the speed won't
#     actually do anything, as only the 'leaf' settings are used by the engine.
class SettingInheritanceManager(QObject):
    def __init__(self, parent = None):
        super().__init__(parent)
        Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
        self._global_container_stack = None
        self._settings_with_inheritance_warning = []
        self._active_container_stack = None
        self._onGlobalContainerChanged()

        cura.Settings.ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
        self._onActiveExtruderChanged()

    settingsWithIntheritanceChanged = pyqtSignal()

    ##  Get the keys of all children settings with an override.
    @pyqtSlot(str, result = "QStringList")
    def getChildrenKeysWithOverride(self, key):
        definitions = self._global_container_stack.getBottom().findDefinitions(key=key)
        if not definitions:
            return
        result = []
        for key in definitions[0].getAllKeys():
            if key in self._settings_with_inheritance_warning:
                result.append(key)
        return result

    @pyqtSlot(str, str, result = "QStringList")
    def getOverridesForExtruder(self, key, extruder_index):
        multi_extrusion = self._global_container_stack.getProperty("machine_extruder_count", "value") > 1
        if not multi_extrusion:
            return self._settings_with_inheritance_warning
        extruder = cura.Settings.ExtruderManager.getInstance().getExtruderStack(extruder_index)
        if not extruder:
            Logger.log("w", "Unable to find extruder for current machine with index %s", extruder_index)
            return []

        definitions = self._global_container_stack.getBottom().findDefinitions(key=key)
        if not definitions:
            return
        result = []
        for key in definitions[0].getAllKeys():
            if self._settingIsOverwritingInheritance(key, extruder):
                result.append(key)

        return result

    @pyqtSlot(str)
    def manualRemoveOverride(self, key):
        if key in self._settings_with_inheritance_warning:
            self._settings_with_inheritance_warning.remove(key)
            self.settingsWithIntheritanceChanged.emit()

    @pyqtSlot()
    def forceUpdate(self):
        self._update()

    def _onActiveExtruderChanged(self):
        new_active_stack = cura.Settings.ExtruderManager.getInstance().getActiveExtruderStack()
        if not new_active_stack:
            new_active_stack = self._global_container_stack

        if new_active_stack != self._active_container_stack:  # Check if changed
            if self._active_container_stack:  # Disconnect signal from old container (if any)
                self._active_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
                self._active_container_stack.containersChanged.disconnect(self._onContainersChanged)

            self._active_container_stack = new_active_stack
            self._active_container_stack.propertyChanged.connect(self._onPropertyChanged)
            self._active_container_stack.containersChanged.connect(self._onContainersChanged)
            self._update()  # Ensure that the settings_with_inheritance_warning list is populated.

    def _onPropertyChanged(self, key, property_name):
        if property_name == "value" and self._global_container_stack:
            definitions = self._global_container_stack.getBottom().findDefinitions(key = key)
            if not definitions:
                return

            has_overwritten_inheritance = self._settingIsOverwritingInheritance(key)

            settings_with_inheritance_warning_changed = False

            # Check if the setting needs to be in the list.
            if key not in self._settings_with_inheritance_warning and has_overwritten_inheritance:
                self._settings_with_inheritance_warning.append(key)
                settings_with_inheritance_warning_changed = True
            elif key in self._settings_with_inheritance_warning and not has_overwritten_inheritance:
                self._settings_with_inheritance_warning.remove(key)
                settings_with_inheritance_warning_changed = True

            # Find the topmost parent (Assumed to be a category)
            parent = definitions[0].parent
            while parent.parent is not None:
                parent = parent.parent

            if parent.key not in self._settings_with_inheritance_warning and has_overwritten_inheritance:
                # Category was not in the list yet, so needs to be added now.
                self._settings_with_inheritance_warning.append(parent.key)
                settings_with_inheritance_warning_changed = True

            elif parent.key in self._settings_with_inheritance_warning and not has_overwritten_inheritance:
                # Category was in the list and one of it's settings is not overwritten.
                if not self._recursiveCheck(parent):  # Check if any of it's children have overwritten inheritance.
                    self._settings_with_inheritance_warning.remove(parent.key)
                    settings_with_inheritance_warning_changed = True

            # Emit the signal if there was any change to the list.
            if settings_with_inheritance_warning_changed:
                self.settingsWithIntheritanceChanged.emit()

    def _recursiveCheck(self, definition):
        for child in definition.children:
            if child.key in self._settings_with_inheritance_warning:
                return True
            if child.children:
                if self._recursiveCheck(child):
                    return True
        return False

    @pyqtProperty("QVariantList", notify = settingsWithIntheritanceChanged)
    def settingsWithInheritanceWarning(self):
        return self._settings_with_inheritance_warning

    ##  Check if a setting has an inheritance function that is overwritten
    def _settingIsOverwritingInheritance(self, key, stack = None):
        has_setting_function = False
        if not stack:
            stack = self._active_container_stack
        containers = []

        ## Check if the setting has a user state. If not, it is never overwritten.
        has_user_state = stack.getProperty(key, "state") == UM.Settings.InstanceState.User
        if not has_user_state:
            return False

        ## If a setting is not enabled, don't label it as overwritten (It's never visible anyway).
        if not stack.getProperty(key, "enabled"):
            return False

        ## Also check if the top container is not a setting function (this happens if the inheritance is restored).
        if isinstance(stack.getTop().getProperty(key, "value"), UM.Settings.SettingFunction):
            return False

        ##  Mash all containers for all the stacks together.
        while stack:
            containers.extend(stack.getContainers())
            stack = stack.getNextStack()
        has_non_function_value = False
        for container in containers:
            try:
                value = container.getProperty(key, "value")
            except AttributeError:
                continue
            if value is not None:
                # If a setting doesn't use any keys, it won't change it's value, so treat it as if it's a fixed value
                has_setting_function = isinstance(value, UM.Settings.SettingFunction) and len(value.getUsedSettingKeys()) > 0
                if has_setting_function is False:
                    has_non_function_value = True
                    continue

            if has_setting_function:
                break  # There is a setting function somewhere, stop looking deeper.
        return has_setting_function and has_non_function_value

    def _update(self):
        self._settings_with_inheritance_warning = []  # Reset previous data.

        # Check all setting keys that we know of and see if they are overridden.
        for setting_key in self._global_container_stack.getAllKeys():
            override = self._settingIsOverwritingInheritance(setting_key)
            if override:
                self._settings_with_inheritance_warning.append(setting_key)

        # Check all the categories if any of their children have their inheritance overwritten.
        for category in self._global_container_stack.getBottom().findDefinitions(type = "category"):
            if self._recursiveCheck(category):
                self._settings_with_inheritance_warning.append(category.key)

        # Notify others that things have changed.
        self.settingsWithIntheritanceChanged.emit()

    def _onGlobalContainerChanged(self):
        if self._global_container_stack:
            self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
            self._global_container_stack.containersChanged.disconnect(self._onContainersChanged)
        self._global_container_stack = Application.getInstance().getGlobalContainerStack()
        if self._global_container_stack:
            self._global_container_stack.containersChanged.connect(self._onContainersChanged)
            self._global_container_stack.propertyChanged.connect(self._onPropertyChanged)
        self._onActiveExtruderChanged()

    def _onContainersChanged(self, container):
        # TODO: Multiple container changes in sequence now cause quite a few recalculations.
        # This isn't that big of an issue, but it could be in the future.
        self._update()

    @staticmethod
    def createSettingInheritanceManager(engine=None, script_engine=None):
        return SettingInheritanceManager()
<|endoftext|>


<commit_before>from corehq.apps.data_interfaces.models import (
    AUTO_UPDATE_XMLNS,
    CaseRuleActionResult,
)
from corehq.apps.hqcase.utils import update_case
from corehq.form_processor.models import CommCareCase, CommCareCaseIndex
from custom.gcc_sangath.const import (
    DATE_OF_PEER_REVIEW_CASE_PROP,
    MEAN_GENERAL_SKILLS_SCORE_CASE_PROP,
    MEAN_TREATMENT_SPECIFIC_SCORE_CASE_PROP,
    NEEDS_AGGREGATION_CASE_PROP,
    NEEDS_AGGREGATION_NO_VALUE,
    SESSION_CASE_TYPE,
    SESSION_RATING_CASE_PROP,
)

def sanitize_session_peer_rating(session_case, rule):
    """
    For any session case
    sanitize the peer_rating metrics based on child cases of type peer_rating
    """
    if session_case.type != SESSION_CASE_TYPE:
        return CaseRuleActionResult()

    peer_rating_cases = _get_peer_rating_cases(session_case)
    num_updates = 0

    if peer_rating_cases:
        case_updates = _get_case_updates(peer_rating_cases)
        (submission, cases) = update_case(
            session_case.domain,
            session_case.case_id,
            case_properties=case_updates,
            xmlns=AUTO_UPDATE_XMLNS,
            device_id=__name__ + ".sanitize_session_peer_rating",
        )
        num_updates = 1
        rule.log_submission(submission.form_id)

    return CaseRuleActionResult(
        num_updates=num_updates,
    )

def _get_peer_rating_cases(session_case):
    case_ids = CommCareCaseIndex.objects.get_extension_case_ids(session_case.domain, [session_case.case_id])
    return CommCareCase.objects.get_cases(case_ids, session_case.domain)

def _get_case_updates(peer_rating_cases):
    """
    feedback_num = number of child peer_rating cases
    total_session_rating = sum of session_rating of all peer_rating child cases

    agg_rating = sum of session_rating of all peer_rating child cases / num of peer_rating child cases
    agg_mean_treatment_specific_score = sum of mean_treatment_specific_score of all peer_rating child cases /
                                        num of peer _rating child cases
    agg_mean_general_skills_score = sum of mean_general_skills_score of all peer_rating child cases /
                                    num of peer _rating child cases

    date_of peer_review = max(date_of_peer_review) set on peer_rating child case
    share_score_check = 'yes'
    """
    number_of_peer_ratings = len(peer_rating_cases)
    sum_of_session_rating = _get_sum(SESSION_RATING_CASE_PROP, peer_rating_cases)

    agg_of_mean_treatment_specific_score = _get_aggregate(MEAN_TREATMENT_SPECIFIC_SCORE_CASE_PROP,
                                                          peer_rating_cases)
    agg_of_mean_general_skills_score = _get_aggregate(MEAN_GENERAL_SKILLS_SCORE_CASE_PROP, peer_rating_cases)

    latest_peer_review = _get_latest_peer_review_date(peer_rating_cases)

    case_updates = {
        'feedback_num': number_of_peer_ratings,
        'total_session_rating': sum_of_session_rating,
        'agg_rating': round(sum_of_session_rating / number_of_peer_ratings, 1),
        'agg_mean_treatment_specific_score': agg_of_mean_treatment_specific_score,
        'agg_mean_general_skills_score': agg_of_mean_general_skills_score,
        'date_of_peer_review': latest_peer_review,
        'share_score_check': 'yes',
    }
    case_updates[NEEDS_AGGREGATION_CASE_PROP] = NEEDS_AGGREGATION_NO_VALUE
    return case_updates

def _get_sum(case_property, peer_rating_cases):
    return sum([
        int(peer_rating_case.get_case_property(case_property) or 0)
        for peer_rating_case in peer_rating_cases
    ])

def _get_aggregate(case_property, peer_rating_cases):
    total = _get_sum(case_property, peer_rating_cases)
    count = len(peer_rating_cases)
    return round(total / count, 1)

def _get_latest_peer_review_date(peer_rating_cases):
    latest_peer_review = None
    for peer_rating_case in peer_rating_cases:
        date_of_peer_review = peer_rating_case.get_case_property(DATE_OF_PEER_REVIEW_CASE_PROP)
        if not latest_peer_review and date_of_peer_review:
            latest_peer_review = date_of_peer_review
        elif latest_peer_review and date_of_peer_review and date_of_peer_review > latest_peer_review:
            latest_peer_review = date_of_peer_review
    return latest_peer_review
<commit_msg>removes redundant documentation<commit_after>from corehq.apps.data_interfaces.models import (
    AUTO_UPDATE_XMLNS,
    CaseRuleActionResult,
)
from corehq.apps.hqcase.utils import update_case
from corehq.form_processor.models import CommCareCase, CommCareCaseIndex
from custom.gcc_sangath.const import (
    DATE_OF_PEER_REVIEW_CASE_PROP,
    MEAN_GENERAL_SKILLS_SCORE_CASE_PROP,
    MEAN_TREATMENT_SPECIFIC_SCORE_CASE_PROP,
    NEEDS_AGGREGATION_CASE_PROP,
    NEEDS_AGGREGATION_NO_VALUE,
    SESSION_CASE_TYPE,
    SESSION_RATING_CASE_PROP,
)

def sanitize_session_peer_rating(session_case, rule):
    """
    For any session case
    sanitize the peer_rating metrics based on child cases of type peer_rating
    """
    if session_case.type != SESSION_CASE_TYPE:
        return CaseRuleActionResult()

    peer_rating_cases = _get_peer_rating_cases(session_case)
    num_updates = 0

    if peer_rating_cases:
        case_updates = _get_case_updates(peer_rating_cases)
        (submission, cases) = update_case(
            session_case.domain,
            session_case.case_id,
            case_properties=case_updates,
            xmlns=AUTO_UPDATE_XMLNS,
            device_id=__name__ + ".sanitize_session_peer_rating",
        )
        num_updates = 1
        rule.log_submission(submission.form_id)

    return CaseRuleActionResult(
        num_updates=num_updates,
    )

def _get_peer_rating_cases(session_case):
    case_ids = CommCareCaseIndex.objects.get_extension_case_ids(session_case.domain, [session_case.case_id])
    return CommCareCase.objects.get_cases(case_ids, session_case.domain)

def _get_case_updates(peer_rating_cases):
    number_of_peer_ratings = len(peer_rating_cases)
    sum_of_session_rating = _get_sum(SESSION_RATING_CASE_PROP, peer_rating_cases)

    agg_of_mean_treatment_specific_score = _get_aggregate(MEAN_TREATMENT_SPECIFIC_SCORE_CASE_PROP,
                                                          peer_rating_cases)
    agg_of_mean_general_skills_score = _get_aggregate(MEAN_GENERAL_SKILLS_SCORE_CASE_PROP, peer_rating_cases)

    latest_peer_review = _get_latest_peer_review_date(peer_rating_cases)

    case_updates = {
        'feedback_num': number_of_peer_ratings,
        'total_session_rating': sum_of_session_rating,
        'agg_rating': round(sum_of_session_rating / number_of_peer_ratings, 1),
        'agg_mean_treatment_specific_score': agg_of_mean_treatment_specific_score,
        'agg_mean_general_skills_score': agg_of_mean_general_skills_score,
        'date_of_peer_review': latest_peer_review,
        'share_score_check': 'yes',
    }
    case_updates[NEEDS_AGGREGATION_CASE_PROP] = NEEDS_AGGREGATION_NO_VALUE
    return case_updates

def _get_sum(case_property, peer_rating_cases):
    return sum([
        int(peer_rating_case.get_case_property(case_property) or 0)
        for peer_rating_case in peer_rating_cases
    ])

def _get_aggregate(case_property, peer_rating_cases):
    total = _get_sum(case_property, peer_rating_cases)
    count = len(peer_rating_cases)
    return round(total / count, 1)

def _get_latest_peer_review_date(peer_rating_cases):
    latest_peer_review = None
    for peer_rating_case in peer_rating_cases:
        date_of_peer_review = peer_rating_case.get_case_property(DATE_OF_PEER_REVIEW_CASE_PROP)
        if not latest_peer_review and date_of_peer_review:
            latest_peer_review = date_of_peer_review
        elif latest_peer_review and date_of_peer_review and date_of_peer_review > latest_peer_review:
            latest_peer_review = date_of_peer_review
    return latest_peer_review
<|endoftext|>


<commit_before>#!/usr/bin/env python2.5
#
# Copyright 2009 the Melange authors.
#
# 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.

"""Module contains sidebar memcaching functions.
"""

__authors__ = [
    '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]

from google.appengine.api import memcache

import soc.cache.base
import soc.cache.rights
import soc.logic.accounts

def key(id):
  """Returns the memcache key for the user's sidebar.
  """

  return 'sidebar_for_%s' % repr(id)

def get(id, *args, **kwargs):
  """Retrieves the sidebar for the specified user from the memcache.
  """

  memcache_key = key(id)
  # pylint: disable-msg=E1101
  return memcache.get(memcache_key), memcache_key

def put(sidebar, memcache_key, *args, **kwargs):
  """Sets the sidebar for the specified user in the memcache.

  Args:
    sidebar: the sidebar to be cached
  """

  # Store sidebar for just three minutes to force a refresh every so often
  retention = 3*60
  # pylint: disable-msg=E1101
  memcache.add(memcache_key, sidebar, retention)

def flush(id=None):
  """Removes the sidebar for the current user from the memcache.

  Also calls soc.cache.rights.flush for the specified user.

  Args:
    id: defaults to the current account if not set
  """

  if not id:
    id = soc.logic.accounts.getCurrentAccount()

  memcache_key = key(id)
  # pylint: disable-msg=E1101
  memcache.delete(memcache_key)
  soc.cache.rights.flush(id)

# define the cache function
cache = soc.cache.base.getCacher(get, put)
<commit_msg>Fix sidebar caching<commit_after>#!/usr/bin/env python2.5
#
# Copyright 2009 the Melange authors.
#
# 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.

"""Module contains sidebar memcaching functions.
"""

__authors__ = [
    '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]

from google.appengine.api import memcache

import soc.cache.base
import soc.cache.rights
import soc.logic.accounts

def key(id):
  """Returns the memcache key for the user's sidebar.
  """

  return 'sidebar_for_%s' % repr(id)

def get(core, id, *args, **kwargs):
  """Retrieves the sidebar for the specified user from the memcache.
  """

  memcache_key = key(id)
  # pylint: disable-msg=E1101
  return memcache.get(memcache_key), memcache_key

def put(sidebar, memcache_key, core, *args, **kwargs):
  """Sets the sidebar for the specified user in the memcache.

  Args:
    sidebar: the sidebar to be cached
  """

  # Store sidebar for just three minutes to force a refresh every so often
  retention = 3*60
  # pylint: disable-msg=E1101
  memcache.add(memcache_key, sidebar, retention)

def flush(id=None):
  """Removes the sidebar for the current user from the memcache.

  Also calls soc.cache.rights.flush for the specified user.

  Args:
    id: defaults to the current account if not set
  """

  if not id:
    id = soc.logic.accounts.getCurrentAccount()

  memcache_key = key(id)
  # pylint: disable-msg=E1101
  memcache.delete(memcache_key)
  soc.cache.rights.flush(id)

# define the cache function
cache = soc.cache.base.getCacher(get, put)
<|endoftext|>


<commit_before>import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
import random
from matplotlib.patches import Polygon, PathPatch
from matplotlib.collections import PatchCollection
from mpl_toolkits.basemap import Basemap
import json
import zipfile
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import io
import zipfile
import csv
import sys

fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(111, axisbg='w', frame_on=False)
fig.suptitle('PUMA Shapefiles: An Example with Basemap', fontsize=20)

# create a map object with the Albert Equal Areas projection.
# This projection tends to look nice for the contiguous us.
m = Basemap(width=5000000,height=3500000,
            resolution='l',projection='aea',\
            lat_1=30.,lat_2=50,lon_0=-96,lat_0=38# state codes from http://www2.census.gov/programs-surveys/acs/tech_docs/pums/data_dict/PUMSDataDict13.txt
# note that areas outside of the conus have been commented out
state_codes = {'01': 'Alabama',
            #   '02': 'Alaska',
               '04': 'Arizona',
               '05': 'Arkansas',
               '06': 'California',
               '08': 'Colorado',
               '09': 'Connecticut',
               '10': 'Delaware',
               '11': 'District of Columbia',
               '12': 'Florida',
               '13': 'Georgia',
               '15': 'Hawaii',
               '16': 'Idaho',
               '17': 'Illinois',
               '18': 'Indiana',
               '19': 'Iowa',
               '20': 'Kansas',
               '21': 'Kentucky',
               '22': 'Louisiana',
               '23': 'Maine',
               '24': 'Maryland',
               '25': 'Massachusetts',
               '26': 'Michigan',
               '27': 'Minnesota',
               '28': 'Mississippi',
               '29': 'Missouri',
               '30': 'Montana',
               '31': 'Nebraska',
               '32': 'Nevada',
               '33': 'New Hampshire',
               '34': 'New Jersey',
               '35': 'New Mexico',
               '36': 'New York',
               '37': 'North Carolina',
               '38': 'North Dakota',
               '39': 'Ohio',
               '40': 'Oklahoma',
               '41': 'Oregon',
               '42': 'Pennsylvania',
               '44': 'Rhode Island',
               '45': 'South Carolina',
               '46': 'South Dakota',
               '47': 'Tennessee',
               '48': 'Texas',
               '49': 'Utah',
               '50': 'Vermont',
               '51': 'Virginia',
               '53': 'Washington',
               '54': 'West Virginia',
               '55': 'Wisconsin',
               '56': 'Wyoming',
            #   '72': 'Puerto Rico'
               }

# define a colorramp
num_colors = 12
cm = plt.get_cmap('Blues')
blues = [cm(1.*i/num_colors) for i in range(num_colors)]

# add colorbar legend
cmap = mpl.colors.ListedColormap(blues)
# define the bins
bounds = np.linspace(0.0, 1.0, num_colors)

# read each states shapefile
for key in state_codes.keys():
    m.readshapefile('../input/shapefiles/pums/tl_2013_{0}_puma10'.format(key),
                    name='state', drawbounds=True, default_encoding='latin-1')

    # loop through each PUMA and assign a random color from our colorramp
    for info, shape in zip(m.state_info, m.state):
        patches = [Polygon(np.array(shape), True)]
        pc = PatchCollection(patches, edgecolor='k', linewidths=1., zorder=2)
        pc.set_color(random.choice(blues))
        ax.add_collection(pc)

# create a second axes for the colorbar
ax2 = fig.add_axes([0.82, 0.1, 0.03, 0.8])
cb = mpl.colorbar.ColorbarBase(ax2, cmap=cmap, ticks=bounds, boundaries=bounds,
                               format='%1i')
cb.ax.set_yticklabels([str(round(i, 2)) for i in bounds])

plt.savefig('map.png')

<commit_msg>subplot added for Alaska<commit_after>import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
import random
from matplotlib.patches import Polygon, PathPatch
from matplotlib.collections import PatchCollection
from mpl_toolkits.basemap import Basemap
import json
import zipfile
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import io
import zipfile
import csv
import sys

def find_nearest_ind(array,value):
    idx = (np.abs(array-value)).argmin()
    return idx

# http://stackoverflow.com/questions/17458580/embedding-small-plots-inside-subplots-in-matplotlib/17479417#17479417
def add_subplot_axes(ax,rect):
    fig = plt.gcf()
    box = ax.get_position()
    width = box.width
    height = box.height
    inax_position  = ax.transAxes.transform(rect[0:2])
    transFigure = fig.transFigure.inverted()
    infig_position = transFigure.transform(inax_position)
    x = infig_position[0]
    y = infig_position[1]
    width *= rect[2]
    height *= rect[3]
    subax = fig.add_axes([x,y,width,height],frameon=False)
    return subax

fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(111, axisbg='w', frame_on=False)
fig.suptitle('PUMA Shapefiles: An Example with Basemap', fontsize=20)

# create a map object with the Albert Equal Areas projection.
# This projection tends to look nice for the contiguous us.
m = Basemap(width=5000000,height=3500000,
            resolution='l',projection='aea',\
            lat_1=30.,lat_2=50,lon_0=-96,lat_0=38# state codes from http://www2.census.gov/programs-surveys/acs/tech_docs/pums/data_dict/PUMSDataDict13.txt
# note that areas outside of the conus have been commented out
state_codes = {'01': 'Alabama',
            #   '02': 'Alaska',
               '04': 'Arizona',
               '05': 'Arkansas',
               '06': 'California',
               '08': 'Colorado',
               '09': 'Connecticut',
               '10': 'Delaware',
               '11': 'District of Columbia',
               '12': 'Florida',
               '13': 'Georgia',
               '15': 'Hawaii',
               '16': 'Idaho',
               '17': 'Illinois',
               '18': 'Indiana',
               '19': 'Iowa',
               '20': 'Kansas',
               '21': 'Kentucky',
               '22': 'Louisiana',
               '23': 'Maine',
               '24': 'Maryland',
               '25': 'Massachusetts',
               '26': 'Michigan',
               '27': 'Minnesota',
               '28': 'Mississippi',
               '29': 'Missouri',
               '30': 'Montana',
               '31': 'Nebraska',
               '32': 'Nevada',
               '33': 'New Hampshire',
               '34': 'New Jersey',
               '35': 'New Mexico',
               '36': 'New York',
               '37': 'North Carolina',
               '38': 'North Dakota',
               '39': 'Ohio',
               '40': 'Oklahoma',
               '41': 'Oregon',
               '42': 'Pennsylvania',
               '44': 'Rhode Island',
               '45': 'South Carolina',
               '46': 'South Dakota',
               '47': 'Tennessee',
               '48': 'Texas',
               '49': 'Utah',
               '50': 'Vermont',
               '51': 'Virginia',
               '53': 'Washington',
               '54': 'West Virginia',
               '55': 'Wisconsin',
               '56': 'Wyoming',
            #   '72': 'Puerto Rico'
               }

# define a colorramp
num_colors = 12
cm = plt.get_cmap('Blues')
blues = [cm(1.*i/num_colors) for i in range(num_colors)]

# add colorbar legend
cmap = mpl.colors.ListedColormap(blues)
# define the bins
bounds = np.linspace(0.0, 1.0, num_colors)

# read each states shapefile
for key in state_codes.keys():
    m.readshapefile('../input/shapefiles/pums/tl_2013_{0}_puma10'.format(key),
                    name='state', drawbounds=True, default_encoding='latin-1')

    # loop through each PUMA and assign a random color from our colorramp
    for info, shape in zip(m.state_info, m.state):
        patches = [Polygon(np.array(shape), True)]
        pc = PatchCollection(patches, edgecolor='k', linewidths=1., zorder=2)
        pc.set_color(random.choice(blues))
        ax.add_collection(pc)

# create a second axes for the colorbar
ax2 = fig.add_axes([0.82, 0.1, 0.03, 0.8])
cb = mpl.colorbar.ColorbarBase(ax2, cmap=cmap, ticks=bounds, boundaries=bounds,
                               format='%1i')
cb.ax.set_yticklabels([str(round(i, 2)) for i in bounds])

plt.savefig('map.png')

<|endoftext|>