<commit_before>#!/usr/bin/env python
# encoding: utf-8

"""
flask_hal.link
==============

Implements the ``HAL`` Link specification.
"""

# Standard Libs
import json

# Third Party Libs
from flask import current_app, request

VALID_LINK_ATTRS = [
    'name',
    'title',
    'type',
    'deprecation',
    'profile',
    'templated',
    'hreflang'
]

class Collection(list):
    """Build a collection of ``HAL`` link objects.

    Example:
        >>> from flask_hal.link import Collection, Link
        >>> l = Collection(
        ...     Link('foo', 'http://foo.com'),
        ...     Link('bar', 'http://bar.com'))
        >>> print l.to_dict()
        ... {
        ...     '_links': {
        ...         'foo': {
        ...             'href": "http://foo.com'
        ...         },
        ...         'bar': {
        ...             'href': 'http://bar.com'
        ...         }
        ...     }
        ... }
    """

    def __init__(self, *args):
        """Initialise a new ``Collection`` object.

        Example:
            >>> l = Collection(
            ...     Link('foo', 'http://foo.com'),
            ...     Link('bar', 'http://bar.com'))

        Raises:
            TypeError: If a link is not a ``flask_hal.link.Link`` instance
        """

        for link in args:
            if not isinstance(link, Link):
                raise TypeError(
                    '{0} is not a valid flask_hal.link.Link instance'.format(link))

            self.append(link)

    def to_dict(self):
        """Returns the Python ``dict`` representation of the ``Collection``
        instance.

        Example:
            >>> from flask_hal.link import Collection, Link
            >>> l = Collection(
            ...     Link('foo', 'http://foo.com'),
            ...     Link('bar', 'http://bar.com'))
            >>> l.to_dict()
            ... {'_links': {'bar': {'href': 'http://bar.com'},
            ... 'foo': {'href': 'http://foo.com'}}}

        Returns:
            dict
        """

        links = {}

        for link in self:
            links.update(link.to_dict())

        return {
            '_links': links
        }

    def to_json(self):
        """Returns the ``JSON`` representation of the instance.

        Example:
            >>> from flask_hal.link import Collection, Link
            >>> l = Collection(
            ...     Link('foo', 'http://foo.com'),
            ...     Link('bar', 'http://bar.com'))
            >>> l.to_json()
            ... '{"_links":
                    {
                        "foo": {"href": "http://foo.com"},
                        "bar": {"href": "http://bar.com"}
                    }
                }'

        Returns:
            str: The ``JSON`` representation of the instance
        """

        return json.dumps(self.to_dict())

class Link(object):
    """Build ``HAL`` specification ``_links`` object.

    Example:
        >>> from flask_hal.link import Link
        >>> l = Link('foo', 'http://foo.com/bar')
        >>> print l.to_json()
        ... '{"foo": {"href": "http://foo.com/bar"}}'
        >>> l.title = 'Foo'
        >>> print l.to_json()
        ... '{"foo": {"href": "http://foo.com/bar", "name": "Foo"}}'

    """

    def __init__(self, rel, href, **kwargs):
        """Initialise a new ``Link`` object.

        Args:
            rel (str): The links ``rel`` or name
            href (str): The URI to the resource

        Keyword Args:
            name (str): The links name attribute, optional
            title (str): The links title attribute, optional
            type (str): The links type attribute, optional
            deprecation (str): The deprecation attribute, optional
            profile (str): The profile  attribute, optional
            templated (bool): The templated attribute, optional
            hreflang (str): The hreflang attribute, optional
        """

        self.rel = rel
        self.href = href

        for attr in VALID_LINK_ATTRS:
            if attr in kwargs:
                setattr(self, attr, kwargs.pop(attr))

    def to_dict(self):
        """Returns the Python ``dict`` representation of the ``Link`` instance.

        Example:
            >>> from flask_hal.link import Link
            >>> l = Link('foo', 'http://foo.com')
            >>> l.to_dict()
            ... {'foo': {'href': 'http://foo.com'}}

        Returns:
            dict
        """

        # Minimum viable link
        link = {
            'href': self.href
        }

        # Add extra attributes if they exist
        for attr in VALID_LINK_ATTRS:
            if hasattr(self, attr):
                link[attr] = getattr(self, attr)

        return {
            self.rel: link
        }

    def to_json(self):
        """Returns the ``JSON`` encoded representation of the ``Link`` object.

        Example:
            >>> from flask_hal.link import Link
            >>> l = Link('foo', 'http://foo.com', name='Foo')
            >>> print l.to_json()
            ... '{"foo": {"href": "http://foo.com", "name": "Foo"}}'

        Returns:
            str: The ``JSON`` encoded object
        """
        return json.dumps(self.to_dict())

class Self(Link):
    """A class to create the required ``self`` link  from the current
    request URL.
    """

    def __init__(self, **kwargs):
        """Initialises a new ``Self`` link instance. Accepts the same
        Keyword Arguments as :class:`.Link`.

        See Also:
            :class:`.Link`
        """

        url = request.url
        if current_app.config['SERVER_NAME'] is None:
            url = request.url.replace(request.host_url, '/')

        return super(Self, self).__init__('self', url, **kwargs)
<commit_msg>Fix Collection.to_dict() to support array of links with same link relation as per section 4.1.1 of draft RFC. [https://tools.ietf.org/html/draft-kelly-json-hal-07]<commit_after>#!/usr/bin/env python
# encoding: utf-8

"""
flask_hal.link
==============

Implements the ``HAL`` Link specification.
"""

# Standard Libs
import json

# Third Party Libs
from flask import current_app, request

VALID_LINK_ATTRS = [
    'name',
    'title',
    'type',
    'deprecation',
    'profile',
    'templated',
    'hreflang'
]

class Collection(list):
    """Build a collection of ``HAL`` link objects.

    Example:
        >>> from flask_hal.link import Collection, Link
        >>> l = Collection(
        ...     Link('foo', 'http://foo.com'),
        ...     Link('bar', 'http://bar.com'))
        >>> print l.to_dict()
        ... {
        ...     '_links': {
        ...         'foo': {
        ...             'href": "http://foo.com'
        ...         },
        ...         'bar': {
        ...             'href': 'http://bar.com'
        ...         }
        ...     }
        ... }
    """

    def __init__(self, *args):
        """Initialise a new ``Collection`` object.

        Example:
            >>> l = Collection(
            ...     Link('foo', 'http://foo.com'),
            ...     Link('bar', 'http://bar.com'))

        Raises:
            TypeError: If a link is not a ``flask_hal.link.Link`` instance
        """

        for link in args:
            if not isinstance(link, Link):
                raise TypeError(
                    '{0} is not a valid flask_hal.link.Link instance'.format(link))

            self.append(link)

    def to_dict(self):
        """Returns the Python ``dict`` representation of the ``Collection``
        instance.

        Example:
            >>> from flask_hal.link import Collection, Link
            >>> l = Collection(
            ...     Link('foo', 'http://foo.com'),
            ...     Link('bar', 'http://bar.com'))
            >>> l.to_dict()
            ... {'_links': {'bar': {'href': 'http://bar.com'},
            ... 'foo': {'href': 'http://foo.com'}}}

        Returns:
            dict
        """

        links = {}

        for link in self:
            if link.rel in links.keys():
                if isinstance(links[link.rel], dict):
                    links[link.rel] = [ links[link.rel] ]
                links[link.rel].append(link.to_dict()[link.rel])
            else:
                links.update(link.to_dict())

        return {
            '_links': links
        }

    def to_json(self):
        """Returns the ``JSON`` representation of the instance.

        Example:
            >>> from flask_hal.link import Collection, Link
            >>> l = Collection(
            ...     Link('foo', 'http://foo.com'),
            ...     Link('bar', 'http://bar.com'))
            >>> l.to_json()
            ... '{"_links":
                    {
                        "foo": {"href": "http://foo.com"},
                        "bar": {"href": "http://bar.com"}
                    }
                }'

        Returns:
            str: The ``JSON`` representation of the instance
        """

        return json.dumps(self.to_dict())

class Link(object):
    """Build ``HAL`` specification ``_links`` object.

    Example:
        >>> from flask_hal.link import Link
        >>> l = Link('foo', 'http://foo.com/bar')
        >>> print l.to_json()
        ... '{"foo": {"href": "http://foo.com/bar"}}'
        >>> l.title = 'Foo'
        >>> print l.to_json()
        ... '{"foo": {"href": "http://foo.com/bar", "name": "Foo"}}'

    """

    def __init__(self, rel, href, **kwargs):
        """Initialise a new ``Link`` object.

        Args:
            rel (str): The links ``rel`` or name
            href (str): The URI to the resource

        Keyword Args:
            name (str): The links name attribute, optional
            title (str): The links title attribute, optional
            type (str): The links type attribute, optional
            deprecation (str): The deprecation attribute, optional
            profile (str): The profile  attribute, optional
            templated (bool): The templated attribute, optional
            hreflang (str): The hreflang attribute, optional
        """

        self.rel = rel
        self.href = href

        for attr in VALID_LINK_ATTRS:
            if attr in kwargs:
                setattr(self, attr, kwargs.pop(attr))

    def to_dict(self):
        """Returns the Python ``dict`` representation of the ``Link`` instance.

        Example:
            >>> from flask_hal.link import Link
            >>> l = Link('foo', 'http://foo.com')
            >>> l.to_dict()
            ... {'foo': {'href': 'http://foo.com'}}

        Returns:
            dict
        """

        # Minimum viable link
        link = {
            'href': self.href
        }

        # Add extra attributes if they exist
        for attr in VALID_LINK_ATTRS:
            if hasattr(self, attr):
                link[attr] = getattr(self, attr)

        return {
            self.rel: link
        }

    def to_json(self):
        """Returns the ``JSON`` encoded representation of the ``Link`` object.

        Example:
            >>> from flask_hal.link import Link
            >>> l = Link('foo', 'http://foo.com', name='Foo')
            >>> print l.to_json()
            ... '{"foo": {"href": "http://foo.com", "name": "Foo"}}'

        Returns:
            str: The ``JSON`` encoded object
        """
        return json.dumps(self.to_dict())

class Self(Link):
    """A class to create the required ``self`` link  from the current
    request URL.
    """

    def __init__(self, **kwargs):
        """Initialises a new ``Self`` link instance. Accepts the same
        Keyword Arguments as :class:`.Link`.

        See Also:
            :class:`.Link`
        """

        url = request.url
        if current_app.config['SERVER_NAME'] is None:
            url = request.url.replace(request.host_url, '/')

        return super(Self, self).__init__('self', url, **kwargs)
<|endoftext|>


<commit_before>import exchange_api
import hashlib
import hmac
import json
import urllib2

class CoinEx(exchange_api.Exchange):

    name = 'CoinEx'

    def __init__(self, api_key, api_secret):
        self.api_url = 'https://coinex.pw/api/v2/'
        self.api_headers = {'Content-type' : 'application/json',
                            'Accept' : 'application/json',
                            'User-Agent' : 'autocoin-autosell'}
        self.api_key = api_key
        self.api_secret = api_secret

    def GetName(self):
        return 'CoinEx'

    def _Request(self, method, headers=None, post_data=None):
        if headers is None:
            headers = {}
        headers.update(self.api_headers.items())
        request = urllib2.Request(self.api_url + method, post_data, headers)
        try:
            response = urllib2.urlopen(request)
            try:
                response_json = json.loads(response.read())
                if not method in response_json:
                    raise exchange_api.ExchangeException('Root not in %s.' % method)
                return response_json[method]
            finally:
                response.close()
        except (urllib2.HTTPError, ValueError) as e:
            raise exchange_api.ExchangeException(e)

    def _PrivateRequest(self, method, post_data=None):
        hmac_data = '' if not post_data else post_data
        digest = hmac.new(self.api_secret, hmac_data, hashlib.sha512).hexdigest()
        headers = {'API-Key' : self.api_key,
                   'API-Sign': digest}
        return self._Request(method, headers, post_data)

    def GetCurrencies(self):
        currencies = {}
        try:
            for currency in self._Request('currencies'):
                currencies[currency['name']] = currency['id']
        except (TypeError, KeyError) as e:
            raise exchange_api.ExchangeException(e)
        return currencies

    def GetBalances(self):
        balances = {}
        try:
            for balance in self._PrivateRequest('balances'):
                balances[balance['currency_id']] = float(balance['amount']) / pow(10, 8)
        except (TypeError, KeyError) as e:
            raise exchange_api.ExchangeException(e)
        return balances

    def GetMarkets(self):
        try:
            return [exchange_api.Market(trade_pair['currency_id'], trade_pair['market_id'],
                                        trade_pair['id']) for
                    trade_pair in self._Request('trade_pairs')]
        except (TypeError, KeyError) as e:
            raise exchange_api.ExchangeException(e)
        return markets

    def CreateOrder(self, market_id, amount, bid=True, price=0):
        order = {'trade_pair_id' : market_id,
                 'amount' : int(amount * pow(10, 8)),
                 'bid' : bid,
                 'rate' : max(1, int(price * pow(10, 8)))}
        post_data = json.dumps({'order' : order})
        order_response = self._PrivateRequest('orders', post_data)
        if not order_response:
            raise exchange_api.ExchangeException('Order response empty.')
        if not 'id' in order_response[0]:
            raise exchange_api.ExchangeException('id not in orders.')
        return order_response[0]['id']
<commit_msg>Simplify CoinEx.CreateOrder a bit.<commit_after>import exchange_api
import hashlib
import hmac
import json
import urllib2

class CoinEx(exchange_api.Exchange):

    name = 'CoinEx'

    def __init__(self, api_key, api_secret):
        self.api_url = 'https://coinex.pw/api/v2/'
        self.api_headers = {'Content-type' : 'application/json',
                            'Accept' : 'application/json',
                            'User-Agent' : 'autocoin-autosell'}
        self.api_key = api_key
        self.api_secret = api_secret

    def GetName(self):
        return 'CoinEx'

    def _Request(self, method, headers=None, post_data=None):
        if headers is None:
            headers = {}
        headers.update(self.api_headers.items())
        request = urllib2.Request(self.api_url + method, post_data, headers)
        try:
            response = urllib2.urlopen(request)
            try:
                response_json = json.loads(response.read())
                if not method in response_json:
                    raise exchange_api.ExchangeException('Root not in %s.' % method)
                return response_json[method]
            finally:
                response.close()
        except (urllib2.HTTPError, ValueError) as e:
            raise exchange_api.ExchangeException(e)

    def _PrivateRequest(self, method, post_data=None):
        hmac_data = '' if not post_data else post_data
        digest = hmac.new(self.api_secret, hmac_data, hashlib.sha512).hexdigest()
        headers = {'API-Key' : self.api_key,
                   'API-Sign': digest}
        return self._Request(method, headers, post_data)

    def GetCurrencies(self):
        currencies = {}
        try:
            for currency in self._Request('currencies'):
                currencies[currency['name']] = currency['id']
        except (TypeError, KeyError) as e:
            raise exchange_api.ExchangeException(e)
        return currencies

    def GetBalances(self):
        balances = {}
        try:
            for balance in self._PrivateRequest('balances'):
                balances[balance['currency_id']] = float(balance['amount']) / pow(10, 8)
        except (TypeError, KeyError) as e:
            raise exchange_api.ExchangeException(e)
        return balances

    def GetMarkets(self):
        try:
            return [exchange_api.Market(trade_pair['currency_id'], trade_pair['market_id'],
                                        trade_pair['id']) for
                    trade_pair in self._Request('trade_pairs')]
        except (TypeError, KeyError) as e:
            raise exchange_api.ExchangeException(e)
        return markets

    def CreateOrder(self, market_id, amount, bid=True, price=0):
        order = {'trade_pair_id' : market_id,
                 'amount' : int(amount * pow(10, 8)),
                 'bid' : bid,
                 'rate' : max(1, int(price * pow(10, 8)))}
        post_data = json.dumps({'order' : order})
        try:
            return self._PrivateRequest('orders', post_data)[0]['id']
        except (TypeError, KeyError, IndexError) as e:
            raise exchange_api.ExchangeException(e)
<|endoftext|>


<commit_before>"""
wrappers around Trim galore! and cutadapt for trimming off common adapter
sequences used in NGS

Trim galore!: http://www.bioinformatics.babraham.ac.uk/projects/trim_galore/
cutadapt: https://github.com/marcelm/cutadapt
sickle: https://github.com/najoshi/sickle
"""

from bcbio.distributed.transaction import file_transaction
from bcbio.utils import file_exists, safe_makedir
from bipy.pipeline.stages import AbstractStage
from bipy.utils import flatten, append_stem, get_in, is_pair
import sh
import os
from pkg_resources import resource_stream
import yaml
from Bio.Seq import Seq
import tempfile
from bipy.toolbox.fastq import DetectFastqFormat

with resource_stream(__name__, 'data/adapters.yaml') as in_handle:
    ADAPTERS = yaml.load(in_handle)

class TrimGalore(AbstractStage):
    """
    runs trim_galore on the data to trim off adapters, polyA tails and
    other contaminating sequences
    http://www.bioinformatics.babraham.ac.uk/projects/trim_galore/

    """

    stage = "trim_galore"

    def __init__(self, config):
        self.config = config
        self.stage_config = get_in(config, ("stage", self.stage), {})
        self.chemistry = self.stage_config.get("chemistry", "truseq")
        if not isinstance(self.chemistry, list):
            self.chemistry = [self.chemistry]

        self.options = self.stage_config.get("options", "")
        self.trim_galore = sh.Command(self.stage_config.get("program",
                                                            "trim_galore"))
        self.out_dir_prefix = get_in(config, ("dir", "results"),
                                     "results") + self.stage
        self.trim_polya = self.stage_config.get("trim_polya", True)
        safe_makedir(self.out_dir_prefix)

    def get_adapters(self, chemistry):
        return list(flatten([["-a", x] for x in ADAPTERS.get(chemistry, [])]))

    def _in2out(self, in_file):
        base, _ = os.path.splitext(in_file)
        return base + "_trimmed.fq"

    def __call__(self, in_file):
        raise NotImplementedError("Waiting to hear back from maintainer to "
                                  "handle multiple adapters before finishing.")
        adapters = list(flatten(map(self.get_adapters, self.chemistry)))
        # if it is a list assume these are pairs
        if isinstance(in_file, list):
            out_files = map(self._in2out, in_file)
            if all(map(file_exists, out_files)):
                return out_files
            self.trim_galore(in_file, self.options, adapters, paired=True)
            return out_files
        # if it is only one file just run it
        else:
            out_file = self._in2out(in_file)
            if file_exists(out_file):
                return out_file
            self.trim_galore(in_file, self.options, adapters)
            return out_file

class Cutadapt(AbstractStage):

    stage = "cutadapt"

    def __init__(self, config):
        self.config = config
        self.stage_config = get_in(config, ("stage", self.stage), {})
        self.chemistry = self.stage_config.get("chemistry", "truseq")
        if not isinstance(self.chemistry, list):
            self.chemistry = [self.chemistry]

        self.options = self.stage_config.get("options", "")
        self.user_adapters = self.stage_config.get("adapters", [])
        self.out_dir = os.path.join(get_in(self.config, ("dir", "results"),
                                           "results"), self.stage)

    def _detect_fastq_format(self, in_file):
        formats = DetectFastqFormat.run(in_file)
        sanger = ["sanger", "illumina_1.8+"]

        # if it is a sanger variant, 33 if not return the base 64
        if any([x in formats for x in sanger]):
            return 33
        else:
            return 64

    def in2trimmed(self, in_file):
        """
        return expected out_file name if cutadapt is run on
        in_file

        """
        basename = os.path.basename(in_file)
        base, _ = os.path.splitext(basename)
        safe_makedir(self.out_dir)
        return os.path.join(self.out_dir, base + "_trimmed.fq")

    def _get_adapters(self, chemistry):
        adapters = [ADAPTERS.get(x, []) for x in chemistry]
        adapters += self.user_adapters
        adapters = list(flatten(adapters))
        adapters += self._rc_adapters(adapters)
        adapter_args = [["-a", adapter] for adapter in adapters]
        return list(flatten(adapter_args))

    def _rc_adapters(self, adapters):
        rc = [str(Seq(x).reverse_complement()) for x in adapters]
        return rc

    def _cut_file(self, in_file):
        """
        run cutadapt on a single file

        """
        adapters = self._get_adapters(self.chemistry)
        out_file = self.in2trimmed(in_file)
        if file_exists(out_file):
            return out_file
        cutadapt = sh.Command(self.stage_config.get("program",
                                                    "cutadapt"))

        # if not sanger assume old style illumina
        quality_base = self._detect_fastq_format(in_file)

        # if we want to trim the polya tails we have to first remove
        # the adapters and then trim the tail
        if self.stage_config.get("trim_polya", True):
            temp_cut = tempfile.NamedTemporaryFile(suffix=".fq",
                                                   dir=self.out_dir)
            # trim off adapters
            cutadapt(in_file, self.options, adapters,
                     quality_base=quality_base,
                     _out=temp_cut.name)
            with file_transaction(out_file) as temp_out:
                polya = ADAPTERS.get("polya")
                # trim off polya
                cutadapt(temp_cut.name, self.options, "-a",
                         polya, "-a", self._rc_adapters(polya),
                         quality_base=quality_base,
                         _out=temp_out)
            return out_file
        else:
            with file_transaction(out_file) as temp_out:
                cutadapt(in_file, self.options, adapters,
                         _out=temp_out)
            return out_file

    def _run_se(self, in_file):
        # cut polyA tails and adapters off
        trimmed_file = self._cut_file(in_file)
        sickle = sh.Command(get_in(self.config,
                                   ("stage", "sickle", "program"),
                                   "sickle"))
        # remove reads that don't pass the length cut
        out_file = append_stem(trimmed_file, "sickle")
        quality_format = self._detect_fastq_format(in_file)
        if file_exists(out_file):
            return out_file
        with file_transaction(out_file) as temp_out:
            sickle.se(f=trimmed_file, l=20, o=temp_out, t=quality_format)

        return out_file

    def _run_pe(self, in_files):
        trimmed_files = map(self._cut_file, in_files)
        sickle = sh.Command(get_in(self.config,
                                   ("stage", "sickle", "program"),
                                   "sickle"))
        out_files = [append_stem(x, "sickle") for x in trimmed_files]
        quality_format = self._detect_fastq_format(in_files[0])
        single_file = append_stem(trimmed_files[0], "singles")
        if all(map(file_exists, out_files)):
            return out_files
        with file_transaction(out_files) as tmp_out_files:
            sickle.pe(f=trimmed_files[0], r=trimmed_files[1], l=20,
                      o=tmp_out_files[0], p=tmp_out_files[1],
                      t=quality_format, s=single_file)

        return out_files

    def __call__(self, in_file):
        if is_pair(in_file):
            out_files = self._run_pe(in_file)
            return out_files
        elif isinstance(in_file, str):
            out_file = self._run_se(in_file)
            return out_file
        else:
            raise ValueError("Cutadapt can only run on either a single "
                             "file as a string or a pair of files to "
                             "handle paired end data.")
<commit_msg>Fixed quality format detection for sickle.<commit_after>"""
wrappers around Trim galore! and cutadapt for trimming off common adapter
sequences used in NGS

Trim galore!: http://www.bioinformatics.babraham.ac.uk/projects/trim_galore/
cutadapt: https://github.com/marcelm/cutadapt
sickle: https://github.com/najoshi/sickle
"""

from bcbio.distributed.transaction import file_transaction
from bcbio.utils import file_exists, safe_makedir
from bipy.pipeline.stages import AbstractStage
from bipy.utils import flatten, append_stem, get_in, is_pair
import sh
import os
from pkg_resources import resource_stream
import yaml
from Bio.Seq import Seq
import tempfile
from bipy.toolbox.fastq import DetectFastqFormat

with resource_stream(__name__, 'data/adapters.yaml') as in_handle:
    ADAPTERS = yaml.load(in_handle)

class TrimGalore(AbstractStage):
    """
    runs trim_galore on the data to trim off adapters, polyA tails and
    other contaminating sequences
    http://www.bioinformatics.babraham.ac.uk/projects/trim_galore/

    """

    stage = "trim_galore"

    def __init__(self, config):
        self.config = config
        self.stage_config = get_in(config, ("stage", self.stage), {})
        self.chemistry = self.stage_config.get("chemistry", "truseq")
        if not isinstance(self.chemistry, list):
            self.chemistry = [self.chemistry]

        self.options = self.stage_config.get("options", "")
        self.trim_galore = sh.Command(self.stage_config.get("program",
                                                            "trim_galore"))
        self.out_dir_prefix = get_in(config, ("dir", "results"),
                                     "results") + self.stage
        self.trim_polya = self.stage_config.get("trim_polya", True)
        safe_makedir(self.out_dir_prefix)

    def get_adapters(self, chemistry):
        return list(flatten([["-a", x] for x in ADAPTERS.get(chemistry, [])]))

    def _in2out(self, in_file):
        base, _ = os.path.splitext(in_file)
        return base + "_trimmed.fq"

    def __call__(self, in_file):
        raise NotImplementedError("Waiting to hear back from maintainer to "
                                  "handle multiple adapters before finishing.")
        adapters = list(flatten(map(self.get_adapters, self.chemistry)))
        # if it is a list assume these are pairs
        if isinstance(in_file, list):
            out_files = map(self._in2out, in_file)
            if all(map(file_exists, out_files)):
                return out_files
            self.trim_galore(in_file, self.options, adapters, paired=True)
            return out_files
        # if it is only one file just run it
        else:
            out_file = self._in2out(in_file)
            if file_exists(out_file):
                return out_file
            self.trim_galore(in_file, self.options, adapters)
            return out_file

class Cutadapt(AbstractStage):

    stage = "cutadapt"

    def __init__(self, config):
        self.config = config
        self.stage_config = get_in(config, ("stage", self.stage), {})
        self.chemistry = self.stage_config.get("chemistry", "truseq")
        if not isinstance(self.chemistry, list):
            self.chemistry = [self.chemistry]

        self.options = self.stage_config.get("options", "")
        self.user_adapters = self.stage_config.get("adapters", [])
        self.out_dir = os.path.join(get_in(self.config, ("dir", "results"),
                                           "results"), self.stage)

    def _detect_fastq_format(self, in_file):
        formats = DetectFastqFormat.run(in_file)
        sanger = ["sanger", "illumina_1.8+"]

        # if it is a sanger variant, 33 if not return the base 64
        if any([x in formats for x in sanger]):
            return "sanger"
        else:
            return "illumina"

    def in2trimmed(self, in_file):
        """
        return expected out_file name if cutadapt is run on
        in_file

        """
        basename = os.path.basename(in_file)
        base, _ = os.path.splitext(basename)
        safe_makedir(self.out_dir)
        return os.path.join(self.out_dir, base + "_trimmed.fq")

    def _get_adapters(self, chemistry):
        adapters = [ADAPTERS.get(x, []) for x in chemistry]
        adapters += self.user_adapters
        adapters = list(flatten(adapters))
        adapters += self._rc_adapters(adapters)
        adapter_args = [["-a", adapter] for adapter in adapters]
        return list(flatten(adapter_args))

    def _rc_adapters(self, adapters):
        rc = [str(Seq(x).reverse_complement()) for x in adapters]
        return rc

    def _cut_file(self, in_file):
        """
        run cutadapt on a single file

        """
        adapters = self._get_adapters(self.chemistry)
        out_file = self.in2trimmed(in_file)
        if file_exists(out_file):
            return out_file
        cutadapt = sh.Command(self.stage_config.get("program",
                                                    "cutadapt"))

        # if not sanger assume old style illumina
        quality_format = self._detect_fastq_format(in_file)
        if quality_format == "sanger":
            quality_base = 33
        else:
            quality_base = 64

        # if we want to trim the polya tails we have to first remove
        # the adapters and then trim the tail
        if self.stage_config.get("trim_polya", True):
            temp_cut = tempfile.NamedTemporaryFile(suffix=".fq",
                                                   dir=self.out_dir)
            # trim off adapters
            cutadapt(in_file, self.options, adapters,
                     quality_base=quality_base,
                     _out=temp_cut.name)
            with file_transaction(out_file) as temp_out:
                polya = ADAPTERS.get("polya")
                # trim off polya
                cutadapt(temp_cut.name, self.options, "-a",
                         polya, "-a", self._rc_adapters(polya),
                         quality_base=quality_base,
                         _out=temp_out)
            return out_file
        else:
            with file_transaction(out_file) as temp_out:
                cutadapt(in_file, self.options, adapters,
                         _out=temp_out)
            return out_file

    def _run_se(self, in_file):
        # cut polyA tails and adapters off
        trimmed_file = self._cut_file(in_file)
        sickle = sh.Command(get_in(self.config,
                                   ("stage", "sickle", "program"),
                                   "sickle"))
        # remove reads that don't pass the length cut
        out_file = append_stem(trimmed_file, "sickle")
        quality_format = self._detect_fastq_format(in_file)
        if file_exists(out_file):
            return out_file
        with file_transaction(out_file) as temp_out:
            sickle.se(f=trimmed_file, l=20, o=temp_out, t=quality_format)

        return out_file

    def _run_pe(self, in_files):
        trimmed_files = map(self._cut_file, in_files)
        sickle = sh.Command(get_in(self.config,
                                   ("stage", "sickle", "program"),
                                   "sickle"))
        out_files = [append_stem(x, "sickle") for x in trimmed_files]
        quality_format = self._detect_fastq_format(in_files[0])
        single_file = append_stem(trimmed_files[0], "singles")
        if all(map(file_exists, out_files)):
            return out_files
        with file_transaction(out_files) as tmp_out_files:
            sickle.pe(f=trimmed_files[0], r=trimmed_files[1], l=20,
                      o=tmp_out_files[0], p=tmp_out_files[1],
                      t=quality_format, s=single_file)

        return out_files

    def __call__(self, in_file):
        if is_pair(in_file):
            out_files = self._run_pe(in_file)
            return out_files
        elif isinstance(in_file, str):
            out_file = self._run_se(in_file)
            return out_file
        else:
            raise ValueError("Cutadapt can only run on either a single "
                             "file as a string or a pair of files to "
                             "handle paired end data.")
<|endoftext|>


<commit_before>from flask import Flask
from flask import request
from flask import make_response
import json
import logging as l

app = Flask(__name__)
app.config['DEBUG'] = True

# Note: We don't need to call run() since our application is embedded within
# the App Engine WSGI application server.

@app.route('/')
def hello():
    """Return a friendly HTTP greeting."""
    print "there u go"
    return 'Hello my Beaturiful World!\n'

@app.route('/apiai', methods=['POST'])
def yello():
    """Return a friendly HTTP greeting."""
    l.info("11")
    #print "1"
    speech = "This is a reponse from GAE !!"
    #print "2"
    l.info("22")
    my_response = {
     "speech" : speech,
     "displayText " : speech,
    }
    l.info("33")
    #print "3"
    res = json.dumps(my_response)
    l.info("44")
    #print "4"
    r = make_response(res)
    l.info("55")
    #print "5"
    #print r
    #print type(r)
    r.headers['Content-Type'] = 'application/json'
    l.info("66")
    #print  type(r)
    #print "5"
    l.info("77")
    return r

@app.errorhandler(404)
def page_not_found(e):
    """Return a custom 404 error."""
    return 'Sorry, nothing at this URL.', 404
<commit_msg>changed to main<commit_after>from flask import Flask
from flask import request
from flask import make_response
import json
import logging as l

app = Flask(__name__)

# Note: We don't need to call run() since our application is embedded within
# the App Engine WSGI application server.

@app.route('/')
def hello():
    """Return a friendly HTTP greeting."""
    l.info("reached the hello() module...")

    return 'Hello my Beaturiful World!\n'

@app.route('/apiai', methods=['POST'])
def apiai_response():
    """Return a static message to api.ai."""
    """Naresh  Ganatra"""

    l.info("reached apaai_response module ...... ")

    speech = "This is a reponse from GAE !! "

    my_response = {
     "speech" : speech,
     "displayText " : speech,
    }

    res = json.dumps(my_response)
    r = make_response(res)
    r.headers['Content-Type'] = 'application/json'

    l.info("Exiting the  apaai_response module ...... ")

    return r

@app.errorhandler(404)
def page_not_found(e):
    """Return a custom 404 error."""
    return 'Sorry, nothing at this URL.', 404
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Licensed under a MIT style license - see LICENSE.rst

"""Generate paths to BOSS data files.

The path module provides convenience methods for building the paths of frequently used
data files.  Most scripts will create a single :class:`Finder` object using the default
constructor for this purpose::

    import bossdata.path
    finder = bossdata.path.Finder()

This finder object is normally configured by the `$BOSS_SAS_PATH` and `$BOSS_REDUX_VERSION`
environment variables and no other modules uses these variables, except through a
a :class:`Finder` object.  These parameters can also be set by :class:`Finder` constructor
arguments. When neither the environment variables nor the constructor arguments are set,
defaults appropriate for the most recent public data release (DR12) are used.

:class:`Finder` objects never interact with any local or
remote filesystems: use the :mod:`bossdata.remote` module to download data files
and access them locally. See :doc:`/usage` for recommendations
on using the :mod:`bossdata.path` and :mod:`bossdata.remote` modules together.
"""

from __future__ import division, print_function

import os
import posixpath

from bossdata.plate import get_num_fibers

class Finder(object):
    """Initialize a path finder object.

    When the constructor is called with no arguments, it will raise a ValueError if either
    BOSS_SAS_PATH or BOSS_REDUX_VERSION is not set.

    Args:
        sas_path(str): Location of the SAS root path to use, e.g., /sas/dr12. Will use the
            value of the BOSS_SAS_PATH environment variable if this is not set.
        redux_version(str): String tag specifying the BOSS spectro reduction version to use,
            e.g., v5_7_0. Will use the value of the BOSS_REDUX_VERSION environment variable
            if this is not set.

    Raises:
        ValueError: No SAS root or redux version specified on the command line or via
            environment variables.
    """
    def __init__(self, sas_path=None, redux_version=None, verbose=True):
        # Environment variables override the constructor args if they are set.
        self.sas_path = os.getenv('BOSS_SAS_PATH', sas_path)
        if self.sas_path is None:
            self.sas_path = Finder.default_sas_path
            if verbose:
                print('Using the default "{}" since $BOSS_SAS_PATH is not set.'.format(
                    self.sas_path))

        self.redux_version = os.getenv('BOSS_REDUX_VERSION', redux_version)
        if self.redux_version is None:
            self.redux_version = Finder.default_redux_version
            if verbose:
                print('Using the default "{}" since $BOSS_REDUX_VERSION is not set.'.format(
                    self.redux_version))

        self.redux_base = posixpath.join(self.sas_path, 'spectro', 'redux', self.redux_version)

    default_sas_path = '/sas/dr12/boss'
    """Default to use when $BOSS_SAS_PATH is not set.

    See :doc:`/scripts` and :doc:`/usage` for details.
    """

    default_redux_version = 'v5_7_0'
    """Default to use when $BOSS_REDUX_VERSION is not set.

    See :doc:`/scripts` and :doc:`/usage` for details.
    """

    def get_plate_path(self, plate, filename=None):
        """Get the path to the specified plate directory or file.

        The returned path contains files that include all targets on the plate. Use the
        :meth:`get_spec_path` method for the path of a single spectrum file.

        This method only performs minimal checks that the requested plate number is valid.

        Args:
            plate(int): Plate number, which must be positive.
            filename(str): Name of a file within the plate directory to append to the
                returned path.

        Returns:
            str: Full path to the specified plate directory or file within this directory.

        Raises:
            ValueError: Invalid plate number must be > 0.
        """
        if plate < 0:
            raise ValueError('Invalid plate number ({}) must be > 0.'.format(plate))

        path = posixpath.join(self.redux_base, '{:04d}'.format(plate))
        if filename:
            path = posixpath.join(path, filename)
        return path

    def get_plate_plan_path(self, plate, mjd, combined=True):
        """Get the path to the specified plate plan file.

        A combined plan may span several nearby MJDs, in which case the last MJD is
        the one used to identify the plan.

        Args:
            plate(int): Plate number, which must be positive.
            mjd(int): Modified Julian date of the observation, which must be > 45000.
            combined(bool): Specifies the combined plan, which spans all MJDs
                associated with a coadd, but does not include calibration frames
                (arcs,flats) for a specific MJD.

        Returns:
            str: Full path to the requested plan file.

        Raises:
            ValueError: Invalid plate or mjd inputs.
        """
        if mjd <= 45000:
            raise ValueError('Invalid mjd ({}) must be >= 45000.'.format(mjd))

        if combined:
            filename = 'spPlancomb-{plate:04d}-{mjd:5d}.par'.format(plate=plate, mjd=mjd)
        else:
            filename = 'spPlan2d-{plate:04d}-{mjd:5d}.par'.format(plate=plate, mjd=mjd)
        return posixpath.join(self.get_plate_path(plate), filename)

    def get_plate_spec_path(self, plate, mjd):
        """Get the path to the file containing combined spectra for a whole plate.

        Combined spectra for all exposures of a plate are packaged in spPlate files
        http://data.sdss3.org/datamodel/files/BOSS_SPECTRO_REDUX/RUN2D/PLATE4/spPlate.html
        As of DR12, these files are about 110Mb for 1000 spectra.

        Args:
            plate(int): Plate number, which must be positive.
            mjd(int): Modified Julian date of the observation, which must be > 45000.

        Returns:
            str: Full path to the requested plan file.

        Raises:
            ValueError: Invalid plate or mjd inputs.
        """
        if mjd <= 45000:
            raise ValueError('Invalid mjd ({}) must be >= 45000.'.format(mjd))

        filename = 'spPlate-{plate:04d}-{mjd:5d}.fits'.format(plate=plate, mjd=mjd)
        return posixpath.join(self.get_plate_path(plate), filename)

    def get_sp_all_path(self, lite=True):
        """Get the location of the metadata summary file.

        The data model of the full (non-lite) file is at
        http://dr12.sdss3.org/datamodel/files/BOSS_SPECTRO_REDUX/RUN2D/spAll.html
        As of DR12, the full file size is about 10Gb and the lite file is about 115Mb.

        Args:
            lite(bool): Specifies the "lite" version which contains all rows but only the
                most commonly used subset of columns. The lite version is a compressed (.gz)
                text data file, while the full version is a FITS file.
        """
        if lite:
            name = 'spAll-{}.dat.gz'.format(self.redux_version)
        else:
            name = 'spAll-{}.fits'.format(self.redux_version)
        return posixpath.join(self.redux_base, name)

    def get_platelist_path(self):
        """Get the location of the platelist summary file.
        """
        name = 'platelist.fits'
        return posixpath.join(self.redux_base, name)

    default_quasar_catalog_name = 'DR12Q'
    """Default quasar catalog name.

    For more info about the BOSS quasar catalog, see
    http://www.sdss.org/dr12/algorithms/boss-dr12-quasar-catalog/
    """

    def get_quasar_catalog_path(self, catalog_name=None):
        """Get the location of the quasar catalog file.

        The data model of the quasar catalog is at
        http://data.sdss3.org/datamodel/files/BOSS_QSO/DR12Q/DR12Q.html
        As of DR12, the file size is about 513Mb.

        Additional information is available at
        http://www.sdss.org/dr12/algorithms/boss-dr12-quasar-catalog/

        Args:
            catalog_name(str): BOSS quasar catalog name. Will use the
                :meth:`get_default_quasar_catalog_name` method if this is not set.
        """
        if catalog_name is None:
            catalog_name = self.default_quasar_catalog_name
        filename = '{}.fits'.format(catalog_name)
        return posixpath.join(self.sas_path, 'qso', catalog_name, filename)

    def get_spec_path(self, plate, mjd, fiber, lite=True):
        """Get the location of the spectrum file for the specified observation.

        The DR12 data model for the returned files is at
        http://dr12.sdss3.org/datamodel/files/BOSS_SPECTRO_REDUX/RUN2D/spectra/PLATE4/spec.html
        but only HDUs 0-3 are included in the (default) lite format.
        Each lite (full) file is approximately 0.2Mb (1.7Mb) in size.

        Use the :meth:`get_plate_path` method for the path to files that include all targets
        on a plate.

        This method only performs minimal checks that the requested plate-mjd-fiber are valid.

        Args:
            plate(int): Plate number, which must be positive.
            mjd(int): Modified Julian date of the observation, which must be > 45000.
            fiber(int): Fiber number of the target on this plate, which must be in the
                range 1-1000 (or 1-640 for plate < 3510).
            lite(bool): Specifies the "lite" version which contains only HDUs 0-3, so no
                per-exposure data is included.

        Returns:
            str: Full path to the spectrum file for the specified observation.

        Raises:
            ValueError: Invalid plate, mjd or fiber inputs.
        """
        if plate < 0:
            raise ValueError('Invalid plate number ({}) must be > 0.'.format(plate))
        if mjd <= 45000:
            raise ValueError('Invalid mjd ({}) must be >= 45000.'.format(mjd))
        if fiber < 1 or fiber > get_num_fibers(plate):
            raise ValueError('Invalid fiber ({}) must be 1-{} for plate {}.'.format(
                fiber, get_num_fibers(plate), plate))

        path = 'spectra'
        plate_label = '{:04d}'.format(plate)
        if lite:
            path = posixpath.join(path, 'lite')
        name = 'spec-{plate}-{mjd:5d}-{fiber:04d}.fits'.format(
            plate=plate_label, mjd=mjd, fiber=fiber)
        return posixpath.join(self.redux_base, path, plate_label, name)
<commit_msg>Start get_raw_path method<commit_after># -*- coding: utf-8 -*-
# Licensed under a MIT style license - see LICENSE.rst

"""Generate paths to BOSS data files.

The path module provides convenience methods for building the paths of frequently used
data files.  Most scripts will create a single :class:`Finder` object using the default
constructor for this purpose::

    import bossdata.path
    finder = bossdata.path.Finder()

This finder object is normally configured by the `$BOSS_SAS_PATH` and `$BOSS_REDUX_VERSION`
environment variables and no other modules uses these variables, except through a
a :class:`Finder` object.  These parameters can also be set by :class:`Finder` constructor
arguments. When neither the environment variables nor the constructor arguments are set,
defaults appropriate for the most recent public data release (DR12) are used.

:class:`Finder` objects never interact with any local or
remote filesystems: use the :mod:`bossdata.remote` module to download data files
and access them locally. See :doc:`/usage` for recommendations
on using the :mod:`bossdata.path` and :mod:`bossdata.remote` modules together.
"""

from __future__ import division, print_function

import os
import posixpath

from bossdata.plate import get_num_fibers

class Finder(object):
    """Initialize a path finder object.

    When the constructor is called with no arguments, it will raise a ValueError if either
    BOSS_SAS_PATH or BOSS_REDUX_VERSION is not set.

    Args:
        sas_path(str): Location of the SAS root path to use, e.g., /sas/dr12. Will use the
            value of the BOSS_SAS_PATH environment variable if this is not set.
        redux_version(str): String tag specifying the BOSS spectro reduction version to use,
            e.g., v5_7_0. Will use the value of the BOSS_REDUX_VERSION environment variable
            if this is not set.

    Raises:
        ValueError: No SAS root or redux version specified on the command line or via
            environment variables.
    """
    def __init__(self, sas_path=None, redux_version=None, verbose=True):
        # Environment variables override the constructor args if they are set.
        self.sas_path = os.getenv('BOSS_SAS_PATH', sas_path)
        if self.sas_path is None:
            self.sas_path = Finder.default_sas_path
            if verbose:
                print('Using the default "{}" since $BOSS_SAS_PATH is not set.'.format(
                    self.sas_path))

        self.redux_version = os.getenv('BOSS_REDUX_VERSION', redux_version)
        if self.redux_version is None:
            self.redux_version = Finder.default_redux_version
            if verbose:
                print('Using the default "{}" since $BOSS_REDUX_VERSION is not set.'.format(
                    self.redux_version))

        self.redux_base = posixpath.join(self.sas_path, 'spectro', 'redux', self.redux_version)

    default_sas_path = '/sas/dr12/boss'
    """Default to use when $BOSS_SAS_PATH is not set.

    See :doc:`/scripts` and :doc:`/usage` for details.
    """

    default_redux_version = 'v5_7_0'
    """Default to use when $BOSS_REDUX_VERSION is not set.

    See :doc:`/scripts` and :doc:`/usage` for details.
    """

    def get_plate_path(self, plate, filename=None):
        """Get the path to the specified plate directory or file.

        The returned path contains files that include all targets on the plate. Use the
        :meth:`get_spec_path` method for the path of a single spectrum file.

        This method only performs minimal checks that the requested plate number is valid.

        Args:
            plate(int): Plate number, which must be positive.
            filename(str): Name of a file within the plate directory to append to the
                returned path.

        Returns:
            str: Full path to the specified plate directory or file within this directory.

        Raises:
            ValueError: Invalid plate number must be > 0.
        """
        if plate < 0:
            raise ValueError('Invalid plate number ({}) must be > 0.'.format(plate))

        path = posixpath.join(self.redux_base, '{:04d}'.format(plate))
        if filename:
            path = posixpath.join(path, filename)
        return path

    def get_plate_plan_path(self, plate, mjd, combined=True):
        """Get the path to the specified plate plan file.

        A combined plan may span several nearby MJDs, in which case the last MJD is
        the one used to identify the plan.

        Args:
            plate(int): Plate number, which must be positive.
            mjd(int): Modified Julian date of the observation, which must be > 45000.
            combined(bool): Specifies the combined plan, which spans all MJDs
                associated with a coadd, but does not include calibration frames
                (arcs,flats) for a specific MJD.

        Returns:
            str: Full path to the requested plan file.

        Raises:
            ValueError: Invalid plate or mjd inputs.
        """
        if mjd <= 45000:
            raise ValueError('Invalid mjd ({}) must be >= 45000.'.format(mjd))

        if combined:
            filename = 'spPlancomb-{plate:04d}-{mjd:5d}.par'.format(plate=plate, mjd=mjd)
        else:
            filename = 'spPlan2d-{plate:04d}-{mjd:5d}.par'.format(plate=plate, mjd=mjd)
        return posixpath.join(self.get_plate_path(plate), filename)

    def get_plate_spec_path(self, plate, mjd):
        """Get the path to the file containing combined spectra for a whole plate.

        Combined spectra for all exposures of a plate are packaged in spPlate files
        http://data.sdss3.org/datamodel/files/BOSS_SPECTRO_REDUX/RUN2D/PLATE4/spPlate.html
        As of DR12, these files are about 110Mb for 1000 spectra.

        Args:
            plate(int): Plate number, which must be positive.
            mjd(int): Modified Julian date of the observation, which must be > 45000.

        Returns:
            str: Full path to the requested plan file.

        Raises:
            ValueError: Invalid plate or mjd inputs.
        """
        if mjd <= 45000:
            raise ValueError('Invalid mjd ({}) must be >= 45000.'.format(mjd))

        filename = 'spPlate-{plate:04d}-{mjd:5d}.fits'.format(plate=plate, mjd=mjd)
        return posixpath.join(self.get_plate_path(plate), filename)

    def get_sp_all_path(self, lite=True):
        """Get the location of the metadata summary file.

        The data model of the full (non-lite) file is at
        http://dr12.sdss3.org/datamodel/files/BOSS_SPECTRO_REDUX/RUN2D/spAll.html
        As of DR12, the full file size is about 10Gb and the lite file is about 115Mb.

        Args:
            lite(bool): Specifies the "lite" version which contains all rows but only the
                most commonly used subset of columns. The lite version is a compressed (.gz)
                text data file, while the full version is a FITS file.
        """
        if lite:
            name = 'spAll-{}.dat.gz'.format(self.redux_version)
        else:
            name = 'spAll-{}.fits'.format(self.redux_version)
        return posixpath.join(self.redux_base, name)

    def get_platelist_path(self):
        """Get the location of the platelist summary file.
        """
        name = 'platelist.fits'
        return posixpath.join(self.redux_base, name)

    default_quasar_catalog_name = 'DR12Q'
    """Default quasar catalog name.

    For more info about the BOSS quasar catalog, see
    http://www.sdss.org/dr12/algorithms/boss-dr12-quasar-catalog/
    """

    def get_quasar_catalog_path(self, catalog_name=None):
        """Get the location of the quasar catalog file.

        The data model of the quasar catalog is at
        http://data.sdss3.org/datamodel/files/BOSS_QSO/DR12Q/DR12Q.html
        As of DR12, the file size is about 513Mb.

        Additional information is available at
        http://www.sdss.org/dr12/algorithms/boss-dr12-quasar-catalog/

        Args:
            catalog_name(str): BOSS quasar catalog name. Will use the
                :meth:`get_default_quasar_catalog_name` method if this is not set.
        """
        if catalog_name is None:
            catalog_name = self.default_quasar_catalog_name
        filename = '{}.fits'.format(catalog_name)
        return posixpath.join(self.sas_path, 'qso', catalog_name, filename)

    def get_raw_path(self, camera, exposure):
        """Get the location of the raw data for the specified camera and exposure.

        The DR12 data model for BOSS raw data in the sdR format is at
        http://data.sdss3.org/datamodel/files/BOSS_SPECTRO_DATA/MJD/sdR.html

        Args:
            camara(str): One of b1, b2, r1, r2.
            exposure(int): Exposure number to return, which should be

        Raises:
            ValueError: Invalid camera or exposure number.
        """
        if camera not in ('b1', 'b2', 'r1', 'r2'):
            raise ValueError(
                'Unexpected camera ({}) should be one of b1, b2, r1, r2.'.format(camera))

    def get_spec_path(self, plate, mjd, fiber, lite=True):
        """Get the location of the spectrum file for the specified observation.

        The DR12 data model for the returned files is at
        http://dr12.sdss3.org/datamodel/files/BOSS_SPECTRO_REDUX/RUN2D/spectra/PLATE4/spec.html
        but only HDUs 0-3 are included in the (default) lite format.
        Each lite (full) file is approximately 0.2Mb (1.7Mb) in size.

        Use the :meth:`get_plate_path` method for the path to files that include all targets
        on a plate.

        This method only performs minimal checks that the requested plate-mjd-fiber are valid.

        Args:
            plate(int): Plate number, which must be positive.
            mjd(int): Modified Julian date of the observation, which must be > 45000.
            fiber(int): Fiber number of the target on this plate, which must be in the
                range 1-1000 (or 1-640 for plate < 3510).
            lite(bool): Specifies the "lite" version which contains only HDUs 0-3, so no
                per-exposure data is included.

        Returns:
            str: Full path to the spectrum file for the specified observation.

        Raises:
            ValueError: Invalid plate, mjd or fiber inputs.
        """
        if plate < 0:
            raise ValueError('Invalid plate number ({}) must be > 0.'.format(plate))
        if mjd <= 45000:
            raise ValueError('Invalid mjd ({}) must be >= 45000.'.format(mjd))
        if fiber < 1 or fiber > get_num_fibers(plate):
            raise ValueError('Invalid fiber ({}) must be 1-{} for plate {}.'.format(
                fiber, get_num_fibers(plate), plate))

        path = 'spectra'
        plate_label = '{:04d}'.format(plate)
        if lite:
            path = posixpath.join(path, 'lite')
        name = 'spec-{plate}-{mjd:5d}-{fiber:04d}.fits'.format(
            plate=plate_label, mjd=mjd, fiber=fiber)
        return posixpath.join(self.redux_base, path, plate_label, name)
<|endoftext|>


<commit_before>import abc
import os
import re
import sys
import warnings

import sqlalchemy

import whoosh
import whoosh.fields
import whoosh.index
import whoosh.qparser

from flask_sqlalchemy import models_committed, BaseQuery
from sqlalchemy import text
from sqlalchemy.orm.mapper import Mapper

class WhoosheeQuery(BaseQuery):
    """An override for SQLAlchemy query used to do fulltext search."""

    def whooshee_search(self, search_string, group=whoosh.qparser.OrGroup, whoosheer=None,
                        match_substrings=True, limit=None, order_by_relevance=10):
        """Do a fulltext search on the query.

        Args:
            search_string: string to search for
            group: whoosh group to use for searching, defaults to OrGroup (searches for all
                   words in all columns)
            match_substrings: True if you want to match substrings, False otherwise
            limit: number of the top records to be returned, default None returns all records

        Returns:
            query filtered with results of the fulltext search
        """
        if not whoosheer:
            ### inspiration taken from flask-WhooshAlchemy
            # find out all entities in join
            entities = set()
            # directly queried entities
            for cd in self.column_descriptions:
                entities.add(cd['type'])
            # joined entities
            if self._join_entities and isinstance(self._join_entities[0], Mapper):
                # SQLAlchemy >= 0.8.0
                entities.update(set([x.entity for x in self._join_entities]))
            else:
                # SQLAlchemy < 0.8.0
                entities.update(set(self._join_entities))

            whoosheer = next(w for w in Whooshee.whoosheers if set(w.models) == entities)

        # TODO what if unique field doesn't exist or there are multiple?
        for fname, field in list(whoosheer.schema._fields.items()):
            if field.unique:
                uniq = fname

        # TODO: use something more general than id
        res = whoosheer.search(search_string=search_string,
                               values_of=uniq,
                               group=group,
                               match_substrings=match_substrings,
                               limit=limit)
        if not res:
            return self.filter(text('null'))

        # transform unique field name into model attribute field
        attr = None

        if hasattr(whoosheer, '_is_model_whoosheer'):
            attr = getattr(whoosheer.models[0], uniq)
        else:
            # non-model whoosheers must have unique field named
            # model.__name__.lower + '_' + attr
            for m in whoosheer.models:
                if m.__name__.lower() == uniq.split('_')[0]:
                    attr = getattr(m, uniq.split('_')[1])

        search_query = self.filter(attr.in_(res))

        if order_by_relevance < 0: # we want all returned rows ordered
            search_query = search_query.order_by(sqlalchemy.sql.expression.case(
                [(attr == uniq_val, index) for index, uniq_val in enumerate(res)],
            ))
        elif order_by_relevance > 0: # we want only number of specified rows ordered
            search_query = search_query.order_by(sqlalchemy.sql.expression.case(
                [(attr == uniq_val, index) for index, uniq_val in enumerate(res) if index < order_by_relevance],
                else_=order_by_relevance
            ))
        else: # no ordering
            pass

        return search_query

class AbstractWhoosheer(object):
    """A superclass for all whoosheers.

    Whoosheer is basically a unit of fulltext search. It represents either of:

    * One table, in which case all given fields of the model is searched.
    * More tables, in which case all given fields of all the tables are searched.
    """

    @classmethod
    def search(cls, search_string, values_of='', group=whoosh.qparser.OrGroup, match_substrings=True, limit=None):
        """Actually searches the fields for given search_string.

        Args:
            search_string: string to search for
            values_of: if given, the method will not return the whole records, but only values
                       of given column (defaults to returning whole records)
            group: whoosh group to use for searching, defaults to OrGroup (searches for all
                   words in all columns)
            match_substrings: True if you want to match substrings, False otherwise
            limit: number of the top records to be returned, default None returns all records

        Returns:
            Found records if 'not values_of', else values of given column
        """
        prepped_string = cls.prep_search_string(search_string, match_substrings)
        with cls.index.searcher() as searcher:
            parser = whoosh.qparser.MultifieldParser(cls.schema.names(), cls.index.schema, group=group)
            query = parser.parse(prepped_string)
            results = searcher.search(query, limit=limit)
            if values_of:
                return [x[values_of] for x in results]
            return results

    @classmethod
    def prep_search_string(cls, search_string, match_substrings):
        """Prepares search string as a proper whoosh search string."""
        s = search_string.strip()
        # we don't want stars from user
        s = s.replace('*', '')
        if len(s) < cls.search_string_min_len:
            raise ValueError('Search string must have at least 3 characters')
        # replace multiple with star space star
        if match_substrings:
            s = u'*{0}*'.format(re.sub('[\s]+', '* *', s))
        # TODO: some sanitization
        return s

AbstractWhoosheerMeta = abc.ABCMeta('AbstractWhoosheer', (AbstractWhoosheer,), {})

class Whooshee(object):
    """A top level class that allows to register whoosheers and adds an on_commit hook
    to SQLAlchemy."""

    _underscore_re1 = re.compile(r'(.)([A-Z][a-z]+)')
    _underscore_re2 = re.compile('([a-z0-9])([A-Z])')
    whoosheers = []

    def __init__(self, app=None):

        if app:
            self.init_app(app)

    def init_app(self, app):

        self.index_path_root = app.config.get('WHOOSHEE_DIR', '') or 'whooshee'
        self.writer_timeout = app.config.get('WHOOSHEE_WRITER_TIMEOUT', 2)
        self.search_string_min_len = app.config.get('WHOOSHEE_MIN_STRING_LEN', 3)

        if app.config.get('WHOOSHE_MIN_STRING_LEN', None) is not None:
            warnings.warn(WhoosheeDeprecationWarning("The config key WHOOSHE_MIN_STRING_LEN has been renamed to WHOOSHEE_MIN_STRING_LEN. The mispelled config key is deprecated and will be removed in upcoming releases. Change it to WHOOSHEE_MIN_STRING_LEN to suppress this warning"))
            self.search_string_min_len = app.config.get('WHOOSHE_MIN_STRING_LEN')

        models_committed.connect(self.on_commit, sender=app)
        if not os.path.exists(self.index_path_root):
            os.makedirs(self.index_path_root)

    def register_whoosheer(self, wh):
        """Registers a given whoosheer:

        * Creates and opens an index for it (if it doesn't exist yet)
        * Sets some default values on it (unless they're already set)
        * Replaces query class of every whoosheer's model by WhoosheeQuery
        """
        if not hasattr(wh, 'search_string_min_len'):
            wh.search_string_min_len = self.search_string_min_len
        if not hasattr(wh, 'index_subdir'):
            # TODO: do we really want/need to use camel casing?
            # everywhere else, there is just .lower()
            wh.index_subdir = self.camel_to_snake(wh.__name__)
        self.__class__.whoosheers.append(wh)
        self.create_index(wh)
        for model in wh.models:
            model.query_class = WhoosheeQuery
        return wh

    def register_model(self, *index_fields, **kw):
        """Registers a single model for fulltext search. This basically creates
        a simple Whoosheer for the model and calls self.register_whoosheer on it.
        """
        # construct subclass of AbstractWhoosheer for a model
        class ModelWhoosheer(AbstractWhoosheerMeta):
            pass

        mwh = ModelWhoosheer

        def inner(model):
            mwh.index_subdir = model.__tablename__
            mwh.models = [model]

            schema_attrs = {}
            for field in model.__table__.columns:
                if field.primary_key:
                    primary = field.name
                    schema_attrs[field.name] = whoosh.fields.NUMERIC(stored=True, unique=True)
                elif field.name in index_fields:
                    schema_attrs[field.name] = whoosh.fields.TEXT(**kw)
            mwh.schema = whoosh.fields.Schema(**schema_attrs)
            # we can't check with isinstance, because ModelWhoosheer is private
            # so use this attribute to find out
            mwh._is_model_whoosheer = True

            @classmethod
            def update_model(cls, writer, model):
                attrs = {primary: getattr(model, primary)}
                for f in index_fields:
                    attrs[f] = getattr(model, f)
                    if not isinstance(attrs[f], int):
                        if sys.version < '3':
                            attrs[f] = unicode(attrs[f])
                        else:
                            attrs[f] = str(attrs[f])
                writer.update_document(**attrs)

            @classmethod
            def insert_model(cls, writer, model):
                attrs = {primary: getattr(model, primary)}
                for f in index_fields:
                    attrs[f] = getattr(model, f)
                    if not isinstance(attrs[f], int):
                        if sys.version < '3':
                            attrs[f] = unicode(attrs[f])
                        else:
                            attrs[f] = str(attrs[f])
                writer.add_document(**attrs)

            @classmethod
            def delete_model(cls, writer, model):
                writer.delete_by_term(primary, getattr(model, primary))

            setattr(mwh, 'update_{0}'.format(model.__name__.lower()), update_model)
            setattr(mwh, 'insert_{0}'.format(model.__name__.lower()), insert_model)
            setattr(mwh, 'delete_{0}'.format(model.__name__.lower()), delete_model)

            model._whoosheer_ = mwh
            model.whoosh_search = mwh.search
            self.register_whoosheer(mwh)
            return model

        return inner

    def create_index(self, wh):
        """Creates and opens index for given whoosheer.

        If the index already exists, it just opens it, otherwise it creates it first.
        """
        index_path = os.path.join(self.index_path_root, wh.index_subdir)
        if whoosh.index.exists_in(index_path):
            index = whoosh.index.open_dir(index_path)
        else:
            if not os.path.exists(index_path):
                os.makedirs(index_path)
            index = whoosh.index.create_in(index_path, wh.schema)
        wh.index = index

    def on_commit(self, app, changes):
        """Method that gets connected to flask_sqlalchemy.models_committed, where it serves
        to do the actual index writing.
        """
        for wh in self.__class__.whoosheers:
            writer = None
            for change in changes:
                if change[0].__class__ in wh.models:
                    method_name = '{0}_{1}'.format(change[1], change[0].__class__.__name__.lower())
                    method = getattr(wh, method_name, None)
                    if method:
                        if not writer:
                            writer = wh.index.writer(timeout=self.writer_timeout)
                        method(writer, change[0])
            if writer:
                writer.commit()

    def camel_to_snake(self, s):
        """Constructs nice dir name from class name, e.g. FooBar => foo_bar."""
        return self._underscore_re2.sub(r'\1_\2', self._underscore_re1.sub(r'\1_\2', s)).lower()

    def reindex(self):
        """ Reindex all data

        This method retrieve all data from registered models and call
        update_<model>() function for every instance of such model.
        """
        for wh in self.__class__.whoosheers:
            writer = wh.index.writer(timeout=self.writer_timeout)
            for model in wh.models:
                method_name = "update_{0}".format(model.__name__.lower())
                for item in model.query.all():
                    getattr(wh, method_name)(writer, item)
            writer.commit()

class WhoosheeDeprecationWarning(DeprecationWarning):
    pass

warnings.simplefilter('always', WhoosheeDeprecationWarning)
<commit_msg>Now uses SQLAlchemy event system<commit_after>import abc
import os
import re
import sys
import warnings

import sqlalchemy

import whoosh
import whoosh.fields
import whoosh.index
import whoosh.qparser

from flask import current_app
from flask_sqlalchemy import BaseQuery
from sqlalchemy import text, event
from sqlalchemy.orm.mapper import Mapper

class WhoosheeQuery(BaseQuery):
    """An override for SQLAlchemy query used to do fulltext search."""

    def whooshee_search(self, search_string, group=whoosh.qparser.OrGroup, whoosheer=None,
                        match_substrings=True, limit=None, order_by_relevance=10):
        """Do a fulltext search on the query.

        Args:
            search_string: string to search for
            group: whoosh group to use for searching, defaults to OrGroup (searches for all
                   words in all columns)
            match_substrings: True if you want to match substrings, False otherwise
            limit: number of the top records to be returned, default None returns all records

        Returns:
            query filtered with results of the fulltext search
        """
        if not whoosheer:
            ### inspiration taken from flask-WhooshAlchemy
            # find out all entities in join
            entities = set()
            # directly queried entities
            for cd in self.column_descriptions:
                entities.add(cd['type'])
            # joined entities
            if self._join_entities and isinstance(self._join_entities[0], Mapper):
                # SQLAlchemy >= 0.8.0
                entities.update(set([x.entity for x in self._join_entities]))
            else:
                # SQLAlchemy < 0.8.0
                entities.update(set(self._join_entities))

            whoosheer = next(w for w in Whooshee.whoosheers if set(w.models) == entities)

        # TODO what if unique field doesn't exist or there are multiple?
        for fname, field in list(whoosheer.schema._fields.items()):
            if field.unique:
                uniq = fname

        # TODO: use something more general than id
        res = whoosheer.search(search_string=search_string,
                               values_of=uniq,
                               group=group,
                               match_substrings=match_substrings,
                               limit=limit)
        if not res:
            return self.filter(text('null'))

        # transform unique field name into model attribute field
        attr = None

        if hasattr(whoosheer, '_is_model_whoosheer'):
            attr = getattr(whoosheer.models[0], uniq)
        else:
            # non-model whoosheers must have unique field named
            # model.__name__.lower + '_' + attr
            for m in whoosheer.models:
                if m.__name__.lower() == uniq.split('_')[0]:
                    attr = getattr(m, uniq.split('_')[1])

        search_query = self.filter(attr.in_(res))

        if order_by_relevance < 0: # we want all returned rows ordered
            search_query = search_query.order_by(sqlalchemy.sql.expression.case(
                [(attr == uniq_val, index) for index, uniq_val in enumerate(res)],
            ))
        elif order_by_relevance > 0: # we want only number of specified rows ordered
            search_query = search_query.order_by(sqlalchemy.sql.expression.case(
                [(attr == uniq_val, index) for index, uniq_val in enumerate(res) if index < order_by_relevance],
                else_=order_by_relevance
            ))
        else: # no ordering
            pass

        return search_query

class AbstractWhoosheer(object):
    """A superclass for all whoosheers.

    Whoosheer is basically a unit of fulltext search. It represents either of:

    * One table, in which case all given fields of the model is searched.
    * More tables, in which case all given fields of all the tables are searched.
    """

    @classmethod
    def search(cls, search_string, values_of='', group=whoosh.qparser.OrGroup, match_substrings=True, limit=None):
        """Actually searches the fields for given search_string.

        Args:
            search_string: string to search for
            values_of: if given, the method will not return the whole records, but only values
                       of given column (defaults to returning whole records)
            group: whoosh group to use for searching, defaults to OrGroup (searches for all
                   words in all columns)
            match_substrings: True if you want to match substrings, False otherwise
            limit: number of the top records to be returned, default None returns all records

        Returns:
            Found records if 'not values_of', else values of given column
        """
        prepped_string = cls.prep_search_string(search_string, match_substrings)
        with cls.index.searcher() as searcher:
            parser = whoosh.qparser.MultifieldParser(cls.schema.names(), cls.index.schema, group=group)
            query = parser.parse(prepped_string)
            results = searcher.search(query, limit=limit)
            if values_of:
                return [x[values_of] for x in results]
            return results

    @classmethod
    def prep_search_string(cls, search_string, match_substrings):
        """Prepares search string as a proper whoosh search string."""
        s = search_string.strip()
        # we don't want stars from user
        s = s.replace('*', '')
        if len(s) < cls.search_string_min_len:
            raise ValueError('Search string must have at least 3 characters')
        # replace multiple with star space star
        if match_substrings:
            s = u'*{0}*'.format(re.sub('[\s]+', '* *', s))
        # TODO: some sanitization
        return s

AbstractWhoosheerMeta = abc.ABCMeta('AbstractWhoosheer', (AbstractWhoosheer,), {})

class Whooshee(object):
    """A top level class that allows to register whoosheers and adds an on_commit hook
    to SQLAlchemy."""

    _underscore_re1 = re.compile(r'(.)([A-Z][a-z]+)')
    _underscore_re2 = re.compile('([a-z0-9])([A-Z])')
    whoosheers = []

    def __init__(self, app=None):

        if app:
            self.init_app(app)

    def init_app(self, app):

        self.index_path_root = app.config.get('WHOOSHEE_DIR', '') or 'whooshee'
        self.writer_timeout = app.config.get('WHOOSHEE_WRITER_TIMEOUT', 2)
        self.search_string_min_len = app.config.get('WHOOSHEE_MIN_STRING_LEN', 3)

        if app.config.get('WHOOSHE_MIN_STRING_LEN', None) is not None:
            warnings.warn(WhoosheeDeprecationWarning("The config key WHOOSHE_MIN_STRING_LEN has been renamed to WHOOSHEE_MIN_STRING_LEN. The mispelled config key is deprecated and will be removed in upcoming releases. Change it to WHOOSHEE_MIN_STRING_LEN to suppress this warning"))
            self.search_string_min_len = app.config.get('WHOOSHE_MIN_STRING_LEN')

        if not os.path.exists(self.index_path_root):
            os.makedirs(self.index_path_root)

    def register_whoosheer(self, wh):
        """Registers a given whoosheer:

        * Creates and opens an index for it (if it doesn't exist yet)
        * Sets some default values on it (unless they're already set)
        * Replaces query class of every whoosheer's model by WhoosheeQuery
        """
        if not hasattr(wh, 'search_string_min_len'):
            wh.search_string_min_len = self.search_string_min_len
        if not hasattr(wh, 'index_subdir'):
            # TODO: do we really want/need to use camel casing?
            # everywhere else, there is just .lower()
            wh.index_subdir = self.camel_to_snake(wh.__name__)
        self.__class__.whoosheers.append(wh)
        self.create_index(wh)
        for model in wh.models:
            event.listen(model, 'after_insert', self.after_insert)
            event.listen(model, 'after_update', self.after_update)
            event.listen(model, 'after_delete', self.after_insert)
            model.query_class = WhoosheeQuery
        return wh

    def register_model(self, *index_fields, **kw):
        """Registers a single model for fulltext search. This basically creates
        a simple Whoosheer for the model and calls self.register_whoosheer on it.
        """
        # construct subclass of AbstractWhoosheer for a model
        class ModelWhoosheer(AbstractWhoosheerMeta):
            pass

        mwh = ModelWhoosheer

        def inner(model):
            mwh.index_subdir = model.__tablename__
            mwh.models = [model]

            schema_attrs = {}
            for field in model.__table__.columns:
                if field.primary_key:
                    primary = field.name
                    schema_attrs[field.name] = whoosh.fields.NUMERIC(stored=True, unique=True)
                elif field.name in index_fields:
                    schema_attrs[field.name] = whoosh.fields.TEXT(**kw)
            mwh.schema = whoosh.fields.Schema(**schema_attrs)
            # we can't check with isinstance, because ModelWhoosheer is private
            # so use this attribute to find out
            mwh._is_model_whoosheer = True

            @classmethod
            def update_model(cls, writer, model):
                attrs = {primary: getattr(model, primary)}
                for f in index_fields:
                    attrs[f] = getattr(model, f)
                    if not isinstance(attrs[f], int):
                        if sys.version < '3':
                            attrs[f] = unicode(attrs[f])
                        else:
                            attrs[f] = str(attrs[f])
                writer.update_document(**attrs)

            @classmethod
            def insert_model(cls, writer, model):
                attrs = {primary: getattr(model, primary)}
                for f in index_fields:
                    attrs[f] = getattr(model, f)
                    if not isinstance(attrs[f], int):
                        if sys.version < '3':
                            attrs[f] = unicode(attrs[f])
                        else:
                            attrs[f] = str(attrs[f])
                writer.add_document(**attrs)

            @classmethod
            def delete_model(cls, writer, model):
                writer.delete_by_term(primary, getattr(model, primary))

            setattr(mwh, 'update_{0}'.format(model.__name__.lower()), update_model)
            setattr(mwh, 'insert_{0}'.format(model.__name__.lower()), insert_model)
            setattr(mwh, 'delete_{0}'.format(model.__name__.lower()), delete_model)
            model._whoosheer_ = mwh
            model.whoosh_search = mwh.search
            self.register_whoosheer(mwh)
            return model

        return inner

    def create_index(self, wh):
        """Creates and opens index for given whoosheer.

        If the index already exists, it just opens it, otherwise it creates it first.
        """
        index_path = os.path.join(self.index_path_root, wh.index_subdir)
        if whoosh.index.exists_in(index_path):
            index = whoosh.index.open_dir(index_path)
        else:
            if not os.path.exists(index_path):
                os.makedirs(index_path)
            index = whoosh.index.create_in(index_path, wh.schema)
        wh.index = index
    def after_insert(self, mapper, connection, target):
        self.on_commit([[target, 'insert']])
    def after_delete(self, mapper, connection, target):
        self.on_commit([[target, 'insert']])
    def after_update(self, mapper, connection, target):
        self.on_commit([[target, 'insert']])

    def on_commit(self, changes):
        """Method that gets called when a model is changed. This serves
        to do the actual index writing.
        """
        for wh in self.__class__.whoosheers:
            writer = None
            for change in changes:
                if change[0].__class__ in wh.models:
                    method_name = '{0}_{1}'.format(change[1], change[0].__class__.__name__.lower())
                    method = getattr(wh, method_name, None)
                    if method:
                        if not writer:
                            writer = wh.index.writer(timeout=self.writer_timeout)
                        method(writer, change[0])
            if writer:
                writer.commit()

    def camel_to_snake(self, s):
        """Constructs nice dir name from class name, e.g. FooBar => foo_bar."""
        return self._underscore_re2.sub(r'\1_\2', self._underscore_re1.sub(r'\1_\2', s)).lower()

    def reindex(self):
        """ Reindex all data

        This method retrieve all data from registered models and call
        update_<model>() function for every instance of such model.
        """
        for wh in self.__class__.whoosheers:
            writer = wh.index.writer(timeout=self.writer_timeout)
            for model in wh.models:
                method_name = "update_{0}".format(model.__name__.lower())
                for item in model.query.all():
                    getattr(wh, method_name)(writer, item)
            writer.commit()

class WhoosheeDeprecationWarning(DeprecationWarning):
    pass

warnings.simplefilter('always', WhoosheeDeprecationWarning)
<|endoftext|>


<commit_before>"""
St. George Game
main.py
Sage Berg
Created: 5 Dec 2014
"""

from st_george_game import Character, Frame, ActionBag
from places import TavernStart

def main():
    character = Character()
    msg = "You are in a tavern. The local assassins hate you."
    opening_frame = Frame(msg, TavernStart, None, None)
    opening_frame.prompt()
    while character.alive and character.alone:
        curr_frame = Frame(place, person, prev_act)
        location, person, prev_act = curr_frame.prompt()

if __name__ == "__main__":
    while True:  # the game automatically restarts
        main()
<commit_msg>changed strategy for initializing first frame<commit_after>"""
St. George Game
main.py
Sage Berg
Created: 5 Dec 2014
"""

from st_george_game import Character, Frame, ActionBag
from places import TavernStart

def main():
    character = Character()
    msg = "You are in a tavern. The local assassins hate you."
    opening_frame = Frame(msg, Tavern, None, None)
    opening_frame.a_action = AskAboutAssassins
    opening_frame.b_action = BuyADrink
    opening_frame.c_action = LeaveInAHuff
    opening_frame.d_action = SingASong
    opening_frame.prompt()
    while character.alive and character.alone:
        curr_frame = Frame(place, person, prev_act)
        location, person, prev_act = curr_frame.prompt()

if __name__ == "__main__":
    while True:  # the game automatically restarts
        main()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from couchdb.design import ViewDefinition
from couchdb.http import HTTPError
from time import sleep
from random import randint

endDate_view = ViewDefinition(
    "auctions",
    "by_endDate",
    ''' function(doc) {
            var end = new Date(doc.endDate||doc.stages[0].start).getTime()
            emit(end, null);
        }
    '''
)

startDate_view = ViewDefinition(
    "auctions",
    "by_startDate",
    ''' function(doc) {
            var start = new Date(doc.stages[0].start).getTime()
            emit(start, null);
        }
    '''
)

def sync_design(db):
    views = [endDate_view, startDate_view]
    for view in views:
        view.sync(db)
    while True:
        design = db.get('_design/auctions')
        if not design:
            design = {'_id': '_design/auctions'}
        validate_doc_update = """
        function(newDoc, oldDoc, userCtx, secObj) {
            if (userCtx.roles.indexOf('_admin') !== -1) {
                return true;
            } else {
                throw({forbidden: 'Only valid user may change docs.'});
            }
        }
        """
        start_date_filter = """function(doc, req) {
            var now = new Date();
            var start = new Date(((doc.stages||[])[0]||{}).start || "2000");
            if (start > now){
                return true;
            }
            return false;
        }
        """
        if 'validate_doc_update' not in design or \
                validate_doc_update != design['validate_doc_update'] or \
                start_date_filter != design.get("filters", {}).get("by_startDate"):
            design['validate_doc_update'] = validate_doc_update
            design['filters'] = design.get("filters", {})
            design['filters']['by_startDate'] = start_date_filter
            try:
                return db.save(design)
            except HTTPError, e:
                sleep(randint(0, 2000) / 1000.0)
        else:
            return
<commit_msg>Added PreAnnounce_view<commit_after># -*- coding: utf-8 -*-
from couchdb.design import ViewDefinition
from couchdb.http import HTTPError
from time import sleep
from random import randint

endDate_view = ViewDefinition(
    "auctions",
    "by_endDate",
    ''' function(doc) {
            var end = new Date(doc.endDate||doc.stages[0].start).getTime()
            emit(end, null);
        }
    '''
)

startDate_view = ViewDefinition(
    "auctions",
    "by_startDate",
    ''' function(doc) {
            var start = new Date(doc.stages[0].start).getTime()
            emit(start, null);
        }
    '''
)

PreAnnounce_view = ViewDefinition(
    "auctions",
    "PreAnnounce",
    ''' function(doc) {
            if ((doc.stages.length - 2) == doc.current_stage){
                emit(start, null);
            }
        }
    '''
)

def sync_design(db):
    views = [endDate_view, startDate_view, PreAnnounce_view]
    for view in views:
        view.sync(db)
    while True:
        design = db.get('_design/auctions')
        if not design:
            design = {'_id': '_design/auctions'}
        validate_doc_update = """
        function(newDoc, oldDoc, userCtx, secObj) {
            if (userCtx.roles.indexOf('_admin') !== -1) {
                return true;
            } else {
                throw({forbidden: 'Only valid user may change docs.'});
            }
        }
        """
        start_date_filter = """function(doc, req) {
            var now = new Date();
            var start = new Date(((doc.stages||[])[0]||{}).start || "2000");
            if (start > now){
                return true;
            }
            return false;
        }
        """
        if 'validate_doc_update' not in design or \
                validate_doc_update != design['validate_doc_update'] or \
                start_date_filter != design.get("filters", {}).get("by_startDate"):
            design['validate_doc_update'] = validate_doc_update
            design['filters'] = design.get("filters", {})
            design['filters']['by_startDate'] = start_date_filter
            try:
                return db.save(design)
            except HTTPError, e:
                sleep(randint(0, 2000) / 1000.0)
        else:
            return
<|endoftext|>