<commit_before>"""
 SlipStream Client
 =====
 Copyright (C) 2015 SixSq Sarl (sixsq.com)
 =====
 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 datetime

from libcloud.compute.drivers.cloudstack import CloudStackNodeDriver, CloudStackAddress, \
    CloudStackIPForwardingRule, CloudStackPortForwardingRule
from libcloud.compute.types import LibcloudError
from libcloud.compute.base import NodeImage

def ex_authorize_security_group_ingress(self, securitygroupname, protocol,
                                        cidrlist, startport=None, endport=None,
                                        icmptype=None, icmpcode=None, **kwargs):
    """
    Creates a new Security Group Ingress rule

    :param   securitygroupname: The name of the security group.
                                Mutually exclusive with securitygroupid.
    :type    securitygroupname: ``str``

    :param   protocol: Can be TCP, UDP or ICMP.
                       Sometime other protocols can be used like AH, ESP, GRE.
    :type    protocol: ``str``

    :param   cidrlist: Source address CIDR for which this rule applies.
    :type    cidrlist: ``str``

    :param   startport: Start port of the range for this ingress rule.
                        Applies to protocols TCP and UDP.
    :type    startport: ``int``

    :param   endport: End port of the range for this ingress rule.
                      It can be None to set only one port.
                      Applies to protocols TCP and UDP.
    :type    endport: ``int``

    :param   icmptype: Type of the ICMP packet (eg: 8 for Echo Request).
                       -1 or None means "all types".
                       Applies to protocol ICMP.
    :type    icmptype: ``int``

    :param   icmpcode: Code of the ICMP packet for the specified type.
                       If the specified type doesn't require a code set this
                       value to 0.
                       -1 or None means "all codes".
                       Applies to protocol ICMP.
    :type    icmpcode: ``int``

    :keyword   account: An optional account for the security group.
                        Must be used with domainId.
    :type      account: ``str``

    :keyword domainid: An optional domainId for the security group.
                       If the account parameter is used, domainId must also
                       be used.

    :keyword projectid: An optional project of the security group
    :type    projectid: ``str``

    :param securitygroupid: The ID of the security group.
                            Mutually exclusive with securitygroupname
    :type  securitygroupid: ``str``

    :param usersecuritygrouplist: User to security group mapping
    :type  usersecuritygrouplist: ``dict``

    :rtype: ``dict``
    """

    args = kwargs.copy()
    protocol = protocol.upper()

    args.update({
        'securitygroupname': securitygroupname,
        'protocol': protocol,
        'cidrlist': cidrlist
    })

    if protocol not in ('TCP', 'UDP') and \
            (startport is not None or endport is not None):
        raise LibcloudError('"startport" and "endport" are only valid with '
                            'protocol TCP or UDP.')

    if protocol != 'ICMP' and (icmptype is not None or icmpcode is not None):
        raise LibcloudError('"icmptype" and "icmpcode" are only valid with '
                            'protocol ICMP.')

    if protocol in ('TCP', 'UDP'):
        if startport is None:
            raise LibcloudError('Protocols TCP and UDP require at least '
                                '"startport" to be set.')
        if startport is not None and endport is None:
            endport = startport

        args.update({
            'startport': startport,
            'endport': endport
        })

    if protocol == 'ICMP':
        if icmptype is None:
            icmptype = -1
        if icmpcode is None:
            icmpcode = -1

        args.update({
            'icmptype': icmptype,
            'icmpcode': icmpcode
        })

    return self._async_request(command='authorizeSecurityGroupIngress',
                               params=args,
                               method='GET')['securitygroup']

def list_nodes(self, project=None, location=None):
    """
    @inherits: :class:`NodeDriver.list_nodes`
    :keyword    project: Limit nodes returned to those configured under
                         the defined project.
    :type       project: :class:`.CloudStackProject`
    :keyword    location: Limit nodes returned to those in the defined
                          location.
    :type       location: :class:`.NodeLocation`
    :rtype: ``list`` of :class:`CloudStackNode`
    """

    args = {}

    if project:
        args['projectid'] = project.id

    if location is not None:
        args['zoneid'] = location.id

    vms = self._sync_request('listVirtualMachines', params=args)
    addrs = self._sync_request('listPublicIpAddresses', params=args)
    port_forwarding_rules = self._sync_request('listPortForwardingRules')
    ip_forwarding_rules = self._sync_request('listIpForwardingRules')

    public_ips_map = {}
    for addr in addrs.get('publicipaddress', []):
        if 'virtualmachineid' not in addr:
            continue
        vm_id = str(addr['virtualmachineid'])
        if vm_id not in public_ips_map:
            public_ips_map[vm_id] = {}
        public_ips_map[vm_id][addr['ipaddress']] = addr['id']

    nodes = []

    for vm in vms.get('virtualmachine', []):
        public_ips = public_ips_map.get(str(vm['id']), {}).keys()
        public_ips = list(public_ips)
        node = self._to_node(data=vm, public_ips=public_ips)

        addresses = public_ips_map.get(str(vm['id']), {}).items()
        addresses = [CloudStackAddress(id=address_id, address=address,
                                       driver=node.driver) for
                     address, address_id in addresses]
        node.extra['ip_addresses'] = addresses

        rules = []
        for addr in addresses:
            for r in ip_forwarding_rules.get('ipforwardingrule', []):
                if str(r['virtualmachineid']) == node.id:
                    rule = CloudStackIPForwardingRule(node, r['id'],
                                                      addr,
                                                      r['protocol']
                                                      .upper(),
                                                      r['startport'],
                                                      r['endport'])
                    rules.append(rule)
        node.extra['ip_forwarding_rules'] = rules

        rules = []
        for r in port_forwarding_rules.get('portforwardingrule', []):
            if str(r['virtualmachineid']) == node.id:
                addr = [CloudStackAddress(id=a['id'],
                                          address=a['ipaddress'],
                                          driver=node.driver)
                        for a in addrs.get('publicipaddress', [])
                        if a['ipaddress'] == r['ipaddress']]
                rule = CloudStackPortForwardingRule(node, r['id'],
                                                    addr[0],
                                                    r['protocol'].upper(),
                                                    r['publicport'],
                                                    r['privateport'],
                                                    r['publicendport'],
                                                    r['privateendport'])
                if not addr[0].address in node.public_ips:
                    node.public_ips.append(addr[0].address)
                rules.append(rule)
        node.extra['port_forwarding_rules'] = rules

        nodes.append(node)

    return nodes

def list_images(self, location=None):
    args = {
        'templatefilter': 'executable'
    }
    if location is not None:
        args['zoneid'] = location.id

    imgs = self._sync_request(command='listTemplates',
                              params=args,
                              method='GET')
    images = []
    for img in imgs.get('template', []):

        extra = {'hypervisor': img['hypervisor'],
                 'format': img['format'],
                 'os': img['ostypename'],
                 'displaytext': img['displaytext'],
                 'location': img.get('zonename'),
                 'ready': img.get('isready', True),
                 'featured': img.get('isfeatured', False)}

        size = img.get('size', None)
        if size is not None:
            extra.update({'size': img['size']})

        if 'created' in img:
            try:
                created = datetime.datetime.strptime(img['created'][:19], '%Y-%m-%dT%H:%M:%S')
                extra.update({'created': created})
            except:
                pass

        images.append(NodeImage(
            id=img['id'],
            name=img['name'],
            driver=self.connection.driver,
            extra=extra))
    return images

def patch_libcloud():
    CloudStackNodeDriver.ex_authorize_security_group_ingress = ex_authorize_security_group_ingress
    CloudStackNodeDriver.list_nodes = list_nodes
    CloudStackNodeDriver.list_images = list_images

<commit_msg>cloudstack: patched libcloud to be able to list instances even when ipaddress field is not present.<commit_after>"""
 SlipStream Client
 =====
 Copyright (C) 2015 SixSq Sarl (sixsq.com)
 =====
 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 datetime

from libcloud.compute.drivers.cloudstack import (CloudStackNodeDriver,
                                                 CloudStackAddress,
                                                 CloudStackIPForwardingRule,
                                                 CloudStackPortForwardingRule,
                                                 CloudStackNode,
                                                 RESOURCE_EXTRA_ATTRIBUTES_MAP)
from libcloud.utils.networking import is_private_subnet
from libcloud.compute.types import LibcloudError
from libcloud.compute.base import NodeImage

def ex_authorize_security_group_ingress(self, securitygroupname, protocol,
                                        cidrlist, startport=None, endport=None,
                                        icmptype=None, icmpcode=None, **kwargs):
    """
    Creates a new Security Group Ingress rule

    :param   securitygroupname: The name of the security group.
                                Mutually exclusive with securitygroupid.
    :type    securitygroupname: ``str``

    :param   protocol: Can be TCP, UDP or ICMP.
                       Sometime other protocols can be used like AH, ESP, GRE.
    :type    protocol: ``str``

    :param   cidrlist: Source address CIDR for which this rule applies.
    :type    cidrlist: ``str``

    :param   startport: Start port of the range for this ingress rule.
                        Applies to protocols TCP and UDP.
    :type    startport: ``int``

    :param   endport: End port of the range for this ingress rule.
                      It can be None to set only one port.
                      Applies to protocols TCP and UDP.
    :type    endport: ``int``

    :param   icmptype: Type of the ICMP packet (eg: 8 for Echo Request).
                       -1 or None means "all types".
                       Applies to protocol ICMP.
    :type    icmptype: ``int``

    :param   icmpcode: Code of the ICMP packet for the specified type.
                       If the specified type doesn't require a code set this
                       value to 0.
                       -1 or None means "all codes".
                       Applies to protocol ICMP.
    :type    icmpcode: ``int``

    :keyword   account: An optional account for the security group.
                        Must be used with domainId.
    :type      account: ``str``

    :keyword domainid: An optional domainId for the security group.
                       If the account parameter is used, domainId must also
                       be used.

    :keyword projectid: An optional project of the security group
    :type    projectid: ``str``

    :param securitygroupid: The ID of the security group.
                            Mutually exclusive with securitygroupname
    :type  securitygroupid: ``str``

    :param usersecuritygrouplist: User to security group mapping
    :type  usersecuritygrouplist: ``dict``

    :rtype: ``dict``
    """

    args = kwargs.copy()
    protocol = protocol.upper()

    args.update({
        'securitygroupname': securitygroupname,
        'protocol': protocol,
        'cidrlist': cidrlist
    })

    if protocol not in ('TCP', 'UDP') and \
            (startport is not None or endport is not None):
        raise LibcloudError('"startport" and "endport" are only valid with '
                            'protocol TCP or UDP.')

    if protocol != 'ICMP' and (icmptype is not None or icmpcode is not None):
        raise LibcloudError('"icmptype" and "icmpcode" are only valid with '
                            'protocol ICMP.')

    if protocol in ('TCP', 'UDP'):
        if startport is None:
            raise LibcloudError('Protocols TCP and UDP require at least '
                                '"startport" to be set.')
        if startport is not None and endport is None:
            endport = startport

        args.update({
            'startport': startport,
            'endport': endport
        })

    if protocol == 'ICMP':
        if icmptype is None:
            icmptype = -1
        if icmpcode is None:
            icmpcode = -1

        args.update({
            'icmptype': icmptype,
            'icmpcode': icmpcode
        })

    return self._async_request(command='authorizeSecurityGroupIngress',
                               params=args,
                               method='GET')['securitygroup']

def list_nodes(self, project=None, location=None):
    """
    @inherits: :class:`NodeDriver.list_nodes`
    :keyword    project: Limit nodes returned to those configured under
                         the defined project.
    :type       project: :class:`.CloudStackProject`
    :keyword    location: Limit nodes returned to those in the defined
                          location.
    :type       location: :class:`.NodeLocation`
    :rtype: ``list`` of :class:`CloudStackNode`
    """

    args = {}

    if project:
        args['projectid'] = project.id

    if location is not None:
        args['zoneid'] = location.id

    vms = self._sync_request('listVirtualMachines', params=args)
    addrs = self._sync_request('listPublicIpAddresses', params=args)
    port_forwarding_rules = self._sync_request('listPortForwardingRules')
    ip_forwarding_rules = self._sync_request('listIpForwardingRules')

    public_ips_map = {}
    for addr in addrs.get('publicipaddress', []):
        if 'virtualmachineid' not in addr:
            continue
        vm_id = str(addr['virtualmachineid'])
        if vm_id not in public_ips_map:
            public_ips_map[vm_id] = {}
        public_ips_map[vm_id][addr['ipaddress']] = addr['id']

    nodes = []

    for vm in vms.get('virtualmachine', []):
        public_ips = public_ips_map.get(str(vm['id']), {}).keys()
        public_ips = list(public_ips)
        node = self._to_node(data=vm, public_ips=public_ips)

        addresses = public_ips_map.get(str(vm['id']), {}).items()
        addresses = [CloudStackAddress(id=address_id, address=address,
                                       driver=node.driver) for
                     address, address_id in addresses]
        node.extra['ip_addresses'] = addresses

        rules = []
        for addr in addresses:
            for r in ip_forwarding_rules.get('ipforwardingrule', []):
                if str(r['virtualmachineid']) == node.id:
                    rule = CloudStackIPForwardingRule(node, r['id'],
                                                      addr,
                                                      r['protocol']
                                                      .upper(),
                                                      r['startport'],
                                                      r['endport'])
                    rules.append(rule)
        node.extra['ip_forwarding_rules'] = rules

        rules = []
        for r in port_forwarding_rules.get('portforwardingrule', []):
            if str(r['virtualmachineid']) == node.id:
                addr = [CloudStackAddress(id=a['id'],
                                          address=a['ipaddress'],
                                          driver=node.driver)
                        for a in addrs.get('publicipaddress', [])
                        if a['ipaddress'] == r['ipaddress']]
                rule = CloudStackPortForwardingRule(node, r['id'],
                                                    addr[0],
                                                    r['protocol'].upper(),
                                                    r['publicport'],
                                                    r['privateport'],
                                                    r['publicendport'],
                                                    r['privateendport'])
                if not addr[0].address in node.public_ips:
                    node.public_ips.append(addr[0].address)
                rules.append(rule)
        node.extra['port_forwarding_rules'] = rules

        nodes.append(node)

    return nodes

def list_images(self, location=None):
    args = {
        'templatefilter': 'executable'
    }
    if location is not None:
        args['zoneid'] = location.id

    imgs = self._sync_request(command='listTemplates',
                              params=args,
                              method='GET')
    images = []
    for img in imgs.get('template', []):

        extra = {'hypervisor': img['hypervisor'],
                 'format': img['format'],
                 'os': img['ostypename'],
                 'displaytext': img['displaytext'],
                 'location': img.get('zonename'),
                 'ready': img.get('isready', True),
                 'featured': img.get('isfeatured', False)}

        size = img.get('size', None)
        if size is not None:
            extra.update({'size': img['size']})

        if 'created' in img:
            try:
                created = datetime.datetime.strptime(img['created'][:19], '%Y-%m-%dT%H:%M:%S')
                extra.update({'created': created})
            except:
                pass

        images.append(NodeImage(
            id=img['id'],
            name=img['name'],
            driver=self.connection.driver,
            extra=extra))
    return images

def _to_node(self, data, public_ips=None):
    """
    :param data: Node data object.
    :type data: ``dict``

    :param public_ips: A list of additional IP addresses belonging to
                       this node. (optional)
    :type public_ips: ``list`` or ``None``
    """
    id = data['id']

    if 'name' in data:
        name = data['name']
    elif 'displayname' in data:
        name = data['displayname']
    else:
        name = None

    state = self.NODE_STATE_MAP[data['state']]

    public_ips = public_ips if public_ips else []
    private_ips = []

    for nic in data['nic']:
        if 'ipaddress' in nic:
            if is_private_subnet(nic['ipaddress']):
                private_ips.append(nic['ipaddress'])
            else:
                public_ips.append(nic['ipaddress'])

    security_groups = data.get('securitygroup', [])

    if security_groups:
        security_groups = [sg['name'] for sg in security_groups]

    affinity_groups = data.get('affinitygroup', [])

    if affinity_groups:
        affinity_groups = [ag['id'] for ag in affinity_groups]

    created = data.get('created', False)

    extra = self._get_extra_dict(data,
                                 RESOURCE_EXTRA_ATTRIBUTES_MAP['node'])

    # Add additional parameters to extra
    extra['security_group'] = security_groups
    extra['affinity_group'] = affinity_groups
    extra['ip_addresses'] = []
    extra['ip_forwarding_rules'] = []
    extra['port_forwarding_rules'] = []
    extra['created'] = created

    if 'tags' in data:
        extra['tags'] = self._get_resource_tags(data['tags'])

    node = CloudStackNode(id=id, name=name, state=state,
                          public_ips=public_ips, private_ips=private_ips,
                          driver=self, extra=extra)
    return node

def patch_libcloud():
    CloudStackNodeDriver.ex_authorize_security_group_ingress = ex_authorize_security_group_ingress
    CloudStackNodeDriver.list_nodes = list_nodes
    CloudStackNodeDriver.list_images = list_images
    CloudStackNodeDriver._to_node = _to_node

<|endoftext|>


<commit_before>"""
Thin and ugly couchdb access layer.
"""

import couchdb
import time
import random

_db = None
_cache = []
_timestamp = 0
_timestamp_count = 0

# This is the design document we're trying to enforce on the connected
# database. It is checked at every startups.
design = {
    "_id": "_design/usage",
    "language": "javascript",
    "views": {
        "reusable": {
            "map": """
                function(doc) {
                    if (doc.expires >= (new Date()).getTime()) {
                        emit([doc.expires, doc.id], null)
                    } else if (doc.new) {
                        emit([0, doc.id], null)
                    }
                }"""
        },
        "highest_id": {
            "map": """function(doc) { emit("highest_id", parseInt(doc._id)) }""",
            "reduce": """
                function(keys, values) {
                    var max = 0;
                    for (var i = 0; i < values.length; i++) {
                        if (values[i] > max) {
                        max = values[i];
                        }
                    }
                    return max;
                }"""
        },
        "allocated": {
            "map": """function(doc) { emit("allocated", 1); }""",
            "reduce": """_sum"""
        }
    }
}

class TooManySaves(Exception):
    """Raised when we feel flooded."""
    pass

def generate_blanks(amount=5):
    """Generate documents when we're running out of expired posts."""
    print("Generating %d blank documents:" % amount)

    res = _db.view("usage/highest_id", reduce=True)
    if len(res) == 0:
        base_id = 0
    else:
        base_id = res.rows[0].value + 1

    print(" - Starting at %d" % base_id)

    for i in range(base_id, base_id+amount):
        doc = { "_id": str(i), "new": True }
        try:
            _db.save(doc)
        except couchdb.ResourceConflict:
            pass

def get_available_doc():
    """Get the first available paste, be it an expired one or a fresh
    new paste. If we can't find one, let's generate a few.
    """
    res = _db.view("usage/reusable", limit=5, include_docs=True)

    # Need some more!
    if len(res) == 0:
        generate_blanks()
        return get_available_doc()

    return random.choice([row.doc for row in res.rows])

def save_paste(source_id, data, expiration):
    """Let's save this stuff somewhere, find an available doc and update it."""
    global _timestamp, _timestamp_count

    # Clumsy flood management
    now = int(time.time())
    if _timestamp != now:
        _timestamp = now
        _timestamp_count = 1
    else:
        _timestamp_count += 1

    if _timestamp_count > 10:
        raise TooManySaves()

    doc = get_available_doc()
    new_doc = doc.copy()
    new_doc["raw"] = data
    new_doc["source"] = source_id
    new_doc["new"] = False
    # Keep it two weeks by default
    new_doc["expires"] = int(time.time() + expiration)
    try:
        _db.save(new_doc)
    except ResourceConflict:
        return save_paste(id, data, expiration)
    id = int(doc.id)
    _cache.append(new_doc)
    while len(_cache) > 50:
        _cache.pop(0)
    return id

def get_paste(id):
    for doc in _cache:
        if int(doc["_id"]) == id:
            print("Fetching %d from cache..." % id)
            return doc
    return _db.get(str(id))

def allocated_slots():
    """How many slots are allocated in the database at the moment."""
    res = _db.view("usage/allocated", reduce=True)
    return res.rows[0].value

def cache_len():
    """Return the current size of the cache."""
    return len(_cache)

def last_paste_id():
    """Return the identifier of the latest paste created if any."""
    if _cache:
        return int(_cache[-1]["_id"])
    else:
        return 0

def init():
    """Reference the database and enforce the design document."""
    global _db

    if _db: return

    server = couchdb.Server()
    if "vimpaste" not in server:
        print("Creating initial database.")
        _db = server.create("vimpaste")
    else:
        _db = server["vimpaste"]

    # Make sure the design docs are in place.
    current_design = _db.get("_design/usage")
    if not current_design:
        print("Creating initial design document.")
        _db.save(design)
    elif current_design["views"] != design["views"]:
        print("Updating design document...")
        new_design = current_design.copy()
        new_design["views"] = design["views"]
        _db.save(new_design)

<commit_msg>db in heroku via cloudant<commit_after>"""
Thin and ugly couchdb access layer.
"""

import os
import couchdb
import time
import random

_db = None
_cache = []
_timestamp = 0
_timestamp_count = 0

# This is the design document we're trying to enforce on the connected
# database. It is checked at every startups.
design = {
    "_id": "_design/usage",
    "language": "javascript",
    "views": {
        "reusable": {
            "map": """
                function(doc) {
                    if (doc.expires >= (new Date()).getTime()) {
                        emit([doc.expires, doc.id], null)
                    } else if (doc.new) {
                        emit([0, doc.id], null)
                    }
                }"""
        },
        "highest_id": {
            "map": """function(doc) { emit("highest_id", parseInt(doc._id)) }""",
            "reduce": """
                function(keys, values) {
                    var max = 0;
                    for (var i = 0; i < values.length; i++) {
                        if (values[i] > max) {
                        max = values[i];
                        }
                    }
                    return max;
                }"""
        },
        "allocated": {
            "map": """function(doc) { emit("allocated", 1); }""",
            "reduce": """_sum"""
        }
    }
}

class TooManySaves(Exception):
    """Raised when we feel flooded."""
    pass

def generate_blanks(amount=5):
    """Generate documents when we're running out of expired posts."""
    print("Generating %d blank documents:" % amount)

    res = _db.view("usage/highest_id", reduce=True)
    if len(res) == 0:
        base_id = 0
    else:
        base_id = res.rows[0].value + 1

    print(" - Starting at %d" % base_id)

    for i in range(base_id, base_id+amount):
        doc = { "_id": str(i), "new": True }
        try:
            _db.save(doc)
        except couchdb.ResourceConflict:
            pass

def get_available_doc():
    """Get the first available paste, be it an expired one or a fresh
    new paste. If we can't find one, let's generate a few.
    """
    res = _db.view("usage/reusable", limit=5, include_docs=True)

    # Need some more!
    if len(res) == 0:
        generate_blanks()
        return get_available_doc()

    return random.choice([row.doc for row in res.rows])

def save_paste(source_id, data, expiration):
    """Let's save this stuff somewhere, find an available doc and update it."""
    global _timestamp, _timestamp_count

    # Clumsy flood management
    now = int(time.time())
    if _timestamp != now:
        _timestamp = now
        _timestamp_count = 1
    else:
        _timestamp_count += 1

    if _timestamp_count > 10:
        raise TooManySaves()

    doc = get_available_doc()
    new_doc = doc.copy()
    new_doc["raw"] = data
    new_doc["source"] = source_id
    new_doc["new"] = False
    # Keep it two weeks by default
    new_doc["expires"] = int(time.time() + expiration)
    try:
        _db.save(new_doc)
    except ResourceConflict:
        return save_paste(id, data, expiration)
    id = int(doc.id)
    _cache.append(new_doc)
    while len(_cache) > 50:
        _cache.pop(0)
    return id

def get_paste(id):
    for doc in _cache:
        if int(doc["_id"]) == id:
            print("Fetching %d from cache..." % id)
            return doc
    return _db.get(str(id))

def allocated_slots():
    """How many slots are allocated in the database at the moment."""
    res = _db.view("usage/allocated", reduce=True)
    return res.rows[0].value

def cache_len():
    """Return the current size of the cache."""
    return len(_cache)

def last_paste_id():
    """Return the identifier of the latest paste created if any."""
    if _cache:
        return int(_cache[-1]["_id"])
    else:
        return 0

def init():
    """Reference the database and enforce the design document."""
    global _db

    if _db: return

    # That's in case we are hosted in Heroku...
    couch_url = os.environ.get("CLOUDANT_URL")
    if couch_url:
        args = {"url": couch_url}
    else:
        args = {}

    server = couchdb.Server(*args)
    if "vimpaste" not in server:
        print("Creating initial database.")
        _db = server.create("vimpaste")
    else:
        _db = server["vimpaste"]

    # Make sure the design docs are in place.
    current_design = _db.get("_design/usage")
    if not current_design:
        print("Creating initial design document.")
        _db.save(design)
    elif current_design["views"] != design["views"]:
        print("Updating design document...")
        new_design = current_design.copy()
        new_design["views"] = design["views"]
        _db.save(new_design)

<|endoftext|>


<commit_before>#
#  Copyright 2.02-2017 Barcelona Supercomputing Center (www.bsc.es)
#
#  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.
#
"""
@author: fconejer

PyCOMPSs API - Implement (Versioning)
=====================================
    This file contains the class constraint, needed for the implement
    definition through the decorator.
"""
import inspect
import logging
import os
from functools import wraps
from pycompss.runtime.binding import register_ce
from pycompss.util.location import i_am_at_master

logger = logging.getLogger(__name__)

class implement(object):
    """
    This decorator also preserves the argspec, but includes the __init__ and
    __call__ methods, useful on mpi task creation.
    """
    def __init__(self, *args, **kwargs):
        # store arguments passed to the decorator
        self.args = args
        self.kwargs = kwargs
        logger.debug("Init @implement decorator...")
        # self = itself.
        # args = not used.
        # kwargs = dictionary with the given constraints.

    def __call__(self, func):

        if i_am_at_master():
            # master code
            mod = inspect.getmodule(func)
            self.module = mod.__name__    # not func.__module__

            if(self.module == '__main__' or
               self.module == 'pycompss.runtime.launch'):
                # The module where the function is defined was run as __main__,
                # we need to find out the real module name.

                # path=mod.__file__
                # dirs=mod.__file__.split(os.sep)
                # file_name=os.path.splitext(os.path.basename(mod.__file__))[0]

                # Get the real module name from our launch.py variable
                path = getattr(mod, "app_path")

                dirs = path.split(os.path.sep)
                file_name = os.path.splitext(os.path.basename(path))[0]
                mod_name = file_name

                i = len(dirs) - 1
                while i > 0:
                    new_l = len(path) - (len(dirs[i]) + 1)
                    path = path[0:new_l]
                    if "__init__.py" in os.listdir(path):
                        # directory is a package
                        i -= 1
                        mod_name = dirs[i] + '.' + mod_name
                    else:
                        break
                self.module = mod_name

            # Include the registering info related to @MPI

            # Retrieve the base coreElement established at @task decorator
            coreElement = func.__to_register__
            # Update the core element information with the mpi information
            anotherClass = self.kwargs['class']
            anotherMethod = self.kwargs['method']
            implSignature = anotherClass + '.' + anotherMethod
            coreElement.set_implSignature(implSignature)
            implArgs = [anotherClass, anotherMethod]
            coreElement.set_implTypeArgs(implArgs)
            coreElement.set_implType("METHOD")
            func.__to_register__ = coreElement
            # Do the task register if I am the top decorator
            if func.__who_registers__ == __name__:
                logger.debug("[@IMPLEMENT] I have to do the register of function %s in module %s" % (func.__name__, self.module))
                register_ce(coreElement)
        else:
            # worker code
            pass

        @wraps(func)
        def implement_f(*args, **kwargs):
            # This is executed only when called.
            logger.debug("Executing implement_f wrapper.")

            # The 'self' for a method function is passed as args[0]
            slf = args[0]

            # Replace and store the attributes
            saved = {}
            for k, v in self.kwargs.items():
                if hasattr(slf, k):
                    saved[k] = getattr(slf, k)
                    setattr(slf, k, v)

            # Call the method
            ret = func(*args, **kwargs)

            # Put things back
            for k, v in saved.items():
                setattr(slf, k, v)

            return ret
        implement_f.__doc__ = func.__doc__
        return implement_f
<commit_msg>[PyCOMPSs] Renamed class field of the implement decorator. class is not a valid keyword.<commit_after>#
#  Copyright 2.02-2017 Barcelona Supercomputing Center (www.bsc.es)
#
#  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.
#
"""
@author: fconejer

PyCOMPSs API - Implement (Versioning)
=====================================
    This file contains the class constraint, needed for the implement
    definition through the decorator.
"""
import inspect
import logging
import os
from functools import wraps
from pycompss.runtime.binding import register_ce
from pycompss.util.location import i_am_at_master

logger = logging.getLogger(__name__)

class implement(object):
    """
    This decorator also preserves the argspec, but includes the __init__ and
    __call__ methods, useful on mpi task creation.
    """
    def __init__(self, *args, **kwargs):
        # store arguments passed to the decorator
        self.args = args
        self.kwargs = kwargs
        logger.debug("Init @implement decorator...")
        # self = itself.
        # args = not used.
        # kwargs = dictionary with the given constraints.

    def __call__(self, func):

        if i_am_at_master():
            # master code
            mod = inspect.getmodule(func)
            self.module = mod.__name__    # not func.__module__

            if(self.module == '__main__' or
               self.module == 'pycompss.runtime.launch'):
                # The module where the function is defined was run as __main__,
                # we need to find out the real module name.

                # path=mod.__file__
                # dirs=mod.__file__.split(os.sep)
                # file_name=os.path.splitext(os.path.basename(mod.__file__))[0]

                # Get the real module name from our launch.py variable
                path = getattr(mod, "app_path")

                dirs = path.split(os.path.sep)
                file_name = os.path.splitext(os.path.basename(path))[0]
                mod_name = file_name

                i = len(dirs) - 1
                while i > 0:
                    new_l = len(path) - (len(dirs[i]) + 1)
                    path = path[0:new_l]
                    if "__init__.py" in os.listdir(path):
                        # directory is a package
                        i -= 1
                        mod_name = dirs[i] + '.' + mod_name
                    else:
                        break
                self.module = mod_name

            # Include the registering info related to @MPI

            # Retrieve the base coreElement established at @task decorator
            coreElement = func.__to_register__
            # Update the core element information with the mpi information
            anotherClass = self.kwargs['source_class']
            anotherMethod = self.kwargs['method']
            implSignature = anotherClass + '.' + anotherMethod
            coreElement.set_implSignature(implSignature)
            implArgs = [anotherClass, anotherMethod]
            coreElement.set_implTypeArgs(implArgs)
            coreElement.set_implType("METHOD")
            func.__to_register__ = coreElement
            # Do the task register if I am the top decorator
            if func.__who_registers__ == __name__:
                logger.debug("[@IMPLEMENT] I have to do the register of function %s in module %s" % (func.__name__, self.module))
                register_ce(coreElement)
        else:
            # worker code
            pass

        @wraps(func)
        def implement_f(*args, **kwargs):
            # This is executed only when called.
            logger.debug("Executing implement_f wrapper.")

            # The 'self' for a method function is passed as args[0]
            slf = args[0]

            # Replace and store the attributes
            saved = {}
            for k, v in self.kwargs.items():
                if hasattr(slf, k):
                    saved[k] = getattr(slf, k)
                    setattr(slf, k, v)

            # Call the method
            ret = func(*args, **kwargs)

            # Put things back
            for k, v in saved.items():
                setattr(slf, k, v)

            return ret
        implement_f.__doc__ = func.__doc__
        return implement_f
<|endoftext|>


<commit_before>#!/usr/bin/python
#
#  Copyright 2002-2018 Barcelona Supercomputing Center (www.bsc.es)
#
#  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.
#

# -*- coding: utf-8 -*-

"""
PyCOMPSs Utils - Location
===================
    This file contains the methods to detect the origin of the call stack.
    Useful to detect if we are in the master or in the worker.
"""

import inspect
from pycompss.runtime.commons import IS_PYTHON3
from pycompss.runtime.commons import IS_INTERACTIVE

DECORATORS_TO_CHECK = ['pycompss/api/binary.py',
                       'pycompss/api/constraint.py',
                       'pycompss/api/decaf.py',
                       'pycompss/api/implement.py',
                       'pycompss/api/mpi.py',
                       'pycompss/api/ompss.py',
                       'pycompss/api/opencl.py',
                       'pycompss/api/parallel.py',
                       'pycompss/api/task.py']

def i_am_at_master():
    """
    Determine if the execution is being performed in the master node
    # if 'pycompss/runtime/launch.py' in inspect.stack()[-1][1]: --> I am at master
    # if inspect.stack()[-2][3] == 'compss_main' --> I am at master
    # if 'pycompss/interactive.py' in inspect.stack()[3][1] --> I am at master in interactive mode
    # if 'pycompss/api/task.py' in inspect.stack()[2][1]    --> I am at master in interactive task decorator
    # if 'pycompss/api/task.py' in inspect.stack()[1][1]    --> I am at master in interactive task decorator

    :return: <Boolean> - True if we are in the master node.
    """

    stack = inspect.stack()
    if IS_INTERACTIVE:
        if IS_PYTHON3:
            return 'pycompss/interactive.py' in stack[9][1] \
                   or any(decorator in stack[2][1] for decorator in DECORATORS_TO_CHECK) \
                   or any(decorator in stack[1][1] for decorator in DECORATORS_TO_CHECK)
        else:
            return 'pycompss/interactive.py' in stack[3][1] \
                   or any(decorator in stack[2][1] for decorator in DECORATORS_TO_CHECK) \
                   or any(decorator in stack[1][1] for decorator in DECORATORS_TO_CHECK)
    else:
        return 'pycompss/runtime/launch.py' in stack[-1][1]

def i_am_at_worker():
    """
    Determine if the execution is being performed in a worker node.
    # if (inspect.stack()[-2][3] == 'compss_worker' or
    #     inspect.stack()[-2][3] == 'compss_persistent_worker'): --> I am at worker

    :return: <Boolean> - True if we are in a worker node.
    """

    return inspect.stack()[-2][3] in ['compss_worker', 'compss_persistent_worker']

def i_am_within_scope():
    """
    Determine if the execution is being performed within the PyCOMPSs scope.

    :return:  <Boolean> - True if under scope. False on the contrary.
    """

    return i_am_at_master() or i_am_at_worker()
    # Old way: - Conflicts with dataClay
    # import sys
    # return sys.path[0].endswith('Bindings/python/2/pycompss/runtime') or \
    #        sys.path[0].endswith('Bindings/python/2/pycompss/worker') or \
    #        sys.path[0].endswith('Bindings/python/3/pycompss/runtime') or \
    #        sys.path[0].endswith('Bindings/python/3/pycompss/worker') or \
    #        sys.path[0] == ''
<commit_msg>Added check with latest jupyter stack.<commit_after>#!/usr/bin/python
#
#  Copyright 2002-2018 Barcelona Supercomputing Center (www.bsc.es)
#
#  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.
#

# -*- coding: utf-8 -*-

"""
PyCOMPSs Utils - Location
===================
    This file contains the methods to detect the origin of the call stack.
    Useful to detect if we are in the master or in the worker.
"""

import inspect
from pycompss.runtime.commons import IS_PYTHON3
from pycompss.runtime.commons import IS_INTERACTIVE

DECORATORS_TO_CHECK = ['pycompss/api/binary.py',
                       'pycompss/api/constraint.py',
                       'pycompss/api/decaf.py',
                       'pycompss/api/implement.py',
                       'pycompss/api/mpi.py',
                       'pycompss/api/ompss.py',
                       'pycompss/api/opencl.py',
                       'pycompss/api/parallel.py',
                       'pycompss/api/task.py']

def i_am_at_master():
    """
    Determine if the execution is being performed in the master node
    # if 'pycompss/runtime/launch.py' in inspect.stack()[-1][1]: --> I am at master
    # if inspect.stack()[-2][3] == 'compss_main' --> I am at master
    # if 'pycompss/interactive.py' in inspect.stack()[3][1] --> I am at master in interactive mode
    # if 'pycompss/api/task.py' in inspect.stack()[2][1]    --> I am at master in interactive task decorator
    # if 'pycompss/api/task.py' in inspect.stack()[1][1]    --> I am at master in interactive task decorator

    :return: <Boolean> - True if we are in the master node.
    """

    stack = inspect.stack()
    if IS_INTERACTIVE:
        if IS_PYTHON3:
            # interactive.py in [9][1] in 3.4 and 3.5, and in [8][1] in 3.6
            return 'pycompss/interactive.py' in stack[9][1] or 'pycompss/interactive.py' in stack[8][1] \
                   or any(decorator in stack[2][1] for decorator in DECORATORS_TO_CHECK) \
                   or any(decorator in stack[1][1] for decorator in DECORATORS_TO_CHECK)
        else:
            return 'pycompss/interactive.py' in stack[3][1] \
                   or any(decorator in stack[2][1] for decorator in DECORATORS_TO_CHECK) \
                   or any(decorator in stack[1][1] for decorator in DECORATORS_TO_CHECK)
    else:
        return 'pycompss/runtime/launch.py' in stack[-1][1]

def i_am_at_worker():
    """
    Determine if the execution is being performed in a worker node.
    # if (inspect.stack()[-2][3] == 'compss_worker' or
    #     inspect.stack()[-2][3] == 'compss_persistent_worker'): --> I am at worker

    :return: <Boolean> - True if we are in a worker node.
    """

    return inspect.stack()[-2][3] in ['compss_worker', 'compss_persistent_worker']

def i_am_within_scope():
    """
    Determine if the execution is being performed within the PyCOMPSs scope.

    :return:  <Boolean> - True if under scope. False on the contrary.
    """

    return i_am_at_master() or i_am_at_worker()
    # Old way: - Conflicts with dataClay
    # import sys
    # return sys.path[0].endswith('Bindings/python/2/pycompss/runtime') or \
    #        sys.path[0].endswith('Bindings/python/2/pycompss/worker') or \
    #        sys.path[0].endswith('Bindings/python/3/pycompss/runtime') or \
    #        sys.path[0].endswith('Bindings/python/3/pycompss/worker') or \
    #        sys.path[0] == ''
<|endoftext|>


<commit_before>import json
import scrapy
from locations.items import GeojsonPointItem

class DiscoArgentinaSpider(scrapy.Spider):
    name = "disco_argentina"
    allowed_domains = ["www.disco.com.ar"]

    def start_requests(self):
        url = 'https://www.disco.com.ar/Login/PreHomeService.aspx/TraerLocales'
        headers={
                    'Content-Type': 'application/json',
                }
        form_data = {}

        yield scrapy.http.FormRequest(
            url=url, method='POST', formdata=form_data,
            headers=headers, callback=self.parse
        )

    def parse(self, response):
        result = response.body_as_unicode().replace("\\", '')
        result = result.replace("{\"d\":\"", '')
        result = result[:-2]
        data = json.loads(result)
        for store in data['Locales']:
            properties = {
                'ref': store['Local']['IdProvincia'].strip(),
                'name': store['Local']['Nombre'].strip(),
                'addr_full': store['Local']['Direccion'].strip(),
                'city': store['Local']['Localidad'].strip(),
                'state': store['Local']['Provincia'].strip(),
                'postcode': store['Local']['CodigoPostal'].strip(),
                'lat': store['Local']['Latitud'].strip(),
                'lon': store['Local']['Longitud'].strip(),
                'phone': store['Local']['Telefono'].strip(),
            }

            yield GeojsonPointItem(**properties)<commit_msg>Disco Argentina #90<commit_after>import json
import scrapy
from locations.items import GeojsonPointItem

class DiscoArgentinaSpider(scrapy.Spider):
    name = "disco_argentina"
    allowed_domains = ["www.disco.com.ar"]

    def start_requests(self):
        url = 'https://www.disco.com.ar/Login/PreHomeService.aspx/TraerLocales'
        headers={
                    'Content-Type': 'application/json',
                }
        form_data = {}

        yield scrapy.http.FormRequest(
            url=url, method='POST', formdata=form_data,
            headers=headers, callback=self.parse
        )

    def parse(self, response):
        result = response.body_as_unicode().replace('\\', '')
        result = result[:5] + result[6:-2] + result[-1:]
        data = json.loads(result)
        ref = 0
        for store in data['d']['Locales']:
            properties = {
                'ref': ref,
                'name': store['Local']['Nombre'].strip(),
                'addr_full': store['Local']['Direccion'].strip(),
                'city': store['Local']['Localidad'].strip(),
                'state': store['Local']['Provincia'].strip(),
                'postcode': store['Local']['CodigoPostal'].strip(),
                'lat': float(store['Local']['Latitud'].strip()),
                'lon': float(store['Local']['Longitud'].strip()),
                'phone': store['Local']['Telefono'].strip(),
            }
            ref += 1
            yield GeojsonPointItem(**properties)<|endoftext|>


<commit_before>import numpy as np
from logistic import LogisticRegression

def test_lr_classifier():
    # data from:
    # http://cs229.stanford.edu/ps/ps1/logistic_x.txt
    # http://cs229.stanford.edu/ps/ps1/logistic_y.txt
    try:
        X = np.loadtxt('logistic_x.txt')
    except FileNotFoundError:
        X = np.loadtxt('logistic_regression/logistic_x.txt')

    try:
        y = np.loadtxt('logistic_y.txt')
    except FileNotFoundError:
        y = np.loadtxt('logistic_regression/logistic_y.txt')

    lr_clf = LogisticRegression()
    lr_clf.fit(X, y)

    # test intercept
    intercept = lr_clf.intercept_
    assert(abs(intercept - -2.618) < 0.01)

    # test coefficient
    coef = lr_clf.coef_
    assert(abs(coef[0] - 0.76) < 0.01)
    assert(abs(coef[1] - 1.17) < 0.01)

if __name__ == "__main__":
    test_lr_classifier()
<commit_msg>add test<commit_after>import numpy as np
from logistic import LogisticRegression

def read_data():
    # data from:
    # http://cs229.stanford.edu/ps/ps1/logistic_x.txt
    # http://cs229.stanford.edu/ps/ps1/logistic_y.txt
    try:
        X = np.loadtxt('logistic_x.txt')
    except FileNotFoundError:
        X = np.loadtxt('logistic_regression/logistic_x.txt')

    try:
        y = np.loadtxt('logistic_y.txt')
    except FileNotFoundError:
        y = np.loadtxt('logistic_regression/logistic_y.txt')

    return (X, y)

def test_lr_newton_method():
    X, y = read_data()

    lr_clf = LogisticRegression(solver="newton_method")
    lr_clf.fit(X, y)

    # test intercept
    intercept = lr_clf.intercept_
    assert(abs(intercept - -2.618) < 0.01)

    # test coefficient
    coef = lr_clf.coef_
    assert(abs(coef[0] - 0.76) < 0.01)
    assert(abs(coef[1] - 1.17) < 0.01)

def test_lr_gradient_descent():
    X, y = read_data()

    lr_clf = LogisticRegression(learning_rate=0.1, max_iter=10000,
                                solver="gradient_descent")
    lr_clf.fit(X, y)

    # test intercept
    intercept = lr_clf.intercept_
    assert(abs(intercept - -2.618) < 0.01)

    # test coefficient
    coef = lr_clf.coef_
    assert(abs(coef[0] - 0.76) < 0.01)
    assert(abs(coef[1] - 1.17) < 0.01)

def test_lr_stochastic_gradient_descent():
    X, y = read_data()

    lr_clf = LogisticRegression(learning_rate=0.001, max_iter=10000,
                                solver="stochastic_gradient_descent")
    lr_clf.fit(X, y)

    # test intercept
    intercept = lr_clf.intercept_
    assert(abs(intercept - -2.618) < 0.01)

    # test coefficient
    coef = lr_clf.coef_
    assert(abs(coef[0] - 0.76) < 0.01)
    assert(abs(coef[1] - 1.17) < 0.01)

if __name__ == "__main__":
    test_lr_newton_method()
    test_lr_gradient_descent()
    test_lr_stochastic_gradient_descent()
<|endoftext|>


<commit_before>from google.appengine.api import mail

from django.shortcuts import render_to_response, redirect, get_object_or_404
from django.template import RequestContext
from django.conf import settings

from wager.forms import WagerForm, UserForm, PickForm
from wager.models import Wager, User, Entry, Award

def index(request):
    if request.method == 'POST':
        wager_form = WagerForm(data=request.POST)
        if wager_form.is_valid():
            wager = wager_form.save()
            return redirect('wager', slug=wager.slug)
    else:
        wager_form = WagerForm()
    return render_to_response('index.html', {'wager_form': wager_form}, context_instance=RequestContext(request))

def wager(request, slug):
    wager = get_object_or_404(Wager, slug=slug)
    if request.method == 'POST':
        user_form = UserForm(data=request.POST)
        if user_form.is_valid():
            user = User(name=user_form.cleaned_data['name'], email=user_form.cleaned_data['email'], wager=wager)
            user.save()
            mail.send_mail(sender="Oscar Wager <oscarwager@oscarwager.net",
                           to="%s" % user.email,
                           subject="Oscar Wager - %s" % user.wager.name,
                           body="""
Hi %s,

You've signed up to be part of an awesome Oscar wager!

Choose your films wisely young Padawan and eat your greens.

Here's the link to your Oscar wager: http://%s/%s/pick/%s/

Thanks,
The Oscar Wager team""" % (user.name, user.slug, settings.ROOT_URL, user.wager.slug))
            return redirect('pick', wager_slug=wager.slug, user_slug=user.slug)
    else:
        user_form = UserForm()
    return render_to_response('wager.html', {'wager': wager, 'user_form': user_form, 'ROOT_URL': settings.ROOT_URL}, context_instance=RequestContext(request))

def pick(request, wager_slug, user_slug):
    wager = get_object_or_404(Wager, slug=wager_slug)
    user = get_object_or_404(User, slug=user_slug, wager=wager)
    award = Award.objects.all()[0]
    entries = award.entries.all()
    pick_form = PickForm()
    if request.method == 'POST':
        pick_form = PickForm(data={'user': user.id, 'wager': wager.id, 'entry': request.POST.get('winner')})
        if pick_form.is_valid():
            pass
    return render_to_response('pick.html', {'wager': wager, 'user': user, 'award': award, 'entries': entries, 'pick_form': pick_form}, context_instance=RequestContext(request))<commit_msg>Saving the users pick.<commit_after>from google.appengine.api import mail

from django.shortcuts import render_to_response, redirect, get_object_or_404
from django.template import RequestContext
from django.conf import settings

from wager.forms import WagerForm, UserForm, PickForm
from wager.models import Wager, User, Entry, Award

def index(request):
    if request.method == 'POST':
        wager_form = WagerForm(data=request.POST)
        if wager_form.is_valid():
            wager = wager_form.save()
            return redirect('wager', slug=wager.slug)
    else:
        wager_form = WagerForm()
    return render_to_response('index.html', {'wager_form': wager_form}, context_instance=RequestContext(request))

def wager(request, slug):
    wager = get_object_or_404(Wager, slug=slug)
    if request.method == 'POST':
        user_form = UserForm(data=request.POST)
        if user_form.is_valid():
            user = User(name=user_form.cleaned_data['name'], email=user_form.cleaned_data['email'], wager=wager)
            user.save()
            mail.send_mail(sender="Oscar Wager <oscarwager@oscarwager.net",
                           to="%s" % user.email,
                           subject="Oscar Wager - %s" % user.wager.name,
                           body="""
Hi %s,

You've signed up to be part of an awesome Oscar wager!

Choose your films wisely young Padawan and eat your greens.

Here's the link to your Oscar wager: http://%s/%s/pick/%s/

Thanks,
The Oscar Wager team""" % (user.name, user.slug, settings.ROOT_URL, user.wager.slug))
            return redirect('pick', wager_slug=wager.slug, user_slug=user.slug)
    else:
        user_form = UserForm()
    return render_to_response('wager.html', {'wager': wager, 'user_form': user_form, 'ROOT_URL': settings.ROOT_URL}, context_instance=RequestContext(request))

def pick(request, wager_slug, user_slug):
    wager = get_object_or_404(Wager, slug=wager_slug)
    user = get_object_or_404(User, slug=user_slug, wager=wager)
    award = Award.objects.all()[0]
    entries = award.entries.all()
    pick_form = PickForm()
    if request.method == 'POST':
        pick_form = PickForm(data={'user': user.id, 'wager': wager.id, 'entry': request.POST.get('winner')})
        if pick_form.is_valid():
            pick_form.save()
    return render_to_response('pick.html', {'wager': wager, 'user': user, 'award': award, 'entries': entries, 'pick_form': pick_form}, context_instance=RequestContext(request))<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright 2013
#    Author: Guewen Baconnier - Camptocamp SA
#            Augustin Cisterne-Kaasv - Elico-corp
#            David Béal - Akretion
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import fields, orm, osv
from openerp.addons.connector.queue.job import job
from openerp.addons.connector.unit.mapper import (mapping,
                                                  changed_by,
                                                  ExportMapper)
from openerp.addons.magentoerpconnect.unit.delete_synchronizer import (
        MagentoDeleteSynchronizer)
from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
        MagentoTranslationExporter)
from openerp.addons.magentoerpconnect.backend import magento
from openerp.addons.magentoerpconnect.product import ProductProductAdapter
from openerp.addons.connector.exception import MappingError
from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
    export_record
)

class MagentoProductProduct(orm.Model):
    _inherit='magento.product.product'

    #Automatically create the magento binding for each image
    def create(self, cr, uid, vals, context=None):
        mag_image_obj = self.pool['magento.product.image']
        mag_product_id = super(MagentoProductProduct, self).\
            create(cr, uid, vals, context=None)
        mag_product = self.browse(cr, uid, mag_product_id, context=context)
        if mag_product.backend_id.auto_bind_image:
            for image in mag_product.image_ids:
                mag_image_obj.create(cr, uid, {
                    'openerp_id': image.id,
                    'backend_id': mag_product.backend_id.id,
                    }, context=context)
        return mag_product_id

@magento
class ProductProductDeleteSynchronizer(MagentoDeleteSynchronizer):
    """ Partner deleter for Magento """
    _model_name = ['magento.product.product']

@magento
class ProductProductExport(MagentoTranslationExporter):
    _model_name = ['magento.product.product']

    def _export_dependencies(self):
        """ Export the dependencies for the product"""
        #TODO add export of category
        attribute_binder = self.get_binder_for_model('magento.product.attribute')
        option_binder = self.get_binder_for_model('magento.attribute.option')
        record = self.binding_record
        for group in record.attribute_group_ids:
            for attribute in group.attribute_ids:
                attribute_ext_id = attribute_binder.to_backend(attribute.attribute_id.id, wrap=True)
                if attribute_ext_id:
                    options = []
                    if attribute.ttype == 'many2one' and record[attribute.name]:
                        options = [record[attribute.name]]
                    elif attribute.ttype == 'many2many':
                        options = record[attribute.name]
                    for option in options:
                        if not option_binder.to_backend(option.id, wrap=True):
                            ctx = self.session.context.copy()
                            ctx['connector_no_export'] = True
                            binding_id = self.session.pool['magento.attribute.option'].create(
                                                    self.session.cr, self.session.uid,{
                                                    'backend_id': self.backend_record.id,
                                                    'openerp_id': option.id,
                                                    'name': option.name,
                                                    }, context=ctx)
                            export_record(self.session, 'magento.attribute.option', binding_id)

@magento
class ProductProductExportMapper(ExportMapper):
    _model_name = 'magento.product.product'

    #TODO FIXME
    # direct = [('name', 'name'),
    #           ('description', 'description'),
    #           ('weight', 'weight'),
    #           ('list_price', 'price'),
    #           ('description_sale', 'short_description'),
    #           ('default_code', 'sku'),
    #           ('product_type', 'type'),
    #           ('created_at', 'created_at'),
    #           ('updated_at', 'updated_at'),
    #           ('status', 'status'),
    #           ('visibility', 'visibility'),
    #           ('product_type', 'product_type')
    #           ]
    @mapping
    def all(self, record):
        return {'name': record.name,
                'description': record.description,
                'weight': record.weight,
                'price': record.list_price,
                'short_description': record.description_sale,
                'type': record.product_type,
                'created_at': record.created_at,
                #'updated_at': record.updated_at,
                'status': record.status,
                'visibility': record.visibility,
                'product_type': record.product_type }

    @mapping
    def sku(self, record):
        sku = record.default_code
        if not sku:
            raise MappingError("The product attribute default code cannot be empty.")
        return {'sku': sku}

    @mapping
    def set(self, record):
        binder = self.get_binder_for_model('magento.attribute.set')
        set_id = binder.to_backend(record.attribute_set_id.id, wrap=True)
        return {'attrset': set_id}

    @mapping
    def updated_at(self, record):
        updated_at = record.updated_at
        if not updated_at:
            updated_at = '1970-01-01'
        return {'updated_at': updated_at}

    @mapping
    def website_ids(self, record):
        website_ids = []
        for website_id in record.website_ids:
            magento_id = website_id.magento_id
            website_ids.append(magento_id)
        return {'website_ids': website_ids}

    @mapping
    def category(self, record):
        categ_ids = []
        if record.categ_id:
            for m_categ in record.categ_id.magento_bind_ids:
                if m_categ.backend_id.id == self.backend_record.id:
                    categ_ids.append(m_categ.magento_id)

        for categ in record.categ_ids:
            for m_categ in categ.magento_bind_ids:
                if m_categ.backend_id.id == self.backend_record.id:
                    categ_ids.append(m_categ.magento_id)
        return {'categories': categ_ids}

    @mapping
    def get_product_attribute_option(self, record):
        result = {}
        attribute_binder = self.get_binder_for_model('magento.product.attribute')
        option_binder = self.get_binder_for_model('magento.attribute.option')
        for group in record.attribute_group_ids:
            for attribute in group.attribute_ids:
                magento_attribute = None
                #TODO maybe adding a get_bind function can be better
                for bind in attribute.magento_bind_ids:
                    if bind.backend_id.id == self.backend_record.id:
                        magento_attribute = bind

                if not magento_attribute:
                    continue

                if attribute.ttype == 'many2one':
                    option = record[attribute.name]
                    if option:
                        result[magento_attribute.attribute_code] = \
                            option_binder.to_backend(option.id, wrap=True)
                    else:
                        continue
                elif attribute.ttype == 'many2many':
                    options = record[attribute.name]
                    if options:
                        result[magento_attribute.attribute_code] = \
                            [option_binder.to_backend(option.id, wrap=True) for option in options]
                    else:
                        continue
                else:
                    #TODO add support of lang
                    result[magento_attribute.attribute_code] = record[attribute.name]
        return result
<commit_msg>[IMP] add automatic bind when the product sku already exist on Magento side<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright 2013
#    Author: Guewen Baconnier - Camptocamp SA
#            Augustin Cisterne-Kaasv - Elico-corp
#            David Béal - Akretion
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import fields, orm, osv
from openerp.addons.connector.queue.job import job
from openerp.addons.connector.unit.mapper import (mapping,
                                                  changed_by,
                                                  ExportMapper)
from openerp.addons.magentoerpconnect.unit.delete_synchronizer import (
        MagentoDeleteSynchronizer)
from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
        MagentoTranslationExporter)
from openerp.addons.magentoerpconnect.backend import magento
from openerp.addons.magentoerpconnect.product import ProductProductAdapter
from openerp.addons.connector.exception import MappingError
from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
    export_record
)
from openerp.addons.magentoerpconnect.exception import SkuAlreadyExistInBackend
import logging
_logger = logging.getLogger(__name__)

class MagentoProductProduct(orm.Model):
    _inherit='magento.product.product'

    #Automatically create the magento binding for each image
    def create(self, cr, uid, vals, context=None):
        mag_image_obj = self.pool['magento.product.image']
        mag_product_id = super(MagentoProductProduct, self).\
            create(cr, uid, vals, context=None)
        mag_product = self.browse(cr, uid, mag_product_id, context=context)
        if mag_product.backend_id.auto_bind_image:
            for image in mag_product.image_ids:
                mag_image_obj.create(cr, uid, {
                    'openerp_id': image.id,
                    'backend_id': mag_product.backend_id.id,
                    }, context=context)
        return mag_product_id

@magento
class ProductProductDeleteSynchronizer(MagentoDeleteSynchronizer):
    """ Partner deleter for Magento """
    _model_name = ['magento.product.product']

@magento
class ProductProductExport(MagentoTranslationExporter):
    _model_name = ['magento.product.product']

    # Force only one way
    # Catalog is by default only
    # edited on OpenERP/Odoo side
    def _should_import(self):
        return False

    def _create(self, data):
        """ Create the Magento record """
        # special check on data before export
        sku = data.pop('sku')
        attr_set_id = data.pop('attrset')
        product_type = data.pop('product_type')
        self._validate_data(data)
        try:
            return self.backend_adapter.create(
                product_type, attr_set_id, sku, data)
        except SkuAlreadyExistInBackend, e:
            _logger.warning(('Product %s already exist in Magento. '
                            'Try to bind it') % sku)
            record = self.backend_adapter.read_with_sku(sku)
            mag_id = record['product_id']
            self.backend_adapter.write(mag_id, data)
            _logger.info(('Product %s have been binded with '
                          'an existing product') % sku)
            return mag_id

    def _export_dependencies(self):
        """ Export the dependencies for the product"""
        #TODO add export of category
        attribute_binder = self.get_binder_for_model('magento.product.attribute')
        option_binder = self.get_binder_for_model('magento.attribute.option')
        record = self.binding_record
        for group in record.attribute_group_ids:
            for attribute in group.attribute_ids:
                attribute_ext_id = attribute_binder.to_backend(attribute.attribute_id.id, wrap=True)
                if attribute_ext_id:
                    options = []
                    if attribute.ttype == 'many2one' and record[attribute.name]:
                        options = [record[attribute.name]]
                    elif attribute.ttype == 'many2many':
                        options = record[attribute.name]
                    for option in options:
                        if not option_binder.to_backend(option.id, wrap=True):
                            ctx = self.session.context.copy()
                            ctx['connector_no_export'] = True
                            binding_id = self.session.pool['magento.attribute.option'].create(
                                                    self.session.cr, self.session.uid,{
                                                    'backend_id': self.backend_record.id,
                                                    'openerp_id': option.id,
                                                    'name': option.name,
                                                    }, context=ctx)
                            export_record(self.session, 'magento.attribute.option', binding_id)

@magento
class ProductProductExportMapper(ExportMapper):
    _model_name = 'magento.product.product'

    #TODO FIXME
    # direct = [('name', 'name'),
    #           ('description', 'description'),
    #           ('weight', 'weight'),
    #           ('list_price', 'price'),
    #           ('description_sale', 'short_description'),
    #           ('default_code', 'sku'),
    #           ('product_type', 'type'),
    #           ('created_at', 'created_at'),
    #           ('updated_at', 'updated_at'),
    #           ('status', 'status'),
    #           ('visibility', 'visibility'),
    #           ('product_type', 'product_type')
    #           ]
    @mapping
    def all(self, record):
        return {'name': record.name,
                'description': record.description,
                'weight': record.weight,
                'price': record.list_price,
                'short_description': record.description_sale,
                'type': record.product_type,
                'created_at': record.created_at,
                #'updated_at': record.updated_at,
                'status': record.status,
                'visibility': record.visibility,
                'product_type': record.product_type }

    @mapping
    def sku(self, record):
        sku = record.default_code
        if not sku:
            raise MappingError("The product attribute default code cannot be empty.")
        return {'sku': sku}

    @mapping
    def set(self, record):
        binder = self.get_binder_for_model('magento.attribute.set')
        set_id = binder.to_backend(record.attribute_set_id.id, wrap=True)
        return {'attrset': set_id}

    @mapping
    def updated_at(self, record):
        updated_at = record.updated_at
        if not updated_at:
            updated_at = '1970-01-01'
        return {'updated_at': updated_at}

    @mapping
    def website_ids(self, record):
        website_ids = []
        for website_id in record.website_ids:
            magento_id = website_id.magento_id
            website_ids.append(magento_id)
        return {'website_ids': website_ids}

    @mapping
    def category(self, record):
        categ_ids = []
        if record.categ_id:
            for m_categ in record.categ_id.magento_bind_ids:
                if m_categ.backend_id.id == self.backend_record.id:
                    categ_ids.append(m_categ.magento_id)

        for categ in record.categ_ids:
            for m_categ in categ.magento_bind_ids:
                if m_categ.backend_id.id == self.backend_record.id:
                    categ_ids.append(m_categ.magento_id)
        return {'categories': categ_ids}

    @mapping
    def get_product_attribute_option(self, record):
        result = {}
        attribute_binder = self.get_binder_for_model('magento.product.attribute')
        option_binder = self.get_binder_for_model('magento.attribute.option')
        for group in record.attribute_group_ids:
            for attribute in group.attribute_ids:
                magento_attribute = None
                #TODO maybe adding a get_bind function can be better
                for bind in attribute.magento_bind_ids:
                    if bind.backend_id.id == self.backend_record.id:
                        magento_attribute = bind

                if not magento_attribute:
                    continue

                if attribute.ttype == 'many2one':
                    option = record[attribute.name]
                    if option:
                        result[magento_attribute.attribute_code] = \
                            option_binder.to_backend(option.id, wrap=True)
                    else:
                        continue
                elif attribute.ttype == 'many2many':
                    options = record[attribute.name]
                    if options:
                        result[magento_attribute.attribute_code] = \
                            [option_binder.to_backend(option.id, wrap=True) for option in options]
                    else:
                        continue
                else:
                    #TODO add support of lang
                    result[magento_attribute.attribute_code] = record[attribute.name]
        return result
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Guewen Baconnier
#    Copyright 2013 Camptocamp SA
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.tools.translate import _
from openerp.addons.connector.queue.job import job, related_action
from openerp.addons.connector.exception import FailedJobError
from openerp.addons.connector.unit.mapper import (mapping,
                                                  only_create
                                                  )
from openerp.addons.connector_ecommerce.event import on_product_price_changed
from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
    MagentoBaseExporter)
from openerp.addons.magentoerpconnect.backend import magento
from openerp.addons.magentoerpconnect import product
from openerp.addons.magentoerpconnect.connector import get_environment
from openerp.addons.magentoerpconnect.related_action import (
    unwrap_binding,
)

@magento(replacing=product.PriceProductImportMapper)
class PriceProductImportMapper(product.PriceProductImportMapper):
    _model_name = 'magento.product.product'

    @only_create
    @mapping
    def price(self, record):
        """ The price is imported at the creation of
        the product, then it is only modified and exported
        from OpenERP """
        return super(PriceProductImportMapper, self).price(record)

@magento
class ProductPriceExporter(MagentoBaseExporter):
    """ Export the price of a product.

    Use the pricelist configured on the backend for the
    default price in Magento.
    If different pricelists have been configured on the websites,
    update the prices on the different websites.
    """
    _model_name = ['magento.product.product']

    def _get_price(self, pricelist_id):
        """ Return the raw OpenERP data for ``self.binding_id`` """
        if pricelist_id is None:
            # a False value will set the 'Use default value' in Magento
            return False
        with self.session.change_context({'pricelist': pricelist_id}):
            return self.session.read(self.model._name,
                                     self.binding_id,
                                     ['price'])['price']

    def _update(self, data, storeview_id=None):
        self.backend_adapter.write(self.magento_id, data,
                                   storeview_id=storeview_id)

    def _run(self, website_id=None):
        """ Export the product inventory to Magento

        :param website_id: if None, export on all websites,
                           or OpenERP ID for the website to update
        """
        # export of products is not implemented so we just raise
        # if the export was existing, we would export it
        assert self.magento_id, "Record has been deleted in Magento"
        pricelist = self.backend_record.pricelist_id
        if not pricelist:
            name = self.backend_record.name
            raise FailedJobError(
                'Configuration Error:\n'
                'No pricelist configured on the backend %s.\n\n'
                'Resolution:\n'
                'Go to Connectors > Backends > %s.\n'
                'Choose a pricelist.' % (name, name))
        pricelist_id = pricelist.id

        # export the price for websites if they have a different
        # pricelist
        storeview_binder = self.binder_for('magento.storeview')
        for website in self.backend_record.website_ids:
            if website_id is not None and website.id != website_id:
                continue
            # 0 is the admin website, the update on this website
            # set the default values in Magento, we use the default
            # pricelist
            site_pricelist_id = None
            if website.magento_id == '0':
                site_pricelist_id = pricelist_id
            elif website.pricelist_id:
                site_pricelist_id = website.pricelist_id.id

            # The update of the prices in Magento is very weird:
            # - The price is different per website (if the option
            #   is active in the config), but is shared between
            #   the store views of a website.
            # - BUT the Magento API expects a storeview id to modify
            #   a price on a website (and not a website id...)
            # So we take the first storeview of the website to update.
            storeview_ids = self.session.search(
                'magento.storeview',
                [('store_id.website_id', '=', website.id)])
            if not storeview_ids:
                continue
            magento_storeview = storeview_binder.to_backend(storeview_ids[0])
            price = self._get_price(site_pricelist_id)
            self._update({'price': price}, storeview_id=magento_storeview)
        self.binder.bind(self.magento_id, self.binding_id)
        return _('Prices have been updated.')

@on_product_price_changed
def product_price_changed(session, model_name, record_id, fields=None):
    """ When a product.product price has been changed """
    if session.context.get('connector_no_export'):
        return
    model = session.pool.get(model_name)
    record = model.browse(session.cr, session.uid,
                          record_id, context=session.context)
    for binding in record.magento_bind_ids:
        export_product_price.delay(session,
                                   binding._model._name,
                                   binding.id,
                                   priority=5)

@job
@related_action(action=unwrap_binding)
def export_product_price(session, model_name, record_id, website_id=None):
    """ Export the price of a product. """
    product_bind = session.browse(model_name, record_id)
    backend_id = product_bind.backend_id.id
    env = get_environment(session, model_name, backend_id)
    price_exporter = env.get_connector_unit(ProductPriceExporter)
    return price_exporter.run(record_id, website_id=website_id)
<commit_msg>New API in product.py<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Guewen Baconnier
#    Copyright 2013-2015 Camptocamp SA
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.tools.translate import _
from openerp.addons.connector.queue.job import job, related_action
from openerp.addons.connector.exception import FailedJobError
from openerp.addons.connector.unit.mapper import (mapping,
                                                  only_create
                                                  )
from openerp.addons.connector_ecommerce.event import on_product_price_changed
from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
    MagentoBaseExporter)
from openerp.addons.magentoerpconnect.backend import magento
from openerp.addons.magentoerpconnect import product
from openerp.addons.magentoerpconnect.connector import get_environment
from openerp.addons.magentoerpconnect.related_action import (
    unwrap_binding,
)

@magento(replacing=product.PriceProductImportMapper)
class PriceProductImportMapper(product.PriceProductImportMapper):
    _model_name = 'magento.product.product'

    @only_create
    @mapping
    def price(self, record):
        """ The price is imported at the creation of
        the product, then it is only modified and exported
        from OpenERP """
        return super(PriceProductImportMapper, self).price(record)

@magento
class ProductPriceExporter(MagentoBaseExporter):
    """ Export the price of a product.

    Use the pricelist configured on the backend for the
    default price in Magento.
    If different pricelists have been configured on the websites,
    update the prices on the different websites.
    """
    _model_name = ['magento.product.product']

    def _get_price(self, pricelist_id):
        """ Return the raw OpenERP data for ``self.binding_id`` """
        if pricelist_id is None:
            # a False value will set the 'Use default value' in Magento
            return False
        model = self.model.with_context(pricelist=pricelist_id)
        return model.browse(self.binding_id).price

    def _update(self, data, storeview_id=None):
        self.backend_adapter.write(self.magento_id, data,
                                   storeview_id=storeview_id)

    def _run(self, website_id=None):
        """ Export the product inventory to Magento

        :param website_id: if None, export on all websites,
                           or OpenERP ID for the website to update
        """
        # export of products is not implemented so we just raise
        # if the export was existing, we would export it
        assert self.magento_id, "Record has been deleted in Magento"
        pricelist = self.backend_record.pricelist_id
        if not pricelist:
            name = self.backend_record.name
            raise FailedJobError(
                'Configuration Error:\n'
                'No pricelist configured on the backend %s.\n\n'
                'Resolution:\n'
                'Go to Connectors > Backends > %s.\n'
                'Choose a pricelist.' % (name, name))
        pricelist_id = pricelist.id

        # export the price for websites if they have a different
        # pricelist
        storeview_binder = self.binder_for('magento.storeview')
        for website in self.backend_record.website_ids:
            if website_id is not None and website.id != website_id:
                continue
            # 0 is the admin website, the update on this website
            # set the default values in Magento, we use the default
            # pricelist
            site_pricelist_id = None
            if website.magento_id == '0':
                site_pricelist_id = pricelist_id
            elif website.pricelist_id:
                site_pricelist_id = website.pricelist_id.id

            # The update of the prices in Magento is very weird:
            # - The price is different per website (if the option
            #   is active in the config), but is shared between
            #   the store views of a website.
            # - BUT the Magento API expects a storeview id to modify
            #   a price on a website (and not a website id...)
            # So we take the first storeview of the website to update.
            storeview = self.env['magento.storeview'].search(
                [('store_id.website_id', '=', website.id)],
                limit=1)
            if not storeview:
                continue
            magento_storeview_id = storeview_binder.to_backend(storeview.id)
            price = self._get_price(site_pricelist_id)
            self._update({'price': price}, storeview_id=magento_storeview_id)
        self.binder.bind(self.magento_id, self.binding_id)
        return _('Prices have been updated.')

@on_product_price_changed
def product_price_changed(session, model_name, record_id, fields=None):
    """ When a product.product price has been changed """
    if session.context.get('connector_no_export'):
        return
    model = session.env[model_name]
    record = model.browse(record_id)
    for binding in record.magento_bind_ids:
        export_product_price.delay(session,
                                   binding._model._name,
                                   binding.id,
                                   priority=5)

@job
@related_action(action=unwrap_binding)
def export_product_price(session, model_name, record_id, website_id=None):
    """ Export the price of a product. """
    product_binding = session.env[model_name].browse(record_id)
    if not product_binding.exists():
        return
    backend_id = product_binding.backend_id.id
    env = get_environment(session, model_name, backend_id)
    price_exporter = env.get_connector_unit(ProductPriceExporter)
    return price_exporter.run(record_id, website_id=website_id)
<|endoftext|>


<commit_before>import sys
from os.path import expanduser
import mechanize
from bug import Bug, BugNotFound
import textwrap
import argparse
import pydoc
from ConfigParser import SafeConfigParser

class NoPaging(Exception): pass
def windowsize():
	from fcntl import ioctl
	from termios import TIOCGWINSZ
	from array import array
	winsize = array("H", [0, 0, 0, 0] )
	ioctl(sys.stdout.fileno(), TIOCGWINSZ, winsize)
	return (winsize[1], winsize[0])

class Bugger(object):
	def __init__(self, url):
		self.url = url
		self.browser = mechanize.Browser()

	def bug(self, bug_id):
		response = self.browser.open("%s/view.php?id=%d" % ( self.url, bug_id))
		return Bug(response.read())

if __name__ == '__main__':
	reload(sys)
	sys.setdefaultencoding("utf-8")
	configparser = SafeConfigParser()
	url = None
	for p in [expanduser('~/.buggerrc'), expanduser('~/.config/bugger/buggerrc')]:
		try:
			configparser.readfp(open(p))
			break #success, break
		except IOError: #no such config file?
			pass

	parser = argparse.ArgumentParser(description='Mechanized Mantis', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
	parser.set_defaults(**dict(configparser.items('bugger')))
	parser.add_argument('--url', '-u', help='URL to Mantis')
	parser.add_argument('id', type=int, help='ID of the bug to operate on')
	args = parser.parse_args()
	bug_id = args.id
	print url
	output = ""
	try:
		bug = Bugger(url).bug(bug_id)
		output += bug.summary
		output += "\n"
		output += "Description: " + bug.description
		try:
			output += "\nAdditional Information: " + bug.additional_information
		except AttributeError:
			# No additional info found
			pass
	except BugNotFound:
		output = "Sorry, that bug doesn't exist."

	try:
		width, height = windowsize()
		if output.count("\n") > height:
			pydoc.pager(output)
		else:
			raise NoPaging
	except (IOError, NoPaging):
		print(output)
		pass
<commit_msg>unbreak url fetching<commit_after>import sys
from os.path import expanduser
import mechanize
from bug import Bug, BugNotFound
import textwrap
import argparse
import pydoc
from ConfigParser import SafeConfigParser

class NoPaging(Exception): pass
def windowsize():
	from fcntl import ioctl
	from termios import TIOCGWINSZ
	from array import array
	winsize = array("H", [0, 0, 0, 0] )
	ioctl(sys.stdout.fileno(), TIOCGWINSZ, winsize)
	return (winsize[1], winsize[0])

class Bugger(object):
	def __init__(self, url):
		self.url = url
		self.browser = mechanize.Browser()

	def bug(self, bug_id):
		response = self.browser.open("%s/view.php?id=%d" % ( self.url, bug_id))
		return Bug(response.read())

if __name__ == '__main__':
	reload(sys)
	sys.setdefaultencoding("utf-8")
	configparser = SafeConfigParser()
	url = None
	for p in [expanduser('~/.buggerrc'), expanduser('~/.config/bugger/buggerrc')]:
		try:
			configparser.readfp(open(p))
			break #success, break
		except IOError: #no such config file?
			pass

	parser = argparse.ArgumentParser(description='Mechanized Mantis', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
	parser.set_defaults(**dict(configparser.items('bugger')))
	parser.add_argument('--url', '-u', help='URL to Mantis')
	parser.add_argument('id', type=int, help='ID of the bug to operate on')
	args = parser.parse_args()
	url = args.url
	bug_id = args.id
	output = ""
	try:
		bug = Bugger(url).bug(bug_id)
		output += bug.summary
		output += "\n"
		output += "Description: " + bug.description
		try:
			output += "\nAdditional Information: " + bug.additional_information
		except AttributeError:
			# No additional info found
			pass
	except BugNotFound:
		output = "Sorry, that bug doesn't exist."

	try:
		width, height = windowsize()
		if output.count("\n") > height:
			pydoc.pager(output)
		else:
			raise NoPaging
	except (IOError, NoPaging):
		print(output)
		pass
<|endoftext|>