<commit_before>import json
import logging
import copy

from scrapi import tasks
from scrapi import settings
from scrapi.events import log_to_sentry
from scrapi.processing import get_processor
from scrapi.linter import RawDocument, NormalizedDocument

logger = logging.getLogger()

@tasks.task_autoretry(default_retry_delay=30, max_retries=5)
def rename(docs, target=None, **kwargs):
    assert target, "To run this migration you need a target."

    for doc in docs:
        new_doc = copy.copy(doc.attributes)
        new_doc['source'] = target

        raw = RawDocument(new_doc, validate=False)

        assert doc.attributes['source'] != target, "Can't rename {} to {}, names are the same.".format(doc['source'], target)

        if not kwargs.get('dry'):
            tasks.process_raw(raw)
            tasks.process_normalized(tasks.normalize(raw, raw['source']), raw)
            logger.info('Processed document from {} with id {}'.format(doc.attributes['source'], raw['docID']))

            es_processor = get_processor('elasticsearch')
            es_processor.manager.es.delete(index=settings.ELASTIC_INDEX, doc_type=doc.attributes['source'], id=raw['docID'], ignore=[404])
            es_processor.manager.es.delete(index='share_v1', doc_type=doc.attributes['source'], id=raw['docID'], ignore=[404])

        logger.info('Renamed document from {} to {} with id {}'.format(doc.attributes['source'], target, raw['docID']))

@tasks.task_autoretry(default_retry_delay=30, max_retries=5)
def cross_db(docs, target_db=None, index=None, **kwargs):
    """
    Migration to go between cassandra > postgres, or cassandra > elasticsearch.
    TODO - make this source_db agnostic. Should happen along with larger migration refactor
    """
    assert target_db, 'Please specify a target db for the migration -- either postgres or elasticsearch'
    # assert target_db in ['postgres', 'elasticsearch'], 'Invalid target database - please specify either postgres or elasticsearch'

    for doc in docs:

        if not doc.doc:
            # corrupted database item has no doc element
            message = 'Could not migrate document from {} with id {}'.format(doc.source, doc.docID)
            log_to_sentry(message)
            logger.info(message)
            continue

        raw = RawDocument({
            'doc': doc.doc,
            'docID': doc.docID,
            'source': doc.source,
            'filetype': doc.filetype,
            'timestamps': doc.timestamps,
            'versions': doc.versions
        }, validate=False)

        normed = doc_to_normed_dict(doc)

        # Create the normalized, don't validate b/c its been done once already
        normalized = NormalizedDocument(normed, validate=False)

        processor = get_processor(target_db)

        if not kwargs.get('dry'):
            processor.process_raw(raw)

            try:
                if target_db == 'elasticsearch':
                    processor.process_normalized(raw, normalized, index=index)
                else:
                    processor.process_normalized(raw, normalized)
            except KeyError:
                # This means that the document was harvested but wasn't approved to be normalized
                logger.info('Not storing migrated normalized from {} with id {}, document is not in approved set list.'.format(doc.source, doc.docID))

@tasks.task_autoretry(default_retry_delay=1, max_retries=5)
def renormalize(docs, *args, **kwargs):
    for doc in docs:
        if not kwargs.get('dry'):
            tasks.process_normalized(tasks.normalize(doc, doc['source']), doc)

@tasks.task_autoretry(default_retry_delay=30, max_retries=5)
def delete(docs, sources=None, **kwargs):
    for doc in docs:
        assert sources, "To run this migration you need a source."

        processor = get_processor(settings.CANONICAL_PROCESSOR)
        processor.document_delete(source=doc.attributes['source'], docID=doc.attributes['docID'])

        es_processor = get_processor('elasticsearch')
        es_processor.manager.es.delete(index=settings.ELASTIC_INDEX, doc_type=sources, id=doc.attributes['docID'], ignore=[404])
        es_processor.manager.es.delete(index='share_v1', doc_type=sources, id=doc.attributes['docID'], ignore=[404])

        logger.info('Deleted document from {} with id {}'.format(sources, doc.attributes['docID']))

def doc_to_normed_dict(doc):
    # make the new dict actually contain real items
    normed = {}
    for key, value in dict(doc).items():
        try:
            normed[key] = json.loads(value)
        except (ValueError, TypeError):
            normed[key] = value

    # Remove empty values and strip down to only normalized fields
    do_not_include = ['docID', 'doc', 'filetype', 'timestamps', 'source']
    for key in list(normed.keys()):
        if not normed[key]:
            del normed[key]

    for key in list(normed.keys()):
        if key in do_not_include:
            del normed[key]

    if normed.get('versions'):
        normed['versions'] = list(map(str, normed['versions']))

    # No datetime means the document wasn't normalized (probably wasn't on the approved list)
    if normed.get('providerUpdatedDateTime'):
        normed['providerUpdatedDateTime'] = normed['providerUpdatedDateTime'].isoformat()

    return normed
<commit_msg>Fix migrations for new DocTuple for rename<commit_after>import json
import logging
import copy

from scrapi import tasks
from scrapi import settings
from scrapi.events import log_to_sentry
from scrapi.processing import get_processor
from scrapi.linter import RawDocument, NormalizedDocument

logger = logging.getLogger()

@tasks.task_autoretry(default_retry_delay=30, max_retries=5)
def rename(docs, target=None, **kwargs):
    assert target, "To run this migration you need a target."

    for doc in docs:
        raw_doc = doc.raw
        new_doc = copy.copy(raw_doc.attributes)
        new_doc['source'] = target

        raw = RawDocument(new_doc, validate=False)

        assert raw_doc.attributes['source'] != target, "Can't rename {} to {}, names are the same.".format(raw_doc['source'], target)

        if not kwargs.get('dry'):
            tasks.process_raw(raw)
            tasks.process_normalized(tasks.normalize(raw, raw['source']), raw)
            logger.info('Processed document from {} with id {}'.format(raw_doc.attributes['source'], raw['docID']))

            es_processor = get_processor('elasticsearch')
            es_processor.manager.es.delete(index=settings.ELASTIC_INDEX, doc_type=raw_doc.attributes['source'], id=raw['docID'], ignore=[404])
            es_processor.manager.es.delete(index='share_v1', doc_type=raw_doc.attributes['source'], id=raw['docID'], ignore=[404])

        logger.info('Renamed document from {} to {} with id {}'.format(raw_doc.attributes['source'], target, raw['docID']))

@tasks.task_autoretry(default_retry_delay=30, max_retries=5)
def cross_db(docs, target_db=None, index=None, **kwargs):
    """
    Migration to go between cassandra > postgres, or cassandra > elasticsearch.
    TODO - make this source_db agnostic. Should happen along with larger migration refactor
    """
    assert target_db, 'Please specify a target db for the migration -- either postgres or elasticsearch'
    # assert target_db in ['postgres', 'elasticsearch'], 'Invalid target database - please specify either postgres or elasticsearch'

    for doc in docs:

        if not doc.doc:
            # corrupted database item has no doc element
            message = 'Could not migrate document from {} with id {}'.format(doc.source, doc.docID)
            log_to_sentry(message)
            logger.info(message)
            continue

        raw = RawDocument({
            'doc': doc.doc,
            'docID': doc.docID,
            'source': doc.source,
            'filetype': doc.filetype,
            'timestamps': doc.timestamps,
            'versions': doc.versions
        }, validate=False)

        normed = doc_to_normed_dict(doc)

        # Create the normalized, don't validate b/c its been done once already
        normalized = NormalizedDocument(normed, validate=False)

        processor = get_processor(target_db)

        if not kwargs.get('dry'):
            processor.process_raw(raw)

            try:
                if target_db == 'elasticsearch':
                    processor.process_normalized(raw, normalized, index=index)
                else:
                    processor.process_normalized(raw, normalized)
            except KeyError:
                # This means that the document was harvested but wasn't approved to be normalized
                logger.info('Not storing migrated normalized from {} with id {}, document is not in approved set list.'.format(doc.source, doc.docID))

@tasks.task_autoretry(default_retry_delay=1, max_retries=5)
def renormalize(docs, *args, **kwargs):
    for doc in docs:
        if not kwargs.get('dry'):
            tasks.process_normalized(tasks.normalize(doc, doc['source']), doc)

@tasks.task_autoretry(default_retry_delay=30, max_retries=5)
def delete(docs, sources=None, **kwargs):
    for doc in docs:
        assert sources, "To run this migration you need a source."

        processor = get_processor(settings.CANONICAL_PROCESSOR)
        processor.delete(source=doc.attributes['source'], docID=doc.attributes['docID'])

        es_processor = get_processor('elasticsearch')
        es_processor.manager.es.delete(index=settings.ELASTIC_INDEX, doc_type=sources, id=doc.attributes['docID'], ignore=[404])
        es_processor.manager.es.delete(index='share_v1', doc_type=sources, id=doc.attributes['docID'], ignore=[404])

        logger.info('Deleted document from {} with id {}'.format(sources, doc.attributes['docID']))

def doc_to_normed_dict(doc):
    # make the new dict actually contain real items
    normed = {}
    for key, value in dict(doc).items():
        try:
            normed[key] = json.loads(value)
        except (ValueError, TypeError):
            normed[key] = value

    # Remove empty values and strip down to only normalized fields
    do_not_include = ['docID', 'doc', 'filetype', 'timestamps', 'source']
    for key in list(normed.keys()):
        if not normed[key]:
            del normed[key]

    for key in list(normed.keys()):
        if key in do_not_include:
            del normed[key]

    if normed.get('versions'):
        normed['versions'] = list(map(str, normed['versions']))

    # No datetime means the document wasn't normalized (probably wasn't on the approved list)
    if normed.get('providerUpdatedDateTime'):
        normed['providerUpdatedDateTime'] = normed['providerUpdatedDateTime'].isoformat()

    return normed
<|endoftext|>


<commit_before>import os
import unittest
from base_test import BaseTest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.select import Select

class DiffTest(BaseTest, unittest.TestCase):

    def job_name(self):
        return 'Diff test'

    def get_drawer_button(self):
        return self.driver.find_element_by_xpath('//*[@id="timeline-link"]')

    def test_diffs(self):
        self.driver.get('http://localhost:8000/1005-2/2011-11111')
        html = self.driver.find_element_by_tag_name('html')
        WebDriverWait(self.driver, 30).until(
            lambda driver: 'selenium-start' in html.get_attribute('class'))

        WebDriverWait(self.driver, 50)
        drawer_button = self.get_drawer_button()
        drawer_button.click()

        WebDriverWait(self.driver, 60).until(
            lambda driver: driver.find_element_by_css_selector('#timeline:not(.hidden)'))

        # drawer button should be active
        self.assertTrue('current' in drawer_button.get_attribute('class'))

        diff_field = Select(self.driver.find_element_by_xpath('//*[@id="timeline"]/div[2]/ul/li[1]/div/div/div/form/select'))
        # select version to compare to
        diff_field.select_by_value('2012-12121')

        # wait until diff view has loaded w/ JS
        WebDriverWait(self.driver, 30).until(
             lambda driver: driver.find_element_by_css_selector('html.js'))

        WebDriverWait(self.driver, 60)
        # make sure the url is right
        self.assertTrue(self.driver.current_url == 'http://localhost:8000/diff/1005-2/2012-12121/2011-11111?from_version=2011-11111')

        WebDriverWait(self.driver, 60)

        # open diff pane in drawer
        active_drawer_button = self.get_drawer_button()
        active_drawer_button.click()
        WebDriverWait(self.driver, 60).until(
            lambda driver: 'current' in active_drawer_button.get_attribute('class'))

        # navigate to 1005.3
        self.driver.find_element_by_id('menu-link').click()
        WebDriverWait(self.driver, 10).until(
            lambda driver: 'current' in driver.find_element_by_id('table-of-contents').get_attribute('class'))
        toc_link_1005_3 = self.driver.find_element_by_xpath('//*[@id="toc"]/ol/li[3]')
        # drawer should have green bar
        self.assertTrue('modified' in toc_link_1005_3.get_attribute('class'))
        toc_link_1005_3.click()

        # wait until 1005.3 diff loads
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.current_url == 'http://localhost:8000/diff/1005-3/2012-12121/2011-11111?from_version=2011-11111')

        # make sure new section is greened
        new_section = self.driver.find_element_by_xpath('//*[@id="1005-3-b-1-vi"]')
        self.assertTrue(new_section.find_element_by_tag_name('ins'))

        # make sure changed paragraph has insertions and deletions
        changed_section = self.driver.find_element_by_xpath('//*[@id="1005-3-b-2-ii"]')
        self.assertTrue(len(changed_section.find_elements_by_tag_name('ins')) == 2)
        self.assertTrue(len(changed_section.find_elements_by_tag_name('del')))

        # go back into diff pane in drawer, stop comparing
        self.get_drawer_button().click()
        stop_button = self.driver.find_element_by_xpath('//*[@id="timeline"]/div[2]/ul/li[2]/div/a')
        stop_button.click()

        # make sure it goes back to the right place
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.current_url == 'http://localhost:8000/1005-3/2011-11111')

if __name__ == '__main__':
    unittest.main()
<commit_msg>apparently the diff test needs a little extra time<commit_after>import os
import unittest
from base_test import BaseTest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.select import Select

class DiffTest(BaseTest, unittest.TestCase):

    def job_name(self):
        return 'Diff test'

    def get_drawer_button(self):
        return self.driver.find_element_by_xpath('//*[@id="timeline-link"]')

    def test_diffs(self):
        self.driver.get('http://localhost:8000/1005-2/2011-11111')
        html = self.driver.find_element_by_tag_name('html')
        WebDriverWait(self.driver, 60).until(
            lambda driver: 'selenium-start' in html.get_attribute('class'))

        WebDriverWait(self.driver, 50)
        drawer_button = self.get_drawer_button()
        drawer_button.click()

        WebDriverWait(self.driver, 60).until(
            lambda driver: driver.find_element_by_css_selector('#timeline:not(.hidden)'))

        # drawer button should be active
        self.assertTrue('current' in drawer_button.get_attribute('class'))

        diff_field = Select(self.driver.find_element_by_xpath('//*[@id="timeline"]/div[2]/ul/li[1]/div/div/div/form/select'))
        # select version to compare to
        diff_field.select_by_value('2012-12121')

        # wait until diff view has loaded w/ JS
        WebDriverWait(self.driver, 30).until(
             lambda driver: driver.find_element_by_css_selector('html.js'))

        WebDriverWait(self.driver, 60)
        # make sure the url is right
        self.assertTrue(self.driver.current_url == 'http://localhost:8000/diff/1005-2/2012-12121/2011-11111?from_version=2011-11111')

        WebDriverWait(self.driver, 60)

        # open diff pane in drawer
        active_drawer_button = self.get_drawer_button()
        active_drawer_button.click()
        WebDriverWait(self.driver, 60).until(
            lambda driver: 'current' in active_drawer_button.get_attribute('class'))

        # navigate to 1005.3
        self.driver.find_element_by_id('menu-link').click()
        WebDriverWait(self.driver, 10).until(
            lambda driver: 'current' in driver.find_element_by_id('table-of-contents').get_attribute('class'))
        toc_link_1005_3 = self.driver.find_element_by_xpath('//*[@id="toc"]/ol/li[3]')
        # drawer should have green bar
        self.assertTrue('modified' in toc_link_1005_3.get_attribute('class'))
        toc_link_1005_3.click()

        # wait until 1005.3 diff loads
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.current_url == 'http://localhost:8000/diff/1005-3/2012-12121/2011-11111?from_version=2011-11111')

        # make sure new section is greened
        new_section = self.driver.find_element_by_xpath('//*[@id="1005-3-b-1-vi"]')
        self.assertTrue(new_section.find_element_by_tag_name('ins'))

        # make sure changed paragraph has insertions and deletions
        changed_section = self.driver.find_element_by_xpath('//*[@id="1005-3-b-2-ii"]')
        self.assertTrue(len(changed_section.find_elements_by_tag_name('ins')) == 2)
        self.assertTrue(len(changed_section.find_elements_by_tag_name('del')))

        # go back into diff pane in drawer, stop comparing
        self.get_drawer_button().click()
        stop_button = self.driver.find_element_by_xpath('//*[@id="timeline"]/div[2]/ul/li[2]/div/a')
        stop_button.click()

        # make sure it goes back to the right place
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.current_url == 'http://localhost:8000/1005-3/2011-11111')

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


<commit_before>__version__ = '0.3.2'
<commit_msg>scrapydd v0.3.3<commit_after>__version__ = '0.3.3'
<|endoftext|>


<commit_before># Copyright 2018 Google LLC
#
# 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
#
#     https://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.

import getpass
import re
from typing import Union

import click
from requests import HTTPError

import releasetool.circleci
import releasetool.git
import releasetool.github
import releasetool.secrets
import releasetool.commands.common
from releasetool.commands.common import TagContext

# Standard Ruby repos in the googleapis org
RUBY_CLIENT_REPOS = [
    "common-protos-ruby",
    "gapic-generator-ruby",
    "google-api-ruby-client",
    "google-auth-library-ruby",
    "google-cloud-ruby",
    "ruby-cloud-env",
    "ruby-spanner-activerecord",
    "ruby-style",
    "signet",
]

# Standard Ruby repos in the GoogleCloudPlatform org
RUBY_CLOUD_REPOS = [
    "appengine-ruby",
    "functions-framework-ruby",
    "serverless-exec-ruby",
]

# Standard Ruby monorepos with gems located in subdirectories
RUBY_MONO_REPOS = [
    "common-protos-ruby",
    "gapic-generator-ruby",
    "google-api-ruby-client",
    "google-cloud-ruby",
]

def determine_release_pr(ctx: TagContext) -> None:
    click.secho(
        "> Let's figure out which pull request corresponds to your release.", fg="cyan"
    )

    pulls = ctx.github.list_pull_requests(ctx.upstream_repo, state="closed")
    pulls = [pull for pull in pulls if "release" in pull["title"].lower()][:30]

    click.secho("> Please pick one of the following PRs:\n")
    for n, pull in enumerate(pulls, 1):
        print(f"\t{n}: {pull['title']} ({pull['number']})")

    pull_idx = click.prompt(
        "\nWhich one do you want to tag and release?", type=click.INT
    )

    ctx.release_pr = pulls[pull_idx - 1]

def determine_release_tag(ctx: TagContext) -> None:
    click.secho("> Determining the release tag.", fg="cyan")
    head_ref = ctx.release_pr["head"]["ref"]
    click.secho(f"PR head ref is {head_ref}")
    match = re.match(r"release-(.+)-v(\d+\.\d+\.\d+)", head_ref)
    rp13_match = re.match(r"release-please--branches--(.+)--components--(.+)", head_ref)
    title_match = re.match(
        r"chore\(.+\): release (.+) (\d+\.\d+\.\d+)", ctx.release_pr["title"]
    )

    if match is not None:
        ctx.package_name = match.group(1)
        ctx.release_version = match.group(2)
        ctx.release_tag = f"{ctx.package_name}/v{ctx.release_version}"
    elif rp13_match is not None and title_match is not None:
        ctx.package_name = title_match.group(1)
        ctx.release_version = title_match.group(2)
        ctx.release_tag = f"{ctx.package_name}/v{ctx.release_version}"

    if ctx.release_tag is None:
        click.secho(
            "I couldn't determine what the release tag should be from the PR's "
            f"head ref {head_ref}.",
            fg="red",
        )
        ctx.release_tag = click.prompt(
            "What should the release tag be (for example, google-cloud-storage/v1.2.3)?"
        )

    click.secho(f"Package name is {ctx.package_name}")
    click.secho(f"Package version is {ctx.release_version}")
    click.secho(f"Release tag is {ctx.release_tag}")

def determine_package_name_and_version(ctx: TagContext) -> None:
    click.secho(
        "> Determining the package name and version from your release tag.", fg="cyan"
    )
    match = re.match(r"^([a-z0-9-_]+)\/v(\d+.\d+.\d+)$", ctx.release_tag)
    ctx.package_name = match.group(1)
    ctx.release_version = match.group(2)

def get_release_notes(ctx: TagContext) -> None:
    click.secho("> Grabbing the release notes.", fg="cyan")
    changelog_file = "CHANGELOG.md"
    for name in RUBY_MONO_REPOS:
        if name in ctx.upstream_repo:
            changelog_file = f"{ctx.package_name}/CHANGELOG.md"
    changelog = ctx.github.get_contents(
        ctx.upstream_repo, changelog_file, ref=ctx.release_pr["merge_commit_sha"]
    ).decode("utf-8")

    match = re.search(
        rf"^### {ctx.release_version} \/ \d\d\d\d-\d\d-\d\d\n(?P<notes>.+?)(\n###\s|\Z)",
        changelog,
        re.DOTALL | re.MULTILINE,
    )
    v13_match = re.search(
        rf"^### {ctx.release_version} \(\d\d\d\d-\d\d-\d\d\)\n(?P<notes>.+?)(\n###\s|\Z)",
        changelog,
        re.DOTALL | re.MULTILINE,
    )
    if match is not None:
        ctx.release_notes = match.group("notes").strip()
    elif v13_match is not None:
        ctx.release_notes = v13_match.group("notes").strip()
    else:
        ctx.release_notes = ""

    click.secho(f"Here's the release notes:\n\n{ctx.release_notes}\n")

def create_release(ctx: TagContext) -> None:
    click.secho("> Creating the release.")
    click.secho(f"pkg={ctx.package_name} pr={ctx.release_pr['number']}")

    ctx.github_release = ctx.github.create_release(
        repository=ctx.upstream_repo,
        tag_name=ctx.release_tag,
        target_commitish=ctx.release_pr["merge_commit_sha"],
        name=f"Release {ctx.package_name} {ctx.release_version}",
        body=ctx.release_notes,
    )

    release_location_string = f"Release is at {ctx.github_release['html_url']}"
    click.secho(release_location_string)
    click.secho("CI will handle publishing the package to Rubygems.")

    ctx.github.create_pull_request_comment(
        ctx.upstream_repo, ctx.release_pr["number"], release_location_string
    )

    ctx.github.update_pull_labels(
        ctx.release_pr, add=["autorelease: tagged"], remove=["autorelease: pending"]
    )

def kokoro_job_name(upstream_repo: str, package_name: str) -> Union[str, None]:
    """Return the Kokoro job name.

    Args:
        upstream_repo (str): The GitHub repo in the form of `<owner>/<repo>`
        package_name (str): The name of package to release

    Returns:
        The name of the Kokoro job to trigger or None if there is no job to trigger
    """

    for name in RUBY_CLIENT_REPOS:
        if name in upstream_repo:
            return f"cloud-devrel/client-libraries/{name}/release"
    for name in RUBY_CLOUD_REPOS:
        if name in upstream_repo:
            return f"cloud-devrel/ruby/{name}/release"

    return f"cloud-devrel/client-libraries/{package_name}/release"

def package_name(pull: dict) -> Union[str, None]:
    head_ref = pull["head"]["ref"]
    click.secho(f"PR head ref is {head_ref}")
    match = re.match(r"release-(.+)-v(\d+\.\d+\.\d+)", head_ref)
    if match is None:
        return None

    return match.group(1)

def tag(ctx: TagContext = None) -> TagContext:
    if not ctx:
        ctx = TagContext()

    if ctx.interactive:
        click.secho(
            f"o/ Hey, {getpass.getuser()}, let's tag a Ruby release!", fg="magenta"
        )

    if ctx.github is None:
        releasetool.commands.common.setup_github_context(ctx)

    if ctx.release_pr is None:
        determine_release_pr(ctx)

    determine_release_tag(ctx)
    determine_package_name_and_version(ctx)

    # If the release already exists, don't do anything
    if releasetool.commands.common.release_exists(ctx):
        click.secho(f"{ctx.release_tag} already exists.", fg="magenta")
        return ctx

    get_release_notes(ctx)

    create_release(ctx)
    ctx.kokoro_job_name = kokoro_job_name(ctx.upstream_repo, ctx.package_name)

    releasetool.commands.common.publish_via_kokoro(ctx)

    if ctx.interactive:
        click.secho("\\o/ All done!", fg="magenta")

    branch = ctx.release_pr["head"]["ref"]

    try:
        ctx.github.delete_branch(repository=ctx.upstream_repo, branch=branch)
        click.secho(f"Deleted branch {branch}")
    # If user has already deleted the branch, this will fail.
    except HTTPError as exc:
        if exc.response.status_code != 422:
            click.secho(f"{exc!r}")

    return ctx
<commit_msg>feat(ruby): Add new repo ruby-spanner to Ruby client and mono repos (#450)<commit_after># Copyright 2018 Google LLC
#
# 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
#
#     https://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.

import getpass
import re
from typing import Union

import click
from requests import HTTPError

import releasetool.circleci
import releasetool.git
import releasetool.github
import releasetool.secrets
import releasetool.commands.common
from releasetool.commands.common import TagContext

# Standard Ruby repos in the googleapis org
RUBY_CLIENT_REPOS = [
    "common-protos-ruby",
    "gapic-generator-ruby",
    "google-api-ruby-client",
    "google-auth-library-ruby",
    "google-cloud-ruby",
    "ruby-cloud-env",
    "ruby-spanner",
    "ruby-spanner-activerecord",
    "ruby-style",
    "signet",
]

# Standard Ruby repos in the GoogleCloudPlatform org
RUBY_CLOUD_REPOS = [
    "appengine-ruby",
    "functions-framework-ruby",
    "serverless-exec-ruby",
]

# Standard Ruby monorepos with gems located in subdirectories
RUBY_MONO_REPOS = [
    "common-protos-ruby",
    "gapic-generator-ruby",
    "google-api-ruby-client",
    "google-cloud-ruby",
    "ruby-spanner",
]

def determine_release_pr(ctx: TagContext) -> None:
    click.secho(
        "> Let's figure out which pull request corresponds to your release.", fg="cyan"
    )

    pulls = ctx.github.list_pull_requests(ctx.upstream_repo, state="closed")
    pulls = [pull for pull in pulls if "release" in pull["title"].lower()][:30]

    click.secho("> Please pick one of the following PRs:\n")
    for n, pull in enumerate(pulls, 1):
        print(f"\t{n}: {pull['title']} ({pull['number']})")

    pull_idx = click.prompt(
        "\nWhich one do you want to tag and release?", type=click.INT
    )

    ctx.release_pr = pulls[pull_idx - 1]

def determine_release_tag(ctx: TagContext) -> None:
    click.secho("> Determining the release tag.", fg="cyan")
    head_ref = ctx.release_pr["head"]["ref"]
    click.secho(f"PR head ref is {head_ref}")
    match = re.match(r"release-(.+)-v(\d+\.\d+\.\d+)", head_ref)
    rp13_match = re.match(r"release-please--branches--(.+)--components--(.+)", head_ref)
    title_match = re.match(
        r"chore\(.+\): release (.+) (\d+\.\d+\.\d+)", ctx.release_pr["title"]
    )

    if match is not None:
        ctx.package_name = match.group(1)
        ctx.release_version = match.group(2)
        ctx.release_tag = f"{ctx.package_name}/v{ctx.release_version}"
    elif rp13_match is not None and title_match is not None:
        ctx.package_name = title_match.group(1)
        ctx.release_version = title_match.group(2)
        ctx.release_tag = f"{ctx.package_name}/v{ctx.release_version}"

    if ctx.release_tag is None:
        click.secho(
            "I couldn't determine what the release tag should be from the PR's "
            f"head ref {head_ref}.",
            fg="red",
        )
        ctx.release_tag = click.prompt(
            "What should the release tag be (for example, google-cloud-storage/v1.2.3)?"
        )

    click.secho(f"Package name is {ctx.package_name}")
    click.secho(f"Package version is {ctx.release_version}")
    click.secho(f"Release tag is {ctx.release_tag}")

def determine_package_name_and_version(ctx: TagContext) -> None:
    click.secho(
        "> Determining the package name and version from your release tag.", fg="cyan"
    )
    match = re.match(r"^([a-z0-9-_]+)\/v(\d+.\d+.\d+)$", ctx.release_tag)
    ctx.package_name = match.group(1)
    ctx.release_version = match.group(2)

def get_release_notes(ctx: TagContext) -> None:
    click.secho("> Grabbing the release notes.", fg="cyan")
    changelog_file = "CHANGELOG.md"
    for name in RUBY_MONO_REPOS:
        if name in ctx.upstream_repo:
            changelog_file = f"{ctx.package_name}/CHANGELOG.md"
    changelog = ctx.github.get_contents(
        ctx.upstream_repo, changelog_file, ref=ctx.release_pr["merge_commit_sha"]
    ).decode("utf-8")

    match = re.search(
        rf"^### {ctx.release_version} \/ \d\d\d\d-\d\d-\d\d\n(?P<notes>.+?)(\n###\s|\Z)",
        changelog,
        re.DOTALL | re.MULTILINE,
    )
    v13_match = re.search(
        rf"^### {ctx.release_version} \(\d\d\d\d-\d\d-\d\d\)\n(?P<notes>.+?)(\n###\s|\Z)",
        changelog,
        re.DOTALL | re.MULTILINE,
    )
    if match is not None:
        ctx.release_notes = match.group("notes").strip()
    elif v13_match is not None:
        ctx.release_notes = v13_match.group("notes").strip()
    else:
        ctx.release_notes = ""

    click.secho(f"Here's the release notes:\n\n{ctx.release_notes}\n")

def create_release(ctx: TagContext) -> None:
    click.secho("> Creating the release.")
    click.secho(f"pkg={ctx.package_name} pr={ctx.release_pr['number']}")

    ctx.github_release = ctx.github.create_release(
        repository=ctx.upstream_repo,
        tag_name=ctx.release_tag,
        target_commitish=ctx.release_pr["merge_commit_sha"],
        name=f"Release {ctx.package_name} {ctx.release_version}",
        body=ctx.release_notes,
    )

    release_location_string = f"Release is at {ctx.github_release['html_url']}"
    click.secho(release_location_string)
    click.secho("CI will handle publishing the package to Rubygems.")

    ctx.github.create_pull_request_comment(
        ctx.upstream_repo, ctx.release_pr["number"], release_location_string
    )

    ctx.github.update_pull_labels(
        ctx.release_pr, add=["autorelease: tagged"], remove=["autorelease: pending"]
    )

def kokoro_job_name(upstream_repo: str, package_name: str) -> Union[str, None]:
    """Return the Kokoro job name.

    Args:
        upstream_repo (str): The GitHub repo in the form of `<owner>/<repo>`
        package_name (str): The name of package to release

    Returns:
        The name of the Kokoro job to trigger or None if there is no job to trigger
    """

    for name in RUBY_CLIENT_REPOS:
        if name in upstream_repo:
            return f"cloud-devrel/client-libraries/{name}/release"
    for name in RUBY_CLOUD_REPOS:
        if name in upstream_repo:
            return f"cloud-devrel/ruby/{name}/release"

    return f"cloud-devrel/client-libraries/{package_name}/release"

def package_name(pull: dict) -> Union[str, None]:
    head_ref = pull["head"]["ref"]
    click.secho(f"PR head ref is {head_ref}")
    match = re.match(r"release-(.+)-v(\d+\.\d+\.\d+)", head_ref)
    if match is None:
        return None

    return match.group(1)

def tag(ctx: TagContext = None) -> TagContext:
    if not ctx:
        ctx = TagContext()

    if ctx.interactive:
        click.secho(
            f"o/ Hey, {getpass.getuser()}, let's tag a Ruby release!", fg="magenta"
        )

    if ctx.github is None:
        releasetool.commands.common.setup_github_context(ctx)

    if ctx.release_pr is None:
        determine_release_pr(ctx)

    determine_release_tag(ctx)
    determine_package_name_and_version(ctx)

    # If the release already exists, don't do anything
    if releasetool.commands.common.release_exists(ctx):
        click.secho(f"{ctx.release_tag} already exists.", fg="magenta")
        return ctx

    get_release_notes(ctx)

    create_release(ctx)
    ctx.kokoro_job_name = kokoro_job_name(ctx.upstream_repo, ctx.package_name)

    releasetool.commands.common.publish_via_kokoro(ctx)

    if ctx.interactive:
        click.secho("\\o/ All done!", fg="magenta")

    branch = ctx.release_pr["head"]["ref"]

    try:
        ctx.github.delete_branch(repository=ctx.upstream_repo, branch=branch)
        click.secho(f"Deleted branch {branch}")
    # If user has already deleted the branch, this will fail.
    except HTTPError as exc:
        if exc.response.status_code != 422:
            click.secho(f"{exc!r}")

    return ctx
<|endoftext|>


<commit_before>""" Test sponsor on index. """

from website.tests import TestCase
from model_mommy import mommy
from datetime import datetime, timedelta
import pytz

# class TestIndex(TestCase):

#     """ Test sponsor on index. """

#     def test_index_no_events(self):
#         """ Test it hides there are no events. """
#         response = self.client.get("/")
#         self.assertIsNone(response.soup.find(id="sponsors"))

#     def test_index_no_sponsor(self):
#         """ Test it hides the event has no sponsor. """
#         mommy.make("Event")
#         response = self.client.get("/")
#         self.assertIsNone(response.soup.find(id="sponsors"))

#     def test_index_future_sponsor(self):
#         """ Test it displays correctly when a future event has a sponsor. """
#         mommy.make("Event", datetime=datetime.now(pytz.utc) +
#                    timedelta(days=20), sponsor=mommy.make("Sponsor"))
#         response = self.client.get("/")
#         sponsor_info = response.soup.find(id="sponsors")
#         self.assertIsNotNone(sponsor_info)
#         self.assertTrue("is kindly" in sponsor_info.text)
#         self.assertFalse("was kindly" in sponsor_info.text)

#     def test_index_past_sponsor(self):
#         """ Test it displays correctly when a past event has a sponsor. """
#         mommy.make("Event", datetime=datetime.now(pytz.utc) -
#                    timedelta(days=20), sponsor=mommy.make("Sponsor"))
#         response = self.client.get("/")
#         sponsor_info = response.soup.find(id="sponsors")
#         self.assertIsNotNone(sponsor_info)
#         self.assertTrue("was kindly" in sponsor_info.text)
#         self.assertFalse("is kindly" in sponsor_info.text)
<commit_msg>fix temp tests<commit_after>""" Test sponsor on index. """

# from website.tests import TestCase
# from model_mommy import mommy
# from datetime import datetime, timedelta
# import pytz

# class TestIndex(TestCase):

#     """ Test sponsor on index. """

#     def test_index_no_events(self):
#         """ Test it hides there are no events. """
#         response = self.client.get("/")
#         self.assertIsNone(response.soup.find(id="sponsors"))

#     def test_index_no_sponsor(self):
#         """ Test it hides the event has no sponsor. """
#         mommy.make("Event")
#         response = self.client.get("/")
#         self.assertIsNone(response.soup.find(id="sponsors"))

#     def test_index_future_sponsor(self):
#         """ Test it displays correctly when a future event has a sponsor. """
#         mommy.make("Event", datetime=datetime.now(pytz.utc) +
#                    timedelta(days=20), sponsor=mommy.make("Sponsor"))
#         response = self.client.get("/")
#         sponsor_info = response.soup.find(id="sponsors")
#         self.assertIsNotNone(sponsor_info)
#         self.assertTrue("is kindly" in sponsor_info.text)
#         self.assertFalse("was kindly" in sponsor_info.text)

#     def test_index_past_sponsor(self):
#         """ Test it displays correctly when a past event has a sponsor. """
#         mommy.make("Event", datetime=datetime.now(pytz.utc) -
#                    timedelta(days=20), sponsor=mommy.make("Sponsor"))
#         response = self.client.get("/")
#         sponsor_info = response.soup.find(id="sponsors")
#         self.assertIsNotNone(sponsor_info)
#         self.assertTrue("was kindly" in sponsor_info.text)
#         self.assertFalse("is kindly" in sponsor_info.text)
<|endoftext|>


<commit_before>"""Classes of fundamental atomistic concepts

Representations of fundamental atomistic concepts,
such as energy levels, Atoms,...
Uses ASE's Atoms objects.
"""

import numpy as np
import copy  as cp
from ase.atoms import Atom, Atoms

class EnergyLevel(object):

    """An energy level"""

    def __init__(self, energy, occupation=1.0, wfn=None):
        """Set energy and occupation."""
        self.energy = energy
        self.occupation = occupation
        self.wfn = wfn

class EnergyLevels(object):

    """A list of levels with fermi energy

    Compared to the C++ class,
    - the copy constructor has been renamed to the 'copy' method
    - the get/set methods have been stripped off
    - instead of overloading *=, the levels are exposed to the user
    - removed setFermiZero
    """

    def __init__(self, energies=None, occupations=None, wfns=None, fermi=None):
        """Fill object with levels and Fermi energy."""
        self.levels = []
        self.fermi = fermi

        # If occupations are specified, take them
        if energies is not None and occupations is not None:
            for i in range(len(energies)):
                tmp = EnergyLevel(energies[i], occupations[i])
                self.levels.append(tmp)
        # If we just have a fermi energy, create occupations
        elif energies is not None and fermi is not None:
            for i in range(len(energies)):
                if energies[i] < fermi:
                    tmp = EnergyLevel(energies[i], 1.0)
                else:
                    tmp = EnergyLevel(energies[i], 0.0)

                self.levels.append(tmp)
        # If neither fermi nor occupations are set...
        elif energies is not None:
            for i in range(len(energies)):
                tmp = EnergyLevel(energies[i], None)
                self.levels.append(tmp)

        if wfns is not None:
            if len(wfns) == len(self.levels):
                for i in range(len(wfns)):
                    self.levels[i].wfn = wfns[i]
            else:
                print("Error: Number of wave functions != number or levels")

    @property
    def energies(self):
        return np.array([l.energy for l in self.levels])

    @property
    def occupations(self):
        return np.array([l.occupation for l in self.levels])

    @energies.setter
    def energies(self, es):
        """Sets levels, not touching occupations."""
        if len(self.levels) != len(es):
            print('Error: Trying to set {le} energies for {le} levels.' \
                  .format(lo=len(es), le=len(self.levels)))
            return

        for i in range(len(self.levels)):
            self.levels[i].energy = es[i]

    @occupations.setter
    def occupations(self, os):
        """Sets occupations for existing levels."""

        if len(os) != len(self.levels):
            print('Error: Trying to set {lo} occupations for {le} levels.' \
                  .format(lo=len(os), le=len(self.levels)))
        else:
            for i in range(len(self.levels)):
                self.levels[i].occupation = os[i]

    def copy(self, energylevels):
        """Return a copy of energylevels."""
        self.levels = cp.copy(energylevels.levels)
        self.fermi = energylevels.fermi

    def join(self, energylevels):
        self.levels = self.levels + energylevels.levels
        if self.fermi != energylevels.fermi:
            print('Warning: Merging energy levels'
                  'with different Fermi energies.')
        self.fermi = energylevels.fermi

    def sort(self):
        self.levels.sort(key = lambda x: x.energy)

    def shift(self, de):
        self.energies += de
        self.fermi  += de

    def __iadd__(self, b):
        if isinstance(b, float):
            self.energies += de
            self.fermi  += de
        elif isinstance(b, self.__class__):
            self.levels += b.levels
            self.sort()
            if not self.fermi == b.fermi:
                self.fermi = None
        else:
            raise TypeError("Unsupported operand type(s) for +: '{}' and '{}'")\
                  .format(self.__class__, type(other))

        return self

    def __isub__(self, de):
        self.energies -= de
        self.fermi  -= de
        return self

    def n_occupied(self, epsilon=1e-12):
        """Return number of occupied levels

        Levels with energy at most epsilon above Fermi  still count as occupied.
        This prevents the disregard of occupied levels, when the Fermi energy
        is identical to the highest occupied level.
        """

        if self.fermi:
            return sum([1 if e < self.fermi + epsilon else 0 for e in self.energies])
        elif all(o is not None for o in self.occupations):
            print("Note: Counting occupied levels based on occupation number.")
            return sum([1 if o > 0 else 0 for o in self.occupations])
        else:
            print("Error: Cannot determine occupations.")

    def n_empty(self):
        """Return number of empty levels"""
        return len(levels) - self.n_occupied()

    def __str__(self):
        text  = "{} energy levels".format(len(self.levels))
        if self.fermi:
            text += ", Fermi energy {} eV".format(self.fermi)
        if all(o is not None for o in self.occupations):
            text += ", occupations specified"
        return text

    def __getitem__(self, index):
        return self.levels[index]

    def dos(self, bmethod = 'Gaussian', bepsilon = 1e-3, FWHM = 0.1, delta_e = 0.005):
        """
        Returns [energy, density of states].

        Parameters
        ----------
        bmethod: Method used for broadening ('Gaussian' or 'Lorentzian')
        bepsilon: Convolution is performed with broadening function in range
            [E-Eb, E+Eb] where Eb is determined such that the integrated weight
            of the broadening function outside of [-Eb, Eb] is < bepsilon.
        FWHM: Full-width of broadening function at half-maximum [eV]
        delta_e: spacing of energy grid [eV]
        """

        import scipy.special as scsp
        # Prepare broadening functions for later convolution
        # quantile function quantile(y) = x is defined such that
        # the integral of the probability density from -\infty to x equals y.
        if bmethod == 'Gaussian':
            sigma = FWHM / np.log(8 * np.sqrt(2))
            quantile = lambda y: np.sqrt(2) * scsp.erfinv(2.0*y -1.0) * sigma
            broadening = lambda x: 1/(sigma * np.sqrt(2*np.pi)) \
                                 * np.exp( - x**2 / (2 * sigma**2) )
        elif bmethod == 'Lorentzian':
            gamma = FWHM * 0.5
            quantile = lambda y: np.tan(np.pi * (y - 0.5)) * gamma
            broadening = lambda x: 1/np.pi * gamma / (x**2 + gamma**2)
        else:
            print("Error: Broadening method \"{}\" not recognized."\
                  .format(bmethod))

        eb = -quantile(bepsilon * 0.5)
        if FWHM / delta_e < 5:
            print("Warning: FWHM / delta_e < 5. Broadening function might not be sampled well.")

        # Tabulate the Gaussian in range sigma * nsigma
        benergies = np.r_[-eb : eb : delta_e]
        bprofile = broadening(benergies)

        self.sort()
        energies = self.energies
        loE=energies[0] - eb
        hiE=energies[-1] + eb
        E=np.r_[loE : hiE : delta_e]

        # Encoding the discretized energy in the array index i makes the code much faster.
        # Create dos of delta-peaks to be folded with Gaussian
        DOSdelta = np.array([0.0 for j in E])
        for e in energies:
            # In order to be able to fold with tabulated Gaussian, we have to place
            # levels *on* the grid. I.e. level spacing cannot be smaller than deltaE.
            n = int((e-loE)/delta_e)

            # Note: DOS should be calculated for unoccupied levels as well!
            #if o is not None:
            #    DOSdelta[n] += o
            #else:
            DOSdelta[n] += 1
        # Convolve with gaussian, keeping same dimension
        # Can be made even faster by using fftconvolve
        DOS = np.convolve(DOSdelta,bprofile, mode='same')

        return np.array([E, DOS])

class KPoint(object):
    """Holds a k-point"""

    def __init__(self, kvector=None, energylevels=None, weight=None):
        self.kvector = np.array(kvector)
        self.energylevels = energylevels
        self.weight = weight

    def __iadd__(self, k):
        """Merging two k-points

        Used e.g. when merging k-points of different spins
        """
        if self.kvector != k.kvector:
            print("Warning: Adding k-points with differing k-vectors {} and {}"\
                  .format(self.kvector, k.kvector))
        self.weight += k.weight
        self.energylevels += k.energylevels

    @property
    def nbnd(self):
        return len(self.energylevels.energies)

    def copy(self, kpt):
        """Performs deep copy."""
        self.energylevels = kpt.energylevels.copy()
        self.kvector = cp.copy(spectrum.kvector)
        self.weight = cp.copy(spectrum.weight)

    def __str__(self):
        e = self.energylevels
        k = self.kvector
        text = 'k = ({:6.3f}, {:6.3f}, {:6.3f})'.format(k[0], k[1], k[2])

        if self.weight:
            w = self.weight
            text += ', w = {}'.format(w)

        text += ' : {}\n'.format(e.__str__())

        return text

class Dispersion(object):
    """Holds a collection of k-points"""

    def __init__(self, kpoints=None):
         if kpoints is None:
             self.kpoints = []
         else:
             self.kpoints = kpoints

    @property
    def energylevels(self):
        s = EnergyLevels()
        for kpt in self.kpoints:
            s += kpt.energylevels
        return s

    @property
    def energies(self):
        return self.energylevels.energies

    @property
    def kvectors(self):
        s = []
        for kpt in self.kpoints:
            s.append(kpt.kvector)
        return s

    @property
    def weights(self):
        s = []
        for kpt in self.kpoints:
            s.append(kpt.weights)
        return s

    @property
    def fermi(self):
        """Returns Fermi energy."""
        fermis = [k.energylevels.fermi for k in self.kpoints]

        fermi = np.unique(fermis)

        if len( np.unique(fermis) ) != 1:
            print("There are Fermi energies {}".format(fermis))
            print("Using the mean {}".format(np.mean(fermis)))

        return np.mean(fermis)

    def merge_kpoints(self):
        kv = [0,0,0]
        levels = Energylevels([k.energylevels for k in self.kpoints])
        weight = 1.0
        self.kpoints = [KPoint(kv,levels,weight)]

    def __iadd__(self, s):
        """Merging two dispersions

        Used e.g. when merging dispersions belonging to different spins.
        """
        if len(self.kpoints) != len(s.kpoints):
            print("Unable to merge due to different number of kpoints")
        for i in range(len(self.kpoints)):
            self.kpoints[i] += s.kpoints[i]
        return self

    def shift(self, e):
        """Shift energylevels by energy e"""
        for k in self.kpoints:
            k.energylevels.shift(e)

    @property
    def nbnd(self):
        nbnds = [k.nbnd for k in self.kpoints]
        nbnd = np.unique(nbnds)

        if len( np.unique(nbnd) ) != 1:
            print("Warning: k-points have different numer of bands {}"\
                   .format(nbnd))
        return nbnd[0]

    @property
    def nkpt(self):
        return len(self.kpoints)

    def copy(self, dispersion):
        """Performs deep copy."""
        self.kpoints = [k.copy() for k in dispersion.kpoints]

    def __str__(self):
        text  = "Dispersion containing {} k-points\n".format(self.nkpt)
        for kpt in self.kpoints:
            text += kpt.__str__()
        return text

    def __getitem__(self, index):
        return self.kpoints[index]

#class Atom(object):
#
#    """Represents a single atom.
#
#    An atom with coordinates, chemical species, charge, etc.
#    """
#
#    def __init__(self, coordinates=None, number=None, charge=None):
#        self.coordinates = np.array(coordinates)
#        self.number = number
#        self.charge = charge
#
#    @property
#    def symbol(self):
#        return number2symbol(self.number)
#
#    @symbol.setter
#    def symbol(self, symbol_new):
#        self.symbol = symbol_new
#
#    def distance(self, atom):
#        d = 0
#        #print c1.coordinates
#        #print c2.coordinates
#        for c1, c2 in zip(self.coordinates, atom.coordinates):
#            d += (c1 - c2)**2
#        return np.sqrt(d)
#
#    def __str__(self):
#        text = "(x,y,z) = ({},{},{})\tN = {}\tCharge {}".format(
#                self.coordinates[0],
#                self.coordinates[1],
#                self.coordinates[2],
#                self.number,
#                self.charge)
#        return text

<commit_msg>small bugfix<commit_after>"""Classes of fundamental atomistic concepts

Representations of fundamental atomistic concepts,
such as energy levels, Atoms,...
Uses ASE's Atoms objects.
"""

import numpy as np
import copy  as cp
from ase.atoms import Atom, Atoms

class EnergyLevel(object):

    """An energy level"""

    def __init__(self, energy, occupation=1.0, wfn=None):
        """Set energy and occupation."""
        self.energy = energy
        self.occupation = occupation
        self.wfn = wfn

class EnergyLevels(object):

    """A list of levels with fermi energy

    Compared to the C++ class,
    - the copy constructor has been renamed to the 'copy' method
    - the get/set methods have been stripped off
    - instead of overloading *=, the levels are exposed to the user
    - removed setFermiZero
    """

    def __init__(self, energies=None, occupations=None, wfns=None, fermi=None):
        """Fill object with levels and Fermi energy."""
        self.levels = []
        self.fermi = fermi

        # If occupations are specified, take them
        if energies is not None and occupations is not None:
            for i in range(len(energies)):
                tmp = EnergyLevel(energies[i], occupations[i])
                self.levels.append(tmp)
        # If we just have a fermi energy, create occupations
        elif energies is not None and fermi is not None:
            for i in range(len(energies)):
                if energies[i] < fermi:
                    tmp = EnergyLevel(energies[i], 1.0)
                else:
                    tmp = EnergyLevel(energies[i], 0.0)

                self.levels.append(tmp)
        # If neither fermi nor occupations are set...
        elif energies is not None:
            for i in range(len(energies)):
                tmp = EnergyLevel(energies[i], None)
                self.levels.append(tmp)

        if wfns is not None:
            if len(wfns) == len(self.levels):
                for i in range(len(wfns)):
                    self.levels[i].wfn = wfns[i]
            else:
                print("Error: Number of wave functions != number or levels")

    @property
    def energies(self):
        return np.array([l.energy for l in self.levels])

    @property
    def occupations(self):
        return np.array([l.occupation for l in self.levels])

    @energies.setter
    def energies(self, es):
        """Sets levels, not touching occupations."""
        if len(self.levels) != len(es):
            print('Error: Trying to set {le} energies for {le} levels.' \
                  .format(lo=len(es), le=len(self.levels)))
            return

        for i in range(len(self.levels)):
            self.levels[i].energy = es[i]

    @occupations.setter
    def occupations(self, os):
        """Sets occupations for existing levels."""

        if len(os) != len(self.levels):
            print('Error: Trying to set {lo} occupations for {le} levels.' \
                  .format(lo=len(os), le=len(self.levels)))
        else:
            for i in range(len(self.levels)):
                self.levels[i].occupation = os[i]

    def copy(self, energylevels):
        """Return a copy of energylevels."""
        self.levels = cp.copy(energylevels.levels)
        self.fermi = energylevels.fermi

    def join(self, energylevels):
        self.levels = self.levels + energylevels.levels
        if self.fermi != energylevels.fermi:
            print('Warning: Merging energy levels'
                  'with different Fermi energies.')
        self.fermi = energylevels.fermi

    def sort(self):
        self.levels.sort(key = lambda x: x.energy)

    def shift(self, de):
        self.energies += de
        self.fermi  += de

    def __iadd__(self, b):
        if isinstance(b, float):
            self.energies += de
            self.fermi  += de
        elif isinstance(b, self.__class__):
            self.levels += b.levels
            self.sort()
            if not self.fermi == b.fermi:
                self.fermi = None
        else:
            raise TypeError("Unsupported operand type(s) for +: '{}' and '{}'")\
                  .format(self.__class__, type(other))

        return self

    def __isub__(self, de):
        self.energies -= de
        self.fermi  -= de
        return self

    def n_occupied(self, epsilon=1e-12):
        """Return number of occupied levels

        Levels with energy at most epsilon above Fermi  still count as occupied.
        This prevents the disregard of occupied levels, when the Fermi energy
        is identical to the highest occupied level.
        """

        if self.fermi:
            return sum([1 if e < self.fermi + epsilon else 0 for e in self.energies])
        elif all(o is not None for o in self.occupations):
            print("Note: Counting occupied levels based on occupation number.")
            return sum([1 if o > 0 else 0 for o in self.occupations])
        else:
            print("Error: Cannot determine occupations.")

    def n_empty(self):
        """Return number of empty levels"""
        return len(levels) - self.n_occupied()

    def __str__(self):
        text  = "{} energy levels".format(len(self.levels))
        if self.fermi:
            text += ", Fermi energy {} eV".format(self.fermi)
        if all(o is not None for o in self.occupations):
            text += ", occupations specified"
        return text

    def __getitem__(self, index):
        return self.levels[index]

    def dos(self, bmethod = 'Gaussian', bepsilon = 1e-3, FWHM = 0.1, delta_e = 0.005):
        """
        Returns [energy, density of states].

        Parameters
        ----------
        bmethod: Method used for broadening ('Gaussian' or 'Lorentzian')
        bepsilon: Convolution is performed with broadening function in range
            [E-Eb, E+Eb] where Eb is determined such that the integrated weight
            of the broadening function outside of [-Eb, Eb] is < bepsilon.
        FWHM: Full-width of broadening function at half-maximum [eV]
        delta_e: spacing of energy grid [eV]
        """

        import scipy.special as scsp
        # Prepare broadening functions for later convolution
        # quantile function quantile(y) = x is defined such that
        # the integral of the probability density from -\infty to x equals y.
        if bmethod == 'Gaussian':
            sigma = FWHM / np.log(8 * np.sqrt(2))
            quantile = lambda y: np.sqrt(2) * scsp.erfinv(2.0*y -1.0) * sigma
            broadening = lambda x: 1/(sigma * np.sqrt(2*np.pi)) \
                                 * np.exp( - x**2 / (2 * sigma**2) )
        elif bmethod == 'Lorentzian':
            gamma = FWHM * 0.5
            quantile = lambda y: np.tan(np.pi * (y - 0.5)) * gamma
            broadening = lambda x: 1/np.pi * gamma / (x**2 + gamma**2)
        else:
            print("Error: Broadening method \"{}\" not recognized."\
                  .format(bmethod))

        eb = -quantile(bepsilon * 0.5)
        if FWHM / delta_e < 5:
            print("Warning: FWHM / delta_e < 5. Broadening function might not be sampled well.")

        # Tabulate the Gaussian in range sigma * nsigma
        benergies = np.r_[-eb : eb : delta_e]
        bprofile = broadening(benergies)

        self.sort()
        energies = self.energies
        loE=energies[0] - eb
        hiE=energies[-1] + eb
        E=np.r_[loE : hiE : delta_e]

        # Encoding the discretized energy in the array index i makes the code much faster.
        # Create dos of delta-peaks to be folded with Gaussian
        DOSdelta = np.array([0.0 for j in E])
        for e in energies:
            # In order to be able to fold with tabulated Gaussian, we have to place
            # levels *on* the grid. I.e. level spacing cannot be smaller than deltaE.
            n = int((e-loE)/delta_e)

            # Note: DOS should be calculated for unoccupied levels as well!
            #if o is not None:
            #    DOSdelta[n] += o
            #else:
            DOSdelta[n] += 1
        # Convolve with gaussian, keeping same dimension
        # Can be made even faster by using fftconvolve
        DOS = np.convolve(DOSdelta,bprofile, mode='same')

        return np.array([E, DOS])

class KPoint(object):
    """Holds a k-point"""

    def __init__(self, kvector=None, energylevels=None, weight=None):
        self.kvector = np.array(kvector)
        self.energylevels = energylevels
        self.weight = weight

    def __iadd__(self, k):
        """Merging two k-points

        Used e.g. when merging k-points of different spins
        """
        if self.kvector != k.kvector:
            print("Warning: Adding k-points with differing k-vectors {} and {}"\
                  .format(self.kvector, k.kvector))
        self.weight += k.weight
        self.energylevels += k.energylevels

    @property
    def nbnd(self):
        return len(self.energylevels.energies)

    @property
    def energies(self):
        return self.energylevels.energies

    def copy(self, kpt):
        """Performs deep copy."""
        self.energylevels = kpt.energylevels.copy()
        self.kvector = cp.copy(spectrum.kvector)
        self.weight = cp.copy(spectrum.weight)

    def __str__(self):
        e = self.energylevels
        k = self.kvector
        text = 'k = ({:6.3f}, {:6.3f}, {:6.3f})'.format(k[0], k[1], k[2])

        if self.weight:
            w = self.weight
            text += ', w = {}'.format(w)

        text += ' : {}\n'.format(e.__str__())

        return text

class Dispersion(object):
    """Holds a collection of k-points"""

    def __init__(self, kpoints=None):
         if kpoints is None:
             self.kpoints = []
         else:
             self.kpoints = kpoints

    @property
    def energylevels(self):
        s = EnergyLevels()
        for kpt in self.kpoints:
            s += kpt.energylevels
        return s

    @property
    def energies(self):
        return self.energylevels.energies

    @property
    def kvectors(self):
        s = []
        for kpt in self.kpoints:
            s.append(kpt.kvector)
        return s

    @property
    def weights(self):
        s = []
        for kpt in self.kpoints:
            s.append(kpt.weights)
        return s

    @property
    def fermi(self):
        """Returns Fermi energy."""
        fermis = [k.energylevels.fermi for k in self.kpoints]

        fermi = np.unique(fermis)

        if len( np.unique(fermis) ) != 1:
            print("There are Fermi energies {}".format(fermis))
            print("Using the mean {}".format(np.mean(fermis)))

        return np.mean(fermis)

    def merge_kpoints(self):
        kv = [0,0,0]
        levels = Energylevels([k.energylevels for k in self.kpoints])
        weight = 1.0
        self.kpoints = [KPoint(kv,levels,weight)]

    def __iadd__(self, s):
        """Merging two dispersions

        Used e.g. when merging dispersions belonging to different spins.
        """
        if len(self.kpoints) != len(s.kpoints):
            print("Unable to merge due to different number of kpoints")
        for i in range(len(self.kpoints)):
            self.kpoints[i] += s.kpoints[i]
        return self

    def shift(self, e):
        """Shift energylevels by energy e"""
        for k in self.kpoints:
            k.energylevels.shift(e)

    @property
    def nbnd(self):
        nbnds = [k.nbnd for k in self.kpoints]
        nbnd = np.unique(nbnds)

        if len( np.unique(nbnd) ) != 1:
            print("Warning: k-points have different numer of bands {}"\
                   .format(nbnd))
        return nbnd[0]

    @property
    def nkpt(self):
        return len(self.kpoints)

    def copy(self, dispersion):
        """Performs deep copy."""
        self.kpoints = [k.copy() for k in dispersion.kpoints]

    def __str__(self):
        text  = "Dispersion containing {} k-points\n".format(self.nkpt)
        for kpt in self.kpoints:
            text += kpt.__str__()
        return text

    def __getitem__(self, index):
        return self.kpoints[index]

#class Atom(object):
#
#    """Represents a single atom.
#
#    An atom with coordinates, chemical species, charge, etc.
#    """
#
#    def __init__(self, coordinates=None, number=None, charge=None):
#        self.coordinates = np.array(coordinates)
#        self.number = number
#        self.charge = charge
#
#    @property
#    def symbol(self):
#        return number2symbol(self.number)
#
#    @symbol.setter
#    def symbol(self, symbol_new):
#        self.symbol = symbol_new
#
#    def distance(self, atom):
#        d = 0
#        #print c1.coordinates
#        #print c2.coordinates
#        for c1, c2 in zip(self.coordinates, atom.coordinates):
#            d += (c1 - c2)**2
#        return np.sqrt(d)
#
#    def __str__(self):
#        text = "(x,y,z) = ({},{},{})\tN = {}\tCharge {}".format(
#                self.coordinates[0],
#                self.coordinates[1],
#                self.coordinates[2],
#                self.number,
#                self.charge)
#        return text

<|endoftext|>


<commit_before># Tai Sakuma <tai.sakuma@cern.ch>
from ..Summary import Summarizer, NextKeyComposer, KeyValueComposer
from ..CombineIntoList import CombineIntoList
from ..WriteListToFile import WriteListToFile
from ..Loop import Collector

##__________________________________________________________________||
def build_counter_collector_pair(tblcfg):
    keyValComposer = KeyValueComposer(
        keyAttrNames = tblcfg['keyAttrNames'],
        binnings = tblcfg['binnings'],
        keyIndices = tblcfg['keyIndices'],
        valAttrNames = tblcfg['valAttrNames'],
        valIndices = tblcfg['valIndices']
    )
    nextKeyComposer = NextKeyComposer(tblcfg['binnings'])
    summarizer = Summarizer(
        keyValComposer = keyValComposer,
        summary = tblcfg['summaryClass'](),
        nextKeyComposer = nextKeyComposer,
        weightCalculator = tblcfg['weight']
    )
    resultsCombinationMethod = CombineIntoList(
        keyNames = tblcfg['keyOutColumnNames'],
        valNames = tblcfg['valOutColumnNames']
    )
    deliveryMethod = WriteListToFile(tblcfg['outFilePath']) if tblcfg['outFile'] else None
    collector = Collector(resultsCombinationMethod, deliveryMethod)
    return summarizer, collector

##__________________________________________________________________||
<commit_msg>use summaryClassArgs in instantiating summaryClass<commit_after># Tai Sakuma <tai.sakuma@cern.ch>
from ..Summary import Summarizer, NextKeyComposer, KeyValueComposer
from ..CombineIntoList import CombineIntoList
from ..WriteListToFile import WriteListToFile
from ..Loop import Collector

##__________________________________________________________________||
def build_counter_collector_pair(tblcfg):
    keyValComposer = KeyValueComposer(
        keyAttrNames = tblcfg['keyAttrNames'],
        binnings = tblcfg['binnings'],
        keyIndices = tblcfg['keyIndices'],
        valAttrNames = tblcfg['valAttrNames'],
        valIndices = tblcfg['valIndices']
    )
    nextKeyComposer = NextKeyComposer(tblcfg['binnings'])
    summarizer = Summarizer(
        keyValComposer = keyValComposer,
        summary = tblcfg['summaryClass'](**tblcfg['summaryClassArgs']),
        nextKeyComposer = nextKeyComposer,
        weightCalculator = tblcfg['weight']
    )
    resultsCombinationMethod = CombineIntoList(
        keyNames = tblcfg['keyOutColumnNames'],
        valNames = tblcfg['valOutColumnNames']
    )
    deliveryMethod = WriteListToFile(tblcfg['outFilePath']) if tblcfg['outFile'] else None
    collector = Collector(resultsCombinationMethod, deliveryMethod)
    return summarizer, collector

##__________________________________________________________________||
<|endoftext|>


<commit_before>#
# Copyright (c) 2013, Battelle Memorial Institute
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
#    list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are those
# of the authors and should not be interpreted as representing official policies,
# either expressed or implied, of the FreeBSD Project.
#

# This material was prepared as an account of work sponsored by an
# agency of the United States Government.  Neither the United States
# Government nor the United States Department of Energy, nor Battelle,
# nor any of their employees, nor any jurisdiction or organization
# that has cooperated in the development of these materials, makes
# any warranty, express or implied, or assumes any legal liability
# or responsibility for the accuracy, completeness, or usefulness or
# any information, apparatus, product, software, or process disclosed,
# or represents that its use would not infringe privately owned rights.
#
# Reference herein to any specific commercial product, process, or
# service by trade name, trademark, manufacturer, or otherwise does
# not necessarily constitute or imply its endorsement, recommendation,
# r favoring by the United States Government or any agency thereof,
# or Battelle Memorial Institute. The views and opinions of authors
# expressed herein do not necessarily state or reflect those of the
# United States Government or any agency thereof.
#
# PACIFIC NORTHWEST NATIONAL LABORATORY
# operated by BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY
# under Contract DE-AC05-76RL01830
#

__version__ = '1.9'
<commit_msg>Updating version<commit_after>#
# Copyright (c) 2013, Battelle Memorial Institute
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
#    list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are those
# of the authors and should not be interpreted as representing official policies,
# either expressed or implied, of the FreeBSD Project.
#

# This material was prepared as an account of work sponsored by an
# agency of the United States Government.  Neither the United States
# Government nor the United States Department of Energy, nor Battelle,
# nor any of their employees, nor any jurisdiction or organization
# that has cooperated in the development of these materials, makes
# any warranty, express or implied, or assumes any legal liability
# or responsibility for the accuracy, completeness, or usefulness or
# any information, apparatus, product, software, or process disclosed,
# or represents that its use would not infringe privately owned rights.
#
# Reference herein to any specific commercial product, process, or
# service by trade name, trademark, manufacturer, or otherwise does
# not necessarily constitute or imply its endorsement, recommendation,
# r favoring by the United States Government or any agency thereof,
# or Battelle Memorial Institute. The views and opinions of authors
# expressed herein do not necessarily state or reflect those of the
# United States Government or any agency thereof.
#
# PACIFIC NORTHWEST NATIONAL LABORATORY
# operated by BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY
# under Contract DE-AC05-76RL01830
#

__version__ = '2.0'
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in module root
# directory
##############################################################################
from openerp import models, api, _
from openerp.exceptions import UserError
from openerp.addons.stock.stock import stock_pack_operation

class StockPackOperation(models.Model):

    _inherit = 'stock.pack.operation'

    @api.multi
    def set_all_done(self):
        for rec in self:
            if rec.lots_visible:
                for lot in rec.pack_lot_ids:
                    lot.qty = lot.qty_todo
            rec.qty_done = rec.product_qty

@api.multi
def unlink(self):
    # modificamos para que se pudan borrar las operations aun si el picking
    # esta realizado o cancelado (el campo state de las op es related al state
    # de picking)
    if not self._context.get('force_op_unlink') and any(
            [x.state in ('done', 'cancel') for x in self]):
        raise UserError(_(
            'You can not delete pack operations of a done picking'))
    return super(stock_pack_operation, self).unlink()

stock_pack_operation.unlink = unlink
<commit_msg>IMP set all done with lots<commit_after># -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in module root
# directory
##############################################################################
from openerp import models, api, _
from openerp.exceptions import UserError
from openerp.addons.stock.stock import stock_pack_operation

class StockPackOperation(models.Model):

    _inherit = 'stock.pack.operation'

    @api.multi
    def set_all_done(self):
        for rec in self:
            if rec.lots_visible:
                for lot in rec.pack_lot_ids:
                    lot.qty = lot.qty_todo
            else:
                rec.qty_done = rec.product_qty

@api.multi
def unlink(self):
    # modificamos para que se pudan borrar las operations aun si el picking
    # esta realizado o cancelado (el campo state de las op es related al state
    # de picking)
    if not self._context.get('force_op_unlink') and any(
            [x.state in ('done', 'cancel') for x in self]):
        raise UserError(_(
            'You can not delete pack operations of a done picking'))
    return super(stock_pack_operation, self).unlink()

stock_pack_operation.unlink = unlink
<|endoftext|>


<commit_before>#!/usr/bin/env python3.5

# Copyright 2016 The Johns Hopkins University Applied Physics Laboratory
#
# 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.

import argparse
import os
import sys
from pathlib import Path

import alter_path
from lib.stepfunctions import heaviside

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description = "Script to compile a heaviside file into a StepFunction State Machine",
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("--output", "-o",
                        metavar = "<file>",
                        default = sys.stdout,
                        type = argparse.FileType('w'),
                        help = "Location to save the StepFunction State Machine to (default: stdout)")
    parser.add_argument("--region", "-r",
                        metavar = "<aws_region>",
                        default = '',
                        help = "AWS Region for ARNs (default: '')")
    parser.add_argument("--account", "-a",
                        metavar = "<aws_account>",
                        default = '',
                        help = "AWS Account ID for ARNs (default: '')")
    parser.add_argument("file",
                        help="heaviside file to compile")

    args = parser.parse_args()

    machine = heaviside.compile(Path(args.file),
                                region=args.region,
                                account_id=args.account,
                                indent=3)

    args.output.write(machine)
<commit_msg>Guarded printing of the heaviside output<commit_after>#!/usr/bin/env python3.5

# Copyright 2016 The Johns Hopkins University Applied Physics Laboratory
#
# 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.

import argparse
import os
import sys
from pathlib import Path

import alter_path
from lib.stepfunctions import heaviside

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description = "Script to compile a heaviside file into a StepFunction State Machine",
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("--output", "-o",
                        metavar = "<file>",
                        default = sys.stdout,
                        type = argparse.FileType('w'),
                        help = "Location to save the StepFunction State Machine to (default: stdout)")
    parser.add_argument("--region", "-r",
                        metavar = "<aws_region>",
                        default = '',
                        help = "AWS Region for ARNs (default: '')")
    parser.add_argument("--account", "-a",
                        metavar = "<aws_account>",
                        default = '',
                        help = "AWS Account ID for ARNs (default: '')")
    parser.add_argument("file",
                        help="heaviside file to compile")

    args = parser.parse_args()

    machine = heaviside.compile(Path(args.file),
                                region=args.region,
                                account_id=args.account,
                                indent=3)

    if machine:
        args.output.write(machine)
<|endoftext|>


<commit_before>import json

from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import get_object_or_404, render
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.importlib import import_module
from django.views.decorators.http import require_POST

from account.decorators import login_required
from aiteo.forms import AskQuestionForm, AddResponseForm
from aiteo.models import Question, Response

workflow = import_module(getattr(settings, "AITEO_WORKFLOW_MODULE", "aiteo.workflow"))

def question_list(request):
    questions = Question.objects.all().order_by("-score", "created", "id")
    ctx = {
        "questions": questions,
    }
    return render(request, "aiteo/question_list.html", ctx)

@login_required
def question_create(request):
    if request.method == "POST":
        form = AskQuestionForm(request.POST)
        if form.is_valid():
            question = form.save(commit=False)
            question.user = request.user
            question.save()
            return HttpResponseRedirect(question.get_absolute_url())
    else:
        form = AskQuestionForm()
    ctx = {
        "form": form,
    }
    return render(request, "aiteo/question_create.html", ctx)

def question_detail(request, pk):
    questions = Question.objects.all()
    question = get_object_or_404(questions, pk=pk)
    responses = question.responses.order_by("-score", "created", "id")
    is_me = question.user == request.user
    if request.method == "POST":
        add_response_form = AddResponseForm(request.POST)
        if add_response_form.is_valid():
            response = add_response_form.save(commit=False)
            response.question = question
            response.user = request.user
            response.save()
            return HttpResponseRedirect(response.get_absolute_url())
    else:
        if not is_me or request.user.is_staff:
            add_response_form = AddResponseForm()
        else:
            add_response_form = None
    ctx = {
        "can_mark_accepted": workflow.can_mark_accepted(request.user, question),
        "question": question,
        "responses": responses,
        "add_response_form": add_response_form,
    }
    return render(request, "aiteo/question_detail.html", ctx)

@login_required
@require_POST
def mark_accepted(request, pk):
    response = get_object_or_404(Response, pk=pk)
    if not workflow.can_mark_accepted(request.user, response.question):
        return HttpResponseForbidden("You are not allowed to mark this question accepted.")

    response.accept()

    data = {"fragments": {}}
    for resp in response.question.responses.all():
        data["fragments"]["#accepted-{}".format(resp.pk)] = render_to_string(
            "aiteo/_accepted.html",
            {"response": resp},
            context_instance=RequestContext(request)
        )
    return HttpResponse(json.dumps(data), mimetype="application/json")

@login_required
@require_POST
def question_upvote(request, pk):
    question = get_object_or_404(Question, pk=pk)
    question.vote(user=request.user, upvote=True)
    data = {
        "html": render_to_string("aiteo/_question_vote_badge.html", {
            "question": question
        }, context_instance=RequestContext(request))
    }
    return HttpResponse(json.dumps(data), mimetype="application/json")

def question_downvote(request, pk):
    question = get_object_or_404(Question, pk=pk)
    question.vote(user=request.user, upvote=False)
    data = {
        "html": render_to_string("aiteo/_question_vote_badge.html", {
            "question": question
        }, context_instance=RequestContext(request))
    }
    return HttpResponse(json.dumps(data), mimetype="application/json")

def response_upvote(request, pk):
    response = get_object_or_404(Response, pk=pk)
    response.vote(user=request.user, upvote=True)
    data = {
        "html": render_to_string("aiteo/_response_vote_badge.html", {
            "response": response
        }, context_instance=RequestContext(request))
    }
    return HttpResponse(json.dumps(data), mimetype="application/json")

def response_downvote(request, pk):
    response = get_object_or_404(Response, pk=pk)
    response.vote(user=request.user, upvote=False)
    data = {
        "html": render_to_string("aiteo/_response_vote_badge.html", {
            "response": response
        }, context_instance=RequestContext(request))
    }
    return HttpResponse(json.dumps(data), mimetype="application/json")
<commit_msg>require post and auth on all (up|down)vote view<commit_after>import json

from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import get_object_or_404, render
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.importlib import import_module
from django.views.decorators.http import require_POST

from account.decorators import login_required
from aiteo.forms import AskQuestionForm, AddResponseForm
from aiteo.models import Question, Response

workflow = import_module(getattr(settings, "AITEO_WORKFLOW_MODULE", "aiteo.workflow"))

def question_list(request):
    questions = Question.objects.all().order_by("-score", "created", "id")
    ctx = {
        "questions": questions,
    }
    return render(request, "aiteo/question_list.html", ctx)

@login_required
def question_create(request):
    if request.method == "POST":
        form = AskQuestionForm(request.POST)
        if form.is_valid():
            question = form.save(commit=False)
            question.user = request.user
            question.save()
            return HttpResponseRedirect(question.get_absolute_url())
    else:
        form = AskQuestionForm()
    ctx = {
        "form": form,
    }
    return render(request, "aiteo/question_create.html", ctx)

def question_detail(request, pk):
    questions = Question.objects.all()
    question = get_object_or_404(questions, pk=pk)
    responses = question.responses.order_by("-score", "created", "id")
    is_me = question.user == request.user
    if request.method == "POST":
        add_response_form = AddResponseForm(request.POST)
        if add_response_form.is_valid():
            response = add_response_form.save(commit=False)
            response.question = question
            response.user = request.user
            response.save()
            return HttpResponseRedirect(response.get_absolute_url())
    else:
        if not is_me or request.user.is_staff:
            add_response_form = AddResponseForm()
        else:
            add_response_form = None
    ctx = {
        "can_mark_accepted": workflow.can_mark_accepted(request.user, question),
        "question": question,
        "responses": responses,
        "add_response_form": add_response_form,
    }
    return render(request, "aiteo/question_detail.html", ctx)

@login_required
@require_POST
def mark_accepted(request, pk):
    response = get_object_or_404(Response, pk=pk)
    if not workflow.can_mark_accepted(request.user, response.question):
        return HttpResponseForbidden("You are not allowed to mark this question accepted.")

    response.accept()

    data = {"fragments": {}}
    for resp in response.question.responses.all():
        data["fragments"]["#accepted-{}".format(resp.pk)] = render_to_string(
            "aiteo/_accepted.html",
            {"response": resp},
            context_instance=RequestContext(request)
        )
    return HttpResponse(json.dumps(data), mimetype="application/json")

@login_required
@require_POST
def question_upvote(request, pk):
    question = get_object_or_404(Question, pk=pk)
    question.vote(user=request.user, upvote=True)
    data = {
        "html": render_to_string("aiteo/_question_vote_badge.html", {
            "question": question
        }, context_instance=RequestContext(request))
    }
    return HttpResponse(json.dumps(data), mimetype="application/json")

@login_required
@require_POST
def question_downvote(request, pk):
    question = get_object_or_404(Question, pk=pk)
    question.vote(user=request.user, upvote=False)
    data = {
        "html": render_to_string("aiteo/_question_vote_badge.html", {
            "question": question
        }, context_instance=RequestContext(request))
    }
    return HttpResponse(json.dumps(data), mimetype="application/json")

@login_required
@require_POST
def response_upvote(request, pk):
    response = get_object_or_404(Response, pk=pk)
    response.vote(user=request.user, upvote=True)
    data = {
        "html": render_to_string("aiteo/_response_vote_badge.html", {
            "response": response
        }, context_instance=RequestContext(request))
    }
    return HttpResponse(json.dumps(data), mimetype="application/json")

@login_required
@require_POST
def response_downvote(request, pk):
    response = get_object_or_404(Response, pk=pk)
    response.vote(user=request.user, upvote=False)
    data = {
        "html": render_to_string("aiteo/_response_vote_badge.html", {
            "response": response
        }, context_instance=RequestContext(request))
    }
    return HttpResponse(json.dumps(data), mimetype="application/json")
<|endoftext|>