<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

DOCUMENTATION = '''
---
module: bigip_gtm_datacenter
short_description: Manage Datacenter configuration in BIG-IP
description:
  - Manage BIG-IP data center configuration. A data center defines the location
    where the physical network components reside, such as the server and link
    objects that share the same subnet on the network. This module is able to
    manipulate the data center definitions in a BIG-IP
version_added: "2.2"
options:
  contact:
    description:
      - The name of the contact for the data center
    required: false
    default: None
  description:
    description:
      - The description of the data center
    required: false
    default: None
  enabled:
    description:
      - Whether the data center should be enabled. At least one of state and
        enabled are required.
    required: false
    default: None
  location:
    description:
      - The location of the data center
    required: false
    default: None
  name:
    description:
      - The name of the data center
    required: true
  password:
    description:
      - BIG-IP password
    required: false
    default: admin
  server:
    description:
      - BIG-IP host
    required: true
  server_port:
    description:
      - BIG-IP server port
    required: false
    default: 443
  state:
    description:
      - The state of the datacenter on the BIG-IP. When C(present), guarantees
        that the data center exists. When C(absent) removes the data center
        from the BIG-IP. C(enabled) will enable the data center and C(disabled)
        will ensure the data center is disabled. At least one of state and
        enabled are required.
    required: false
    default: None
    choices:
      - present
      - absent
  user:
    description:
      - BIG-IP username
    required: false
    default: admin
  validate_certs:
    description:
      - If C(no), SSL certificates will not be validated. This should only be
        used on personally controlled sites using self-signed certificates.
    required: false
    default: yes
    choices:
      - yes
      - no
notes:
  - Requires the f5-sdk Python package on the host. This is as easy as
    pip install f5-sdk
requirements:
  - f5-sdk
author:
  - Tim Rupp (@caphrim007)
'''

EXAMPLES = '''
- name: Create data center "New York"
  bigip_gtm_datacenter:
      server: "big-ip"
      name: "New York"
      location: "222 West 23rd"
  delegate_to: localhost
'''

RETURN = '''
contact:
    description: The contact that was set on the datacenter
    returned: changed
    type: string
    sample: "admin@root.local"
description:
    description: The description that was set for the datacenter
    returned: changed
    type: string
    sample: "Datacenter in NYC"
enabled:
    description: Whether the datacenter is enabled or not
    returned: changed
    type: bool
    sample: true
location:
    description: The location that is set for the datacenter
    returned: changed
    type: string
    sample: "222 West 23rd"
name:
    description: Name of the datacenter being manipulated
    returned: changed
    type: string
    sample: "foo"
'''

try:
    from f5.bigip import ManagementRoot
    from icontrol.session import iControlUnexpectedHTTPError
    HAS_F5SDK = True
except ImportError:
    HAS_F5SDK = False

class BigIpGtmDatacenter(object):
    def __init__(self, *args, **kwargs):
        if not HAS_F5SDK:
            raise F5ModuleError("The python f5-sdk module is required")

        # The params that change in the module
        self.cparams = dict()

        # Stores the params that are sent to the module
        self.params = kwargs
        self.api = ManagementRoot(kwargs['server'],
                                  kwargs['user'],
                                  kwargs['password'],
                                  port=kwargs['server_port'])

    def create(self):
        params = dict()

        check_mode = self.params['check_mode']
        contact = self.params['contact']
        description = self.params['description']
        location = self.params['location']
        name = self.params['name']
        partition = self.params['partition']
        enabled = self.params['enabled']

        if check_mode:
            return True

        # Specifically check for None because a person could supply empty
        # values which would technically still be valid
        if contact is not None:
            params['contact'] = contact

        if description is not None:
            params['description'] = description

        if location is not None:
            params['location'] = location

        if enabled is not None:
            params['enabled'] = True
        else:
            params['disabled'] = False

        params['name'] = name
        params['partition'] = partition

        self.cparams = camel_dict_to_snake_dict(params)
        if check_mode:
            return True

        d = self.api.tm.gtm.datacenters.datacenter
        d.create(**params)

        if not self.exists():
            raise F5ModuleError("Failed to create the datacenter")
        return True

    def read(self):
        """Read information and transform it

        The values that are returned by BIG-IP in the f5-sdk can have encoding
        attached to them as well as be completely missing in some cases.

        Therefore, this method will transform the data from the BIG-IP into a
        format that is more easily consumable by the rest of the class and the
        parameters that are supported by the module.
        """
        p = dict()
        name = self.params['name']
        partition = self.params['partition']
        r = self.api.tm.gtm.datacenters.datacenter.load(
            name=name,
            partition=partition
        )

        if hasattr(r, 'servers'):
            # Deliberately using sets to supress duplicates
            p['servers'] = set([str(x) for x in r.servers])
        if hasattr(r, 'contact'):
            p['contact'] = str(r.contact)
        if hasattr(r, 'location'):
            p['location'] = str(r.location)
        if hasattr(r, 'description'):
            p['description'] = str(r.description)
        if r.enabled:
            p['enabled'] = True
        else:
            p['enabled'] = False
        p['name'] = name
        return p

    def update(self):
        changed = False
        params = dict()
        current = self.read()

        check_mode = self.params['check_mode']
        contact = self.params['contact']
        description = self.params['description']
        location = self.params['location']
        name = self.params['name']
        partition = self.params['partition']
        enabled = self.params['enabled']

        if contact is not None:
            if 'contact' in current:
                if contact != current['contact']:
                    params['contact'] = contact
            else:
                params['contact'] = contact

        if description is not None:
            if 'description' in current:
                if description != current['description']:
                    params['description'] = description
            else:
                params['description'] = description

        if location is not None:
            if 'location' in current:
                if location != current['location']:
                    params['location'] = location
            else:
                params['location'] = location

        if enabled is not None:
            if current['enabled'] != enabled:
                if enabled is True:
                    params['enabled'] = True
                    params['disabled'] = False
                else:
                    params['disabled'] = True
                    params['enabled'] = False

        if params:
            changed = True
            if check_mode:
                return changed
            self.cparams = camel_dict_to_snake_dict(params)
        else:
            return changed

        r = self.api.tm.gtm.datacenters.datacenter.load(
            name=name,
            partition=partition
        )
        r.update(**params)
        r.refresh()

        return True

    def delete(self):
        params = dict()
        check_mode = self.params['check_mode']

        params['name'] = self.params['name']
        params['partition'] = self.params['partition']

        self.cparams = camel_dict_to_snake_dict(params)
        if check_mode:
            return True

        dc = self.api.tm.gtm.datacenters.datacenter.load(**params)
        dc.delete()

        if self.exists():
            raise F5ModuleError("Failed to delete the datacenter")
        return True

    def present(self):
        changed = False

        if self.exists():
            changed = self.update()
        else:
            changed = self.create()

        return changed

    def absent(self):
        changed = False

        if self.exists():
            changed = self.delete()

        return changed

    def exists(self):
        name = self.params['name']
        partition = self.params['partition']

        return self.api.tm.gtm.datacenters.datacenter.exists(
            name=name,
            partition=partition
        )

    def flush(self):
        result = dict()
        state = self.params['state']
        enabled = self.params['enabled']

        if state is None and enabled is None:
            module.fail_json(msg="Neither 'state' nor 'enabled' set")

        try:
            if state == "present":
                changed = self.present()

                # Ensure that this field is not returned to the user since it
                # is not a valid parameter to the module.
                if 'disabled' in self.cparams:
                    del self.cparams['disabled']
            elif state == "absent":
                changed = self.absent()
        except iControlUnexpectedHTTPError as e:
            raise F5ModuleError(str(e))

        result.update(**self.cparams)
        result.update(dict(changed=changed))
        return result

def main():
    argument_spec = f5_argument_spec()

    meta_args = dict(
        contact=dict(required=False, default=None),
        description=dict(required=False, default=None),
        enabled=dict(required=False, type='bool', default=None),
        location=dict(required=False, default=None),
        name=dict(required=True)
    )
    argument_spec.update(meta_args)

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True
    )

    try:
        obj = BigIpGtmDatacenter(check_mode=module.check_mode, **module.params)
        result = obj.flush()

        module.exit_json(**result)
    except F5ModuleError as e:
        module.fail_json(msg=str(e))

from ansible.module_utils.basic import *
from ansible.module_utils.ec2 import camel_dict_to_snake_dict
from ansible.module_utils.f5 import *

if __name__ == '__main__':
    main()
<commit_msg>removed redundant code<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

DOCUMENTATION = '''
---
module: bigip_gtm_datacenter
short_description: Manage Datacenter configuration in BIG-IP
description:
  - Manage BIG-IP data center configuration. A data center defines the location
    where the physical network components reside, such as the server and link
    objects that share the same subnet on the network. This module is able to
    manipulate the data center definitions in a BIG-IP
version_added: "2.2"
options:
  contact:
    description:
      - The name of the contact for the data center
    required: false
    default: None
  description:
    description:
      - The description of the data center
    required: false
    default: None
  enabled:
    description:
      - Whether the data center should be enabled. At least one of state and
        enabled are required.
    required: false
    default: None
  location:
    description:
      - The location of the data center
    required: false
    default: None
  name:
    description:
      - The name of the data center
    required: true
  password:
    description:
      - BIG-IP password
    required: false
    default: admin
  server:
    description:
      - BIG-IP host
    required: true
  server_port:
    description:
      - BIG-IP server port
    required: false
    default: 443
  state:
    description:
      - The state of the datacenter on the BIG-IP. When C(present), guarantees
        that the data center exists. When C(absent) removes the data center
        from the BIG-IP. C(enabled) will enable the data center and C(disabled)
        will ensure the data center is disabled. At least one of state and
        enabled are required.
    required: false
    default: None
    choices:
      - present
      - absent
  user:
    description:
      - BIG-IP username
    required: false
    default: admin
  validate_certs:
    description:
      - If C(no), SSL certificates will not be validated. This should only be
        used on personally controlled sites using self-signed certificates.
    required: false
    default: yes
    choices:
      - yes
      - no
notes:
  - Requires the f5-sdk Python package on the host. This is as easy as
    pip install f5-sdk
requirements:
  - f5-sdk
author:
  - Tim Rupp (@caphrim007)
'''

EXAMPLES = '''
- name: Create data center "New York"
  bigip_gtm_datacenter:
      server: "big-ip"
      name: "New York"
      location: "222 West 23rd"
  delegate_to: localhost
'''

RETURN = '''
contact:
    description: The contact that was set on the datacenter
    returned: changed
    type: string
    sample: "admin@root.local"
description:
    description: The description that was set for the datacenter
    returned: changed
    type: string
    sample: "Datacenter in NYC"
enabled:
    description: Whether the datacenter is enabled or not
    returned: changed
    type: bool
    sample: true
location:
    description: The location that is set for the datacenter
    returned: changed
    type: string
    sample: "222 West 23rd"
name:
    description: Name of the datacenter being manipulated
    returned: changed
    type: string
    sample: "foo"
'''

try:
    from f5.bigip import ManagementRoot
    from icontrol.session import iControlUnexpectedHTTPError
    HAS_F5SDK = True
except ImportError:
    HAS_F5SDK = False

class BigIpGtmDatacenter(object):
    def __init__(self, *args, **kwargs):
        if not HAS_F5SDK:
            raise F5ModuleError("The python f5-sdk module is required")

        # The params that change in the module
        self.cparams = dict()

        # Stores the params that are sent to the module
        self.params = kwargs
        self.api = ManagementRoot(kwargs['server'],
                                  kwargs['user'],
                                  kwargs['password'],
                                  port=kwargs['server_port'])

    def create(self):
        params = dict()

        check_mode = self.params['check_mode']
        contact = self.params['contact']
        description = self.params['description']
        location = self.params['location']
        name = self.params['name']
        partition = self.params['partition']
        enabled = self.params['enabled']

        # Specifically check for None because a person could supply empty
        # values which would technically still be valid
        if contact is not None:
            params['contact'] = contact

        if description is not None:
            params['description'] = description

        if location is not None:
            params['location'] = location

        if enabled is not None:
            params['enabled'] = True
        else:
            params['disabled'] = False

        params['name'] = name
        params['partition'] = partition

        self.cparams = camel_dict_to_snake_dict(params)
        if check_mode:
            return True

        d = self.api.tm.gtm.datacenters.datacenter
        d.create(**params)

        if not self.exists():
            raise F5ModuleError("Failed to create the datacenter")
        return True

    def read(self):
        """Read information and transform it

        The values that are returned by BIG-IP in the f5-sdk can have encoding
        attached to them as well as be completely missing in some cases.

        Therefore, this method will transform the data from the BIG-IP into a
        format that is more easily consumable by the rest of the class and the
        parameters that are supported by the module.
        """
        p = dict()
        name = self.params['name']
        partition = self.params['partition']
        r = self.api.tm.gtm.datacenters.datacenter.load(
            name=name,
            partition=partition
        )

        if hasattr(r, 'servers'):
            # Deliberately using sets to supress duplicates
            p['servers'] = set([str(x) for x in r.servers])
        if hasattr(r, 'contact'):
            p['contact'] = str(r.contact)
        if hasattr(r, 'location'):
            p['location'] = str(r.location)
        if hasattr(r, 'description'):
            p['description'] = str(r.description)
        if r.enabled:
            p['enabled'] = True
        else:
            p['enabled'] = False
        p['name'] = name
        return p

    def update(self):
        changed = False
        params = dict()
        current = self.read()

        check_mode = self.params['check_mode']
        contact = self.params['contact']
        description = self.params['description']
        location = self.params['location']
        name = self.params['name']
        partition = self.params['partition']
        enabled = self.params['enabled']

        if contact is not None:
            if 'contact' in current:
                if contact != current['contact']:
                    params['contact'] = contact
            else:
                params['contact'] = contact

        if description is not None:
            if 'description' in current:
                if description != current['description']:
                    params['description'] = description
            else:
                params['description'] = description

        if location is not None:
            if 'location' in current:
                if location != current['location']:
                    params['location'] = location
            else:
                params['location'] = location

        if enabled is not None:
            if current['enabled'] != enabled:
                if enabled is True:
                    params['enabled'] = True
                    params['disabled'] = False
                else:
                    params['disabled'] = True
                    params['enabled'] = False

        if params:
            changed = True
            if check_mode:
                return changed
            self.cparams = camel_dict_to_snake_dict(params)
        else:
            return changed

        r = self.api.tm.gtm.datacenters.datacenter.load(
            name=name,
            partition=partition
        )
        r.update(**params)
        r.refresh()

        return True

    def delete(self):
        params = dict()
        check_mode = self.params['check_mode']

        params['name'] = self.params['name']
        params['partition'] = self.params['partition']

        self.cparams = camel_dict_to_snake_dict(params)
        if check_mode:
            return True

        dc = self.api.tm.gtm.datacenters.datacenter.load(**params)
        dc.delete()

        if self.exists():
            raise F5ModuleError("Failed to delete the datacenter")
        return True

    def present(self):
        changed = False

        if self.exists():
            changed = self.update()
        else:
            changed = self.create()

        return changed

    def absent(self):
        changed = False

        if self.exists():
            changed = self.delete()

        return changed

    def exists(self):
        name = self.params['name']
        partition = self.params['partition']

        return self.api.tm.gtm.datacenters.datacenter.exists(
            name=name,
            partition=partition
        )

    def flush(self):
        result = dict()
        state = self.params['state']
        enabled = self.params['enabled']

        if state is None and enabled is None:
            module.fail_json(msg="Neither 'state' nor 'enabled' set")

        try:
            if state == "present":
                changed = self.present()

                # Ensure that this field is not returned to the user since it
                # is not a valid parameter to the module.
                if 'disabled' in self.cparams:
                    del self.cparams['disabled']
            elif state == "absent":
                changed = self.absent()
        except iControlUnexpectedHTTPError as e:
            raise F5ModuleError(str(e))

        result.update(**self.cparams)
        result.update(dict(changed=changed))
        return result

def main():
    argument_spec = f5_argument_spec()

    meta_args = dict(
        contact=dict(required=False, default=None),
        description=dict(required=False, default=None),
        enabled=dict(required=False, type='bool', default=None),
        location=dict(required=False, default=None),
        name=dict(required=True)
    )
    argument_spec.update(meta_args)

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True
    )

    try:
        obj = BigIpGtmDatacenter(check_mode=module.check_mode, **module.params)
        result = obj.flush()

        module.exit_json(**result)
    except F5ModuleError as e:
        module.fail_json(msg=str(e))

from ansible.module_utils.basic import *
from ansible.module_utils.ec2 import camel_dict_to_snake_dict
from ansible.module_utils.f5 import *

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


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 F5 Networks Inc.
# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = '''
---
module: bigip_dns_record_facts
short_description: foo
description:
  - foo
version_added: "2.2"
options:
  server:
    description:
      - BIG-IP host
    required: true
  user:
    description:
      - BIG-IP username
    required: true
    aliases:
      - username
  password:
    description:
      - BIG-IP password
    required: true
notes:
  - Requires the f5-sdk Python package on the remote host. This is as easy as
    pip install f5-sdk
requirements:
  - f5-sdk
author:
    - Tim Rupp (@caphrim007)
'''

from ansible.module_utils.basic import *
from ansible.module_utils.f5_utils import *

if __name__ == '__main__':
    main()
<commit_msg>formatting<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 F5 Networks Inc.
# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = r'''
---
module: bigip_dns_record_facts
short_description: foo
description:
  - foo
version_added: "2.2"
options:
  server:
    description:
      - BIG-IP host
    required: true
  user:
    description:
      - BIG-IP username
    required: true
    aliases:
      - username
  password:
    description:
      - BIG-IP password
    required: true
notes:
  - Requires the f5-sdk Python package on the remote host. This is as easy as
    pip install f5-sdk
requirements:
  - f5-sdk
author:
    - Tim Rupp (@caphrim007)
'''

from ansible.module_utils.basic import *
from ansible.module_utils.f5_utils import *

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


<commit_before>try:
    from html.parser import HTMLParser
except ImportError:  # Python 2 compatibility
    from HTMLParser import HTMLParser
import re
from bs4 import BeautifulSoup, Comment
from django.contrib.gis.geos import GEOSGeometry
from django.db import connection
from django.db.models.sql import EmptyResultSet
from django.template import Library
from django.utils.encoding import smart_text
from django.utils.safestring import mark_safe
from common.utils.sql import get_raw_query
from ..models import Lieu
from common.utils.html import date_html as date_html_util
from common.utils.abbreviate import abbreviate as abbreviate_func

register = Library()

@register.filter
def stripchars(text):
    return HTMLParser().unescape(text)

def fix_strange_characters(text):
    return (text
            .replace('...\x1f', '…').replace('\x1c', '').replace('\x1b', '')
            .replace('\u2500', '—'))

compact_paragraph_re = re.compile(r'(?<![\n\s ])\n+[\s\n ]*\n+(?![\n\s ])')

@register.filter
def compact_paragraph(text):
    return mark_safe(compact_paragraph_re.sub('\u00A0/ ', text.strip('\n')))

escaped_chars_re = re.compile(r'([#$%&_{}])')

def escape_latex(text):
    text = (text.replace('\\', '\\char`\\\\')
            .replace('^', '\\^{}'))
    return escaped_chars_re.sub(r'\\\1', text)

html_latex_bindings = (
    (dict(name='h1'), r'\part*{', r'}'),
    (dict(name='h2'), r'\chapter*{', r'}'),
    (dict(name='h3'), r'\section*{', r'}'),
    (dict(name='p'), '\n\n', '\n\n'),
    (dict(name='cite'), r'\textit{', r'}'),
    (dict(name='em'), r'\textit{', r'}'),
    (dict(name='i'), r'\textit{', r'}'),
    (dict(name='strong'), r'\textbf{', r'}'),
    (dict(name='b'), r'\textbf{', r'}'),
    (dict(name='small'), r'\small{', r'}'),
    (dict(name='sup'), r'\textsuperscript{', r'}'),
    (dict(class_='sc'), r'\textsc{', r'}'),
    (dict(style=re.compile(r'.*font-variant:\s*'
                           r'small-caps;.*')), r'\textsc{', r'}'),
)

@register.filter
def html_to_latex(html):
    r"""
    Permet de convertir du HTML en syntaxe LaTeX.

    Attention, ce convertisseur est parfaitement incomplet et ne devrait pas
    être utilisé en dehors d'un contexte très précis.

    >>> print(html_to_latex('
Bonjour à tous
'))
    \part*{Bonjour à tous}
    >>> print(html_to_latex('Écriture romaine'))
    \textsc{Écriture romaine}
    >>> print(html_to_latex('Vive les poilus !'))
    Vive les poilus !
    """
    html = escape_latex(stripchars(fix_strange_characters(html)))
    soup = BeautifulSoup(html, 'html.parser')
    for html_selectors, latex_open_tag, latex_close_tag in html_latex_bindings:
        for tag in soup.find_all(**html_selectors):
            tag.insert(0, latex_open_tag)
            tag.append(latex_close_tag)
    for comment in soup.find_all(text=lambda text: isinstance(text, Comment)):
        comment.extract()
    return mark_safe(smart_text(soup.get_text()))

@register.simple_tag(takes_context=True)
def get_prev_event_counter(context, source, event_counter):
    if 'source_dict' not in context:
        context['source_dict'] = {}
    source_dict = context['source_dict']
    if source.pk not in source_dict:
        source_dict[source.pk] = event_counter
    return source_dict[source.pk]

@register.filter
def date_html(date, short=False):
    return date_html_util(date, short=short)

@register.filter
def abbreviate(string, min_len=1, tags=True, enabled=True):
    return abbreviate_func(string, min_len=min_len, tags=tags, enabled=enabled)

def get_data(evenements_qs, min_places, bbox):
    evenements_qs = evenements_qs.order_by()

    cursor = connection.cursor()

    valid_ancestors = Lieu.objects.filter(geometry__isnull=False).order_by()
    if bbox is not None:
        valid_ancestors = valid_ancestors.filter(geometry__contained=bbox)

    valid_ancestors_query, valid_ancestors_params = get_raw_query(
        valid_ancestors.values('id', 'path'))

    evenements_query, params = get_raw_query(
        evenements_qs.values('debut_lieu_id'))

    cursor.execute("""
    SELECT length(ancetre.path) / 4, COUNT(DISTINCT ancetre.id)
    FROM libretto_lieu AS lieu
    INNER JOIN (%s) AS ancetre ON lieu.path LIKE ancetre.path || '%%%%'
    WHERE lieu.id IN (%s)
    GROUP BY length(ancetre.path)
    ORDER BY length(ancetre.path) ASC;
    """ % (valid_ancestors_query, evenements_query),
        valid_ancestors_params + params)

    level = None
    for level, count in cursor.fetchall():
        if count >= min_places:
            break
        if count == 0:
            if level > 0:
                level -= 1
            break
    if level is None:
        return ()

    evenements_query, params = get_raw_query(
        evenements_qs.values('pk', 'debut_lieu_id'))
    params = list(params)
    if bbox is None:
        bbox_where = ''
    else:
        bbox_where = 'geometry @ ST_GeomFromEWKB(%s::bytea) AND '
        params.append(bbox.ewkb)

    params.append(level)

    cursor.execute("""
    SELECT ancetre.id, ancetre.nom, ancetre.geometry, COUNT(evenement.id) AS n
    FROM (%s) AS evenement
    INNER JOIN libretto_lieu AS lieu ON lieu.id = evenement.debut_lieu_id
    INNER JOIN (
        SELECT *
        FROM libretto_lieu
        WHERE (
            %s
            geometry IS NOT NULL
            AND length(path) / 4 = %%s
        )
        ORDER BY length(path) DESC
    ) AS ancetre ON lieu.path LIKE ancetre.path || '%%%%'
    GROUP BY ancetre.id, ancetre.nom, ancetre.geometry
    ORDER BY n DESC;
    """ % (evenements_query, bbox_where), params)
    return cursor.fetchall()

@register.simple_tag
def get_map_data(evenement_qs, min_places, bbox):
    try:
        return [(pk, nom, GEOSGeometry(geometry), n)
                for pk, nom, geometry, n in get_data(evenement_qs, min_places,
                                                     bbox)]
    except EmptyResultSet:
        return ()

@register.simple_tag(takes_context=True)
def map_request(context, lieu_pk=None, show_map=True):
    request = context['request']
    query_dict = request.GET.copy()
    if 'bbox' in query_dict:
        del query_dict['bbox']
    if 'min_places' in query_dict:
        del query_dict['min_places']
    if lieu_pk is not None:
        query_dict['lieu'] = '|%s|' % lieu_pk
    if show_map:
        query_dict['show_map'] = True
    else:
        del query_dict['show_map']
    return '?' + query_dict.urlencode()

@register.simple_tag(takes_context=True)
def export_request(context, export_format):
    request = context['request']
    query_dict = request.GET.copy()
    query_dict['format'] = export_format
    return context['export_url'] + '?' + query_dict.urlencode()

@register.simple_tag(takes_context=True)
def change_results_order(context, order_by='default'):
    query_dict = context['request'].GET.copy()
    if order_by == 'default' and 'order_by' in query_dict:
        del query_dict['order_by']
    elif order_by == 'reversed':
        query_dict['order_by'] = order_by
    return '?' + query_dict.urlencode()
<commit_msg>Formats ul & ol in XeLaTeX exports.<commit_after>try:
    from html.parser import HTMLParser
except ImportError:  # Python 2 compatibility
    from HTMLParser import HTMLParser
import re
from bs4 import BeautifulSoup, Comment
from django.contrib.gis.geos import GEOSGeometry
from django.db import connection
from django.db.models.sql import EmptyResultSet
from django.template import Library
from django.utils.encoding import smart_text
from django.utils.safestring import mark_safe
from common.utils.sql import get_raw_query
from ..models import Lieu
from common.utils.html import date_html as date_html_util
from common.utils.abbreviate import abbreviate as abbreviate_func

register = Library()

@register.filter
def stripchars(text):
    return HTMLParser().unescape(text)

def fix_strange_characters(text):
    return (text
            .replace('...\x1f', '…').replace('\x1c', '').replace('\x1b', '')
            .replace('\u2500', '—'))

compact_paragraph_re = re.compile(r'(?<![\n\s ])\n+[\s\n ]*\n+(?![\n\s ])')

@register.filter
def compact_paragraph(text):
    return mark_safe(compact_paragraph_re.sub('\u00A0/ ', text.strip('\n')))

escaped_chars_re = re.compile(r'([#$%&_{}])')

def escape_latex(text):
    text = (text.replace('\\', '\\char`\\\\')
            .replace('^', '\\^{}'))
    return escaped_chars_re.sub(r'\\\1', text)

html_latex_bindings = (
    (dict(name='h1'), r'\part*{', r'}'),
    (dict(name='h2'), r'\chapter*{', r'}'),
    (dict(name='h3'), r'\section*{', r'}'),
    (dict(name='p'), '\n\n', '\n\n'),
    (dict(name='cite'), r'\textit{', r'}'),
    (dict(name='em'), r'\textit{', r'}'),
    (dict(name='i'), r'\textit{', r'}'),
    (dict(name='strong'), r'\textbf{', r'}'),
    (dict(name='b'), r'\textbf{', r'}'),
    (dict(name='small'), r'\small{', r'}'),
    (dict(name='sup'), r'\textsuperscript{', r'}'),
    (dict(name='ul'), r'\begin{itemize}', r'\end{itemize}'),
    (dict(name='ol'), r'\begin{enumerate}', r'\end{enumerate}'),
    (dict(name='li'), r'\item{', r'}'),
    (dict(class_='sc'), r'\textsc{', r'}'),
    (dict(style=re.compile(r'.*font-variant:\s*'
                           r'small-caps;.*')), r'\textsc{', r'}'),
)

@register.filter
def html_to_latex(html):
    r"""
    Permet de convertir du HTML en syntaxe LaTeX.

    Attention, ce convertisseur est parfaitement incomplet et ne devrait pas
    être utilisé en dehors d'un contexte très précis.

    >>> print(html_to_latex('
Bonjour à tous
'))
    \part*{Bonjour à tous}
    >>> print(html_to_latex('Écriture romaine'))
    \textsc{Écriture romaine}
    >>> print(html_to_latex('Vive les poilus !'))
    Vive les poilus !
    """
    html = escape_latex(stripchars(fix_strange_characters(html)))
    soup = BeautifulSoup(html, 'html.parser')
    for html_selectors, latex_open_tag, latex_close_tag in html_latex_bindings:
        for tag in soup.find_all(**html_selectors):
            tag.insert(0, latex_open_tag)
            tag.append(latex_close_tag)
    for comment in soup.find_all(text=lambda text: isinstance(text, Comment)):
        comment.extract()
    return mark_safe(smart_text(soup.get_text()))

@register.simple_tag(takes_context=True)
def get_prev_event_counter(context, source, event_counter):
    if 'source_dict' not in context:
        context['source_dict'] = {}
    source_dict = context['source_dict']
    if source.pk not in source_dict:
        source_dict[source.pk] = event_counter
    return source_dict[source.pk]

@register.filter
def date_html(date, short=False):
    return date_html_util(date, short=short)

@register.filter
def abbreviate(string, min_len=1, tags=True, enabled=True):
    return abbreviate_func(string, min_len=min_len, tags=tags, enabled=enabled)

def get_data(evenements_qs, min_places, bbox):
    evenements_qs = evenements_qs.order_by()

    cursor = connection.cursor()

    valid_ancestors = Lieu.objects.filter(geometry__isnull=False).order_by()
    if bbox is not None:
        valid_ancestors = valid_ancestors.filter(geometry__contained=bbox)

    valid_ancestors_query, valid_ancestors_params = get_raw_query(
        valid_ancestors.values('id', 'path'))

    evenements_query, params = get_raw_query(
        evenements_qs.values('debut_lieu_id'))

    cursor.execute("""
    SELECT length(ancetre.path) / 4, COUNT(DISTINCT ancetre.id)
    FROM libretto_lieu AS lieu
    INNER JOIN (%s) AS ancetre ON lieu.path LIKE ancetre.path || '%%%%'
    WHERE lieu.id IN (%s)
    GROUP BY length(ancetre.path)
    ORDER BY length(ancetre.path) ASC;
    """ % (valid_ancestors_query, evenements_query),
        valid_ancestors_params + params)

    level = None
    for level, count in cursor.fetchall():
        if count >= min_places:
            break
        if count == 0:
            if level > 0:
                level -= 1
            break
    if level is None:
        return ()

    evenements_query, params = get_raw_query(
        evenements_qs.values('pk', 'debut_lieu_id'))
    params = list(params)
    if bbox is None:
        bbox_where = ''
    else:
        bbox_where = 'geometry @ ST_GeomFromEWKB(%s::bytea) AND '
        params.append(bbox.ewkb)

    params.append(level)

    cursor.execute("""
    SELECT ancetre.id, ancetre.nom, ancetre.geometry, COUNT(evenement.id) AS n
    FROM (%s) AS evenement
    INNER JOIN libretto_lieu AS lieu ON lieu.id = evenement.debut_lieu_id
    INNER JOIN (
        SELECT *
        FROM libretto_lieu
        WHERE (
            %s
            geometry IS NOT NULL
            AND length(path) / 4 = %%s
        )
        ORDER BY length(path) DESC
    ) AS ancetre ON lieu.path LIKE ancetre.path || '%%%%'
    GROUP BY ancetre.id, ancetre.nom, ancetre.geometry
    ORDER BY n DESC;
    """ % (evenements_query, bbox_where), params)
    return cursor.fetchall()

@register.simple_tag
def get_map_data(evenement_qs, min_places, bbox):
    try:
        return [(pk, nom, GEOSGeometry(geometry), n)
                for pk, nom, geometry, n in get_data(evenement_qs, min_places,
                                                     bbox)]
    except EmptyResultSet:
        return ()

@register.simple_tag(takes_context=True)
def map_request(context, lieu_pk=None, show_map=True):
    request = context['request']
    query_dict = request.GET.copy()
    if 'bbox' in query_dict:
        del query_dict['bbox']
    if 'min_places' in query_dict:
        del query_dict['min_places']
    if lieu_pk is not None:
        query_dict['lieu'] = '|%s|' % lieu_pk
    if show_map:
        query_dict['show_map'] = True
    else:
        del query_dict['show_map']
    return '?' + query_dict.urlencode()

@register.simple_tag(takes_context=True)
def export_request(context, export_format):
    request = context['request']
    query_dict = request.GET.copy()
    query_dict['format'] = export_format
    return context['export_url'] + '?' + query_dict.urlencode()

@register.simple_tag(takes_context=True)
def change_results_order(context, order_by='default'):
    query_dict = context['request'].GET.copy()
    if order_by == 'default' and 'order_by' in query_dict:
        del query_dict['order_by']
    elif order_by == 'reversed':
        query_dict['order_by'] = order_by
    return '?' + query_dict.urlencode()
<|endoftext|>


<commit_before>import __builtin__
import os
import glob
import re
import inspect
import gzip
from contextlib import contextmanager
from .uid import generate_string_uid

SPLITEXT_PAT = re.compile("""
    (.*?)           # The file path without the extension
    (               # The extension group
      (\.\w+)+      # The (possibly composite) extension
    )?              # The extension is optional
    $               # Anchor to the end of the file path
    """, re.VERBOSE)
"""
Regexp pattern that splits the name and extension.

:see: :meth:`splitexts`
"""

class FileError(Exception):
    pass

@contextmanager
def open(filename):
    """
    Opens the given file. If the file extension ends in ``.gz``,
    then the content is uncompressed.

    :param filename: the file path
    :return: the file input stream
    :raise: IOError if the file cannot be read
    """
    _, ext = os.path.splitext(filename)
    # The gzip or normal file open context function.
    if ext == '.gz':
        context = gzip.open
    else:
        context = __builtin__.open

    # Open the file.
    with context(filename) as fp:
        yield fp

def splitexts(location):
    """
    Splits the given file path into a name and extension.
    Unlike ``os.path.splitext``, the resulting extension can be composite.

    Example:

    >>> import os
    >>> os.path.splitext('/tmp/foo.nii.gz')
    ('/tmp/foo.nii', '.gz')
    >>> from qiutil.file import splitexts
    >>> splitexts('/tmp/foo.3/bar.nii.gz')
    ('/tmp/foo.3/bar', '.nii.gz')

    :param location: the file path
    :return: the *(prefix, extensions)* tuple
    """
    matches = SPLITEXT_PAT.match(location).groups()[:2]
    # Pad with an empty extension, if necessary.
    matches += (None,) * (2 - len(matches))

    return tuple(matches)

def splitboth(location):
    """
    Splits the given file path into a directory, name and extension.
    Unlike ``os.path.splitext``, the resulting extension can be
    composite.

    Example:

    >>> import os
    >>> from qiutil.file import splitall
    >>> splitall('/tmp/foo.nii.gz')
    ('/tmp', 'foo', '.nii.gz')

    :param location: the file path
    :return: the *(directory, prefix, extensions)* tuple
    """
    prefix, exts = splitexts(location)
    dir_path, base = os.path.split(prefix)
    if dir_path == '':
        dir_path = None

    return (dir_path, base, exts)

def generate_file_name(ext=None):
    """
    Makes a valid file name which is unique to within one microsecond of calling
    this function. The file name is ten characters long without the extension.

    :param ext: the optional file extension, with leading period delimiter
    :return: the file name
    """
    fname = generate_string_uid()
    if ext:
        return fname + ext
    else:
        return fname

class Finder(object):
    """
    Finder matches a file name glob pattern and regular expression.
    """

    def __init__(self, glob='*', regex='.*'):
        """
        :param glob: the glob pattern string
        :param regex: the :class:`RegExp` object or pattern string
        """
        self.glob = glob or '*'
        """The glob pattern string (default ``*``)."""

        if isinstance(regex, str):
            regex = re.compile(regex)
        self.regex = regex or '.*'
        """The file match regular expression (default ``.*``)."""

    def find(self, base_dir=None):
        """
        Iterates over the files which match both the :attr:`glob` and the
        :attr:`regex`.

        :param: the parent base directory path (default current directory)
        :yield: the next matching absolute file path
        """
        if not base_dir:
            base_dir = os.getcwd()
        abs_dir = os.path.abspath(base_dir)
        for match in self.match(base_dir):
            # Restore the base directory prefix.
            yield os.path.join(abs_dir, match.group(0))

    def match(self, base_dir=None):
        """
        Iterates over the files which match both the :attr:`glob` and the
        :attr:`regex`.

        :param: the parent base directory path
        :yield: the next match
        """
        # The primary glob match.
        files = glob.iglob('/'.join((base_dir, self.glob)))
        # Apply the secondary regex filter.
        prefix_len = len(base_dir) + 1
        for path in files:
            # Chop off the base directory prefix.
            rel_path = path[prefix_len:]
            # Match on the rest of the file path.
            match = self.regex.match(rel_path)
            if match:
                yield match

class FileIterator(object):
    """
    FileIterator is a generator class which iterates over the files contained
    recursively in the initializer *filespecs* parameters.
    """

    def __init__(self, *filespecs):
        """
        :param filespecs: the files, directories or file generators over which
            to iterate
        """
        self._filespecs = filespecs

    def __iter__(self):
        """
        Iterates over the files as follows:

        - If the current file specification is a file object, then yield that
          file object.

        - If the current file specification is a non-directory file path,
          then yield that file path.

        - If the current file specification is a directory, then yield each file
          contained recursively in that directory.

        - If the current file specification is a generator, then yield each
          generated item

        :yield: the next file object or path
        :raise FileError: if an iterated file path is neither a directory nor file
        :raise FileError: if an iterated item is not a file object, path
            or generator
        """
        for spec in self._filespecs:
            if isinstance(spec, file):
                yield spec
            elif isinstance(spec, str):
                if os.path.isfile(spec):
                    yield spec
                elif os.path.isdir(spec):
                    for root, dirs, fnames in os.walk(spec):
                        for fn in fnames:
                            yield os.path.join(root, fn)
                else:
                    raise FileError("File not found: %s" % spec)
            elif inspect.isgenerator(spec):
                for f in spec:
                    yield f
            else:
                raise FileError("File iteration item is not supported:"
                                 " %s" % spec.__class__)
<commit_msg>Finder match result does not include the base path.<commit_after>import __builtin__
import os
import glob
import re
import inspect
import gzip
from contextlib import contextmanager
from .uid import generate_string_uid

SPLITEXT_PAT = re.compile("""
    (.*?)           # The file path without the extension
    (               # The extension group
      (\.\w+)+      # The (possibly composite) extension
    )?              # The extension is optional
    $               # Anchor to the end of the file path
    """, re.VERBOSE)
"""
Regexp pattern that splits the name and extension.

:see: :meth:`splitexts`
"""

class FileError(Exception):
    pass

@contextmanager
def open(filename):
    """
    Opens the given file. If the file extension ends in ``.gz``,
    then the content is uncompressed.

    :param filename: the file path
    :return: the file input stream
    :raise: IOError if the file cannot be read
    """
    _, ext = os.path.splitext(filename)
    # The gzip or normal file open context function.
    if ext == '.gz':
        context = gzip.open
    else:
        context = __builtin__.open

    # Open the file.
    with context(filename) as fp:
        yield fp

def splitexts(location):
    """
    Splits the given file path into a name and extension.
    Unlike ``os.path.splitext``, the resulting extension can be composite.

    Example:

    >>> import os
    >>> os.path.splitext('/tmp/foo.nii.gz')
    ('/tmp/foo.nii', '.gz')
    >>> from qiutil.file import splitexts
    >>> splitexts('/tmp/foo.3/bar.nii.gz')
    ('/tmp/foo.3/bar', '.nii.gz')

    :param location: the file path
    :return: the *(prefix, extensions)* tuple
    """
    matches = SPLITEXT_PAT.match(location).groups()[:2]
    # Pad with an empty extension, if necessary.
    matches += (None,) * (2 - len(matches))

    return tuple(matches)

def splitboth(location):
    """
    Splits the given file path into a directory, name and extension.
    Unlike ``os.path.splitext``, the resulting extension can be
    composite.

    Example:

    >>> import os
    >>> from qiutil.file import splitall
    >>> splitall('/tmp/foo.nii.gz')
    ('/tmp', 'foo', '.nii.gz')

    :param location: the file path
    :return: the *(directory, prefix, extensions)* tuple
    """
    prefix, exts = splitexts(location)
    dir_path, base = os.path.split(prefix)
    if dir_path == '':
        dir_path = None

    return (dir_path, base, exts)

def generate_file_name(ext=None):
    """
    Makes a valid file name which is unique to within one microsecond of calling
    this function. The file name is ten characters long without the extension.

    :param ext: the optional file extension, with leading period delimiter
    :return: the file name
    """
    fname = generate_string_uid()
    if ext:
        return fname + ext
    else:
        return fname

class Finder(object):
    """
    Finder matches a file name glob pattern and regular expression.
    """

    def __init__(self, glob='*', regex='.*'):
        """
        :param glob: the glob pattern string
        :param regex: the :class:`RegExp` object or pattern string
        """
        self.glob = glob or '*'
        """The glob pattern string (default ``*``)."""

        if isinstance(regex, str):
            regex = re.compile(regex)
        self.regex = regex or '.*'
        """The file match regular expression (default ``.*``)."""

    def find(self, base_dir=None):
        """
        Iterates over the files which match both the :attr:`glob` and the
        :attr:`regex`. Each iteration result is an absolute file path.

        :param: the parent base directory path (default current directory)
        :yield: the next matching absolute file path
        """
        if not base_dir:
            base_dir = os.getcwd()
        abs_dir = os.path.abspath(base_dir)
        for match in self.match(base_dir):
            yield os.path.join(abs_dir, match.group(0))

    def match(self, base_dir=None):
        """
        Iterates over the files which match both the :attr:`glob` and the
        :attr:`regex`. The match result does not include the base
        directory.

        :param: the parent base directory path (default current directory)
        :yield: the next match
        """
        if not base_dir:
            base_dir = os.getcwd()
        # The primary glob match.
        files = glob.iglob('/'.join((base_dir, self.glob)))
        # Apply the secondary regex filter.
        prefix_len = len(base_dir) + 1
        for location in files:
            # Chop off the base directory prefix.
            rel_path = location[prefix_len:]
            # Match on the rest of the file path.
            match = self.regex.match(rel_path)
            if match:
                yield match

class FileIterator(object):
    """
    FileIterator is a generator class which iterates over the files contained
    recursively in the initializer *filespecs* parameters.
    """

    def __init__(self, *filespecs):
        """
        :param filespecs: the files, directories or file generators over which
            to iterate
        """
        self._filespecs = filespecs

    def __iter__(self):
        """
        Iterates over the files as follows:

        - If the current file specification is a file object, then yield that
          file object.

        - If the current file specification is a non-directory file path,
          then yield that file path.

        - If the current file specification is a directory, then yield each file
          contained recursively in that directory.

        - If the current file specification is a generator, then yield each
          generated item

        :yield: the next file object or path
        :raise FileError: if an iterated file path is neither a directory nor file
        :raise FileError: if an iterated item is not a file object, path
            or generator
        """
        for spec in self._filespecs:
            if isinstance(spec, file):
                yield spec
            elif isinstance(spec, str):
                if os.path.isfile(spec):
                    yield spec
                elif os.path.isdir(spec):
                    for root, dirs, fnames in os.walk(spec):
                        for fn in fnames:
                            yield os.path.join(root, fn)
                else:
                    raise FileError("File not found: %s" % spec)
            elif inspect.isgenerator(spec):
                for f in spec:
                    yield f
            else:
                raise FileError("File iteration item is not supported:"
                                 " %s" % spec.__class__)
<|endoftext|>


<commit_before>#
# growler_sass/__meta__.py
#
"""
Metadata file for the growler-sass package.
"""

version_info = (0, 1, 0, 'dev0')
version = '.'.join(map(str, version_info))

date = 'Sep 29, 2016'
author = 'Andrew Kubera'
author_email = 'andrewkubera@gmail.com'
license = 'MIT'
url = 'https://github.com/pygrowler/growler-sass'
<commit_msg>Begin version 0.2.0 development.<commit_after>#
# growler_sass/__meta__.py
#
"""
Metadata file for the growler-sass package.
"""

version_info = (0, 2, 0, 'dev0')
version = '.'.join(map(str, version_info))

date = 'Oct 01, 2016'
author = 'Andrew Kubera'
author_email = 'andrewkubera@gmail.com'
license = 'MIT'
url = 'https://github.com/pygrowler/growler-sass'
<|endoftext|>


<commit_before># This file is part of Indico.
# Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Indico 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

import csv
import re
from io import BytesIO

from markupsafe import Markup
from speaklater import is_lazy_string
from xlsxwriter import Workbook

from indico.web.flask.util import send_file

def unique_col(name, id_):
    """Ensure uniqueness of a header/data entry.

    Simply apply this to both the entry in `headers` and the
    dict keys in `rows` before passing them to one of the spreadsheet
    functions.

    :param name: The actual column name/title
    :param id_: The id or whatever is needed to ensure uniqueness
    """
    return name, id_

def _prepare_header(header):
    if isinstance(header, tuple):
        header = header[0]
    return header.encode('utf-8')

def _prepare_csv_data(data, _linebreak_re=re.compile(r'(\r?\n)+')):
    if isinstance(data, (list, tuple)):
        data = ', '.join(data).encode('utf-8')
    elif isinstance(data, set):
        data = ', '.join(sorted(data, key=unicode.lower)).encode('utf-8')
    elif isinstance(data, bool):
        data = b'Yes' if data else b'No'
    elif data is None:
        data = b''
    return _linebreak_re.sub('    ', unicode(data)).encode('utf-8')

def generate_csv(headers, rows):
    """Generates a CSV file from a list of headers and rows.

    While CSV cells may contain multiline data, we replace linebreaks
    with spaces in case someone wants to use it in Excel which does
    *not* handle such cells properly...

    :param headers: a list of cell captions
    :param rows: a list of dicts mapping captions to values
    :return: an `io.BytesIO` containing the CSV data
    """
    buf = BytesIO()
    writer = csv.writer(buf)
    writer.writerow(map(_prepare_header, headers))
    header_positions = {name: i for i, name in enumerate(headers)}
    for row in rows:
        row = sorted(row.items(), key=lambda x: header_positions[x[0]])
        writer.writerow([_prepare_csv_data(v) for k, v in row])
    buf.seek(0)
    return buf

def _prepare_excel_data(data):
    if isinstance(data, (list, tuple)):
        data = ', '.join(data)
    elif isinstance(data, set):
        data = ', '.join(sorted(data, key=unicode.lower))
    elif is_lazy_string(data) or isinstance(data, Markup):
        data = unicode(data)
    return data

def generate_xlsx(headers, rows):
    """Generates an XLSX file from a list of headers and rows.

    :param headers: a list of cell captions
    :param rows: a list of dicts mapping captions to values
    :return: an `io.BytesIO` containing the XLSX data
    """
    workbook_options = {'in_memory': True, 'strings_to_formulas': False, 'strings_to_numbers': False,
                        'strings_to_urls': False}
    buf = BytesIO()
    header_positions = {name: i for i, name in enumerate(headers)}
    # convert row dicts to lists
    rows = [[x[1] for x in sorted(row.items(), key=lambda x: header_positions[x[0]])] for row in rows]
    assert all(len(row) == len(headers) for row in rows)
    with Workbook(buf, workbook_options) as workbook:
        bold = workbook.add_format({'bold': True})
        sheet = workbook.add_worksheet()
        for col, name in enumerate(map(_prepare_header, headers)):
            sheet.write(0, col, name, bold)
        for row, values in enumerate(rows, 1):
            sheet.write_row(row, 0, map(_prepare_excel_data, values))
    buf.seek(0)
    return buf

def send_csv(filename, headers, rows):
    """Sends a CSV file to the client

    :param filename: The name of the CSV file
    :param headers: a list of cell captions
    :param rows: a list of dicts mapping captions to values
    :return: a flask response containing the CSV data
    """
    buf = generate_csv(headers, rows)
    return send_file(filename, buf, 'text/csv', inline=False)

def send_xlsx(filename, headers, rows):
    """Sends an XLSX file to the client

    :param filename: The name of the CSV file
    :param headers: a list of cell captions
    :param rows: a list of dicts mapping captions to values
    :return: a flask response containing the XLSX data
    """
    buf = generate_xlsx(headers, rows)
    return send_file(filename, buf, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', inline=False)
<commit_msg>Fix xls generation (needs unicode headers)<commit_after># This file is part of Indico.
# Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Indico 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

import csv
import re
from functools import partial
from io import BytesIO

from markupsafe import Markup
from speaklater import is_lazy_string
from xlsxwriter import Workbook

from indico.web.flask.util import send_file

def unique_col(name, id_):
    """Ensure uniqueness of a header/data entry.

    Simply apply this to both the entry in `headers` and the
    dict keys in `rows` before passing them to one of the spreadsheet
    functions.

    :param name: The actual column name/title
    :param id_: The id or whatever is needed to ensure uniqueness
    """
    return name, id_

def _prepare_header(header, as_unicode=True):
    if isinstance(header, tuple):
        header = header[0]
    return header if as_unicode else header.encode('utf-8')

_prepare_header_utf8 = partial(_prepare_header, as_unicode=False)

def _prepare_csv_data(data, _linebreak_re=re.compile(r'(\r?\n)+')):
    if isinstance(data, (list, tuple)):
        data = ', '.join(data).encode('utf-8')
    elif isinstance(data, set):
        data = ', '.join(sorted(data, key=unicode.lower)).encode('utf-8')
    elif isinstance(data, bool):
        data = b'Yes' if data else b'No'
    elif data is None:
        data = b''
    return _linebreak_re.sub('    ', unicode(data)).encode('utf-8')

def generate_csv(headers, rows):
    """Generates a CSV file from a list of headers and rows.

    While CSV cells may contain multiline data, we replace linebreaks
    with spaces in case someone wants to use it in Excel which does
    *not* handle such cells properly...

    :param headers: a list of cell captions
    :param rows: a list of dicts mapping captions to values
    :return: an `io.BytesIO` containing the CSV data
    """
    buf = BytesIO()
    writer = csv.writer(buf)
    writer.writerow(map(_prepare_header_utf8, headers))
    header_positions = {name: i for i, name in enumerate(headers)}
    for row in rows:
        row = sorted(row.items(), key=lambda x: header_positions[x[0]])
        writer.writerow([_prepare_csv_data(v) for k, v in row])
    buf.seek(0)
    return buf

def _prepare_excel_data(data):
    if isinstance(data, (list, tuple)):
        data = ', '.join(data)
    elif isinstance(data, set):
        data = ', '.join(sorted(data, key=unicode.lower))
    elif is_lazy_string(data) or isinstance(data, Markup):
        data = unicode(data)
    return data

def generate_xlsx(headers, rows):
    """Generates an XLSX file from a list of headers and rows.

    :param headers: a list of cell captions
    :param rows: a list of dicts mapping captions to values
    :return: an `io.BytesIO` containing the XLSX data
    """
    workbook_options = {'in_memory': True, 'strings_to_formulas': False, 'strings_to_numbers': False,
                        'strings_to_urls': False}
    buf = BytesIO()
    header_positions = {name: i for i, name in enumerate(headers)}
    # convert row dicts to lists
    rows = [[x[1] for x in sorted(row.items(), key=lambda x: header_positions[x[0]])] for row in rows]
    assert all(len(row) == len(headers) for row in rows)
    with Workbook(buf, workbook_options) as workbook:
        bold = workbook.add_format({'bold': True})
        sheet = workbook.add_worksheet()
        for col, name in enumerate(map(_prepare_header, headers)):
            sheet.write(0, col, name, bold)
        for row, values in enumerate(rows, 1):
            sheet.write_row(row, 0, map(_prepare_excel_data, values))
    buf.seek(0)
    return buf

def send_csv(filename, headers, rows):
    """Sends a CSV file to the client

    :param filename: The name of the CSV file
    :param headers: a list of cell captions
    :param rows: a list of dicts mapping captions to values
    :return: a flask response containing the CSV data
    """
    buf = generate_csv(headers, rows)
    return send_file(filename, buf, 'text/csv', inline=False)

def send_xlsx(filename, headers, rows):
    """Sends an XLSX file to the client

    :param filename: The name of the CSV file
    :param headers: a list of cell captions
    :param rows: a list of dicts mapping captions to values
    :return: a flask response containing the XLSX data
    """
    buf = generate_xlsx(headers, rows)
    return send_file(filename, buf, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', inline=False)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
__author__ = "Roman Chernikov, Konstantin Klementiev"
__date__ = "01 Nov 2017"

#try:
#    from matplotlib.backends import qt_compat
#except ImportError:
#    from matplotlib.backends import qt4_compat
#    qt_compat = qt4_compat

QtName = None
try:
    import PyQt5
    QtName = "PyQt5"
except ImportError:
    try:
        import PyQt4
        QtName = "PyQt4"
    except ImportError:
        raise ImportError("Cannot import any PyQt package!")

starImport = False

#if 'pyqt4' in qt_compat.QT_API.lower():  # also 'PyQt4v2'
if QtName == "PyQt4":
    from PyQt4 import QtGui, QtCore
    import PyQt4.QtGui as myQtGUI

    if starImport:
        from PyQt4.QtGui import *
        from PyQt4.QtCore import *
    else:
        from PyQt4.QtCore import (
            pyqtSignal, SIGNAL, QUrl, QObject, QTimer, QProcess,
            QThread, QT_VERSION_STR, PYQT_VERSION_STR)
        from PyQt4.QtGui import QSortFilterProxyModel
        try:
            from PyQt4.QtCore import Signal
        except ImportError:
            from PyQt4.QtCore import pyqtSignal as Signal
    locals().update(vars(PyQt4.QtCore.Qt))

    from PyQt4.QtOpenGL import QGLWidget
    import PyQt4.QtWebKit as QtWeb
    try:
        import PyQt4.Qwt5 as Qwt
    except:  # analysis:ignore
        pass
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as\
        FigCanvas
#elif 'pyqt5' in qt_compat.QT_API.lower():
elif QtName == "PyQt5":
    from PyQt5 import QtGui, QtCore
    import PyQt5.QtWidgets as myQtGUI

    if starImport:
        from PyQt5.QtGui import *
        from PyQt5.QtCore import *
        from PyQt5.QtWidgets import *
        Signal = pyqtSignal
    else:
        from PyQt5.QtCore import (
            pyqtSignal, QUrl, QObject, QTimer, QProcess, QThread,
            QT_VERSION_STR, PYQT_VERSION_STR, QSortFilterProxyModel)
        try:
            from PyQt5.QtCore import Signal
        except ImportError:
            from PyQt5.QtCore import pyqtSignal as Signal
    locals().update(vars(PyQt5.QtCore.Qt))

    from PyQt5.QtOpenGL import QGLWidget
    try:
        import PyQt5.QtWebEngineWidgets as QtWeb
    except ImportError:
        import PyQt5.QtWebKitWidgets as QtWeb
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as\
        FigCanvas
else:
    raise ImportError("Cannot import any Python Qt package!")

QWidget, QApplication, QAction, QTabWidget, QToolBar, QStatusBar, QTreeView,\
    QShortcut, QAbstractItemView, QHBoxLayout, QVBoxLayout, QSplitter,\
    QComboBox, QMenu, QListWidget, QTextEdit, QMessageBox, QFileDialog,\
    QListWidgetItem, QGroupBox, QProgressBar, QLabel, QSizePolicy,\
    QLineEdit, QCheckBox, QSpinBox, QSlider, QToolButton = (
        myQtGUI.QWidget, myQtGUI.QApplication, myQtGUI.QAction,
        myQtGUI.QTabWidget, myQtGUI.QToolBar, myQtGUI.QStatusBar,
        myQtGUI.QTreeView, myQtGUI.QShortcut, myQtGUI.QAbstractItemView,
        myQtGUI.QHBoxLayout, myQtGUI.QVBoxLayout, myQtGUI.QSplitter,
        myQtGUI.QComboBox, myQtGUI.QMenu, myQtGUI.QListWidget,
        myQtGUI.QTextEdit, myQtGUI.QMessageBox, myQtGUI.QFileDialog,
        myQtGUI.QListWidgetItem, myQtGUI.QGroupBox, myQtGUI.QProgressBar,
        myQtGUI.QLabel, myQtGUI.QSizePolicy,
        myQtGUI.QLineEdit, myQtGUI.QCheckBox, myQtGUI.QSpinBox,
        myQtGUI.QSlider, myQtGUI.QToolButton)
QIcon, QFont, QKeySequence, QStandardItemModel, QStandardItem, QPixmap,\
    QDoubleValidator, QIntValidator =\
    (QtGui.QIcon, QtGui.QFont, QtGui.QKeySequence, QtGui.QStandardItemModel,
     QtGui.QStandardItem, QtGui.QPixmap, QtGui.QDoubleValidator,
     QtGui.QIntValidator)

class mySlider(QSlider):
    def __init__(self, parent, scaleDirection, scalePosition):
        super(mySlider, self).__init__(scaleDirection)
        self.setTickPosition(scalePosition)
        self.scale = 1.

    def setRange(self, start, end, step):
        self.scale = 1. / step
        QSlider.setRange(self, start / step, end / step)

    def setValue(self, value):
        QSlider.setValue(self, int(value*self.scale))

try:
    glowSlider = Qwt.QwtSlider
    glowTopScale = Qwt.QwtSlider.TopScale
except:  # analysis:ignore
    glowSlider = mySlider
    glowTopScale = QSlider.TicksAbove
<commit_msg>corrected starImport condition<commit_after># -*- coding: utf-8 -*-
__author__ = "Roman Chernikov, Konstantin Klementiev"
__date__ = "01 Nov 2017"

#try:
#    from matplotlib.backends import qt_compat
#except ImportError:
#    from matplotlib.backends import qt4_compat
#    qt_compat = qt4_compat

QtName = None
try:
    import PyQt5
    QtName = "PyQt5"
except ImportError:
    try:
        import PyQt4
        QtName = "PyQt4"
    except ImportError:
        raise ImportError("Cannot import any PyQt package!")

starImport = False  # star import doesn't work with mock import needed for rtfd

#if 'pyqt4' in qt_compat.QT_API.lower():  # also 'PyQt4v2'
if QtName == "PyQt4":
    from PyQt4 import QtGui, QtCore
    import PyQt4.QtGui as myQtGUI

    if starImport:
        from PyQt4.QtGui import *
        from PyQt4.QtCore import *
    else:
        from PyQt4.QtCore import (
            pyqtSignal, SIGNAL, QUrl, QObject, QTimer, QProcess,
            QThread, QT_VERSION_STR, PYQT_VERSION_STR)
        from PyQt4.QtGui import QSortFilterProxyModel
        try:
            from PyQt4.QtCore import Signal
        except ImportError:
            from PyQt4.QtCore import pyqtSignal as Signal
    locals().update(vars(PyQt4.QtCore.Qt))

    from PyQt4.QtOpenGL import QGLWidget
    import PyQt4.QtWebKit as QtWeb
    try:
        import PyQt4.Qwt5 as Qwt
    except:  # analysis:ignore
        pass
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as\
        FigCanvas
#elif 'pyqt5' in qt_compat.QT_API.lower():
elif QtName == "PyQt5":
    from PyQt5 import QtGui, QtCore
    import PyQt5.QtWidgets as myQtGUI

    if starImport:
        from PyQt5.QtGui import *
        from PyQt5.QtCore import *
        from PyQt5.QtWidgets import *
        Signal = pyqtSignal
    else:
        from PyQt5.QtCore import (
            pyqtSignal, QUrl, QObject, QTimer, QProcess, QThread,
            QT_VERSION_STR, PYQT_VERSION_STR, QSortFilterProxyModel)
        try:
            from PyQt5.QtCore import Signal
        except ImportError:
            from PyQt5.QtCore import pyqtSignal as Signal
    locals().update(vars(PyQt5.QtCore.Qt))

    from PyQt5.QtOpenGL import QGLWidget
    try:
        import PyQt5.QtWebEngineWidgets as QtWeb
    except ImportError:
        import PyQt5.QtWebKitWidgets as QtWeb
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as\
        FigCanvas
else:
    raise ImportError("Cannot import any Python Qt package!")

if not starImport:
    (QWidget, QApplication, QAction, QTabWidget, QToolBar, QStatusBar,
     QTreeView, QShortcut, QAbstractItemView, QHBoxLayout, QVBoxLayout,
     QSplitter, QComboBox, QMenu, QListWidget, QTextEdit, QMessageBox,
     QFileDialog, QListWidgetItem, QGroupBox, QProgressBar, QLabel,
     QSizePolicy, QLineEdit, QCheckBox, QSpinBox, QSlider, QToolButton) = (
        myQtGUI.QWidget, myQtGUI.QApplication, myQtGUI.QAction,
        myQtGUI.QTabWidget, myQtGUI.QToolBar, myQtGUI.QStatusBar,
        myQtGUI.QTreeView, myQtGUI.QShortcut, myQtGUI.QAbstractItemView,
        myQtGUI.QHBoxLayout, myQtGUI.QVBoxLayout, myQtGUI.QSplitter,
        myQtGUI.QComboBox, myQtGUI.QMenu, myQtGUI.QListWidget,
        myQtGUI.QTextEdit, myQtGUI.QMessageBox, myQtGUI.QFileDialog,
        myQtGUI.QListWidgetItem, myQtGUI.QGroupBox, myQtGUI.QProgressBar,
        myQtGUI.QLabel, myQtGUI.QSizePolicy,
        myQtGUI.QLineEdit, myQtGUI.QCheckBox, myQtGUI.QSpinBox,
        myQtGUI.QSlider, myQtGUI.QToolButton)
    (QIcon, QFont, QKeySequence, QStandardItemModel, QStandardItem, QPixmap,
     QDoubleValidator, QIntValidator) = (
        QtGui.QIcon, QtGui.QFont, QtGui.QKeySequence, QtGui.QStandardItemModel,
        QtGui.QStandardItem, QtGui.QPixmap, QtGui.QDoubleValidator,
        QtGui.QIntValidator)

class mySlider(QSlider):
    def __init__(self, parent, scaleDirection, scalePosition):
        super(mySlider, self).__init__(scaleDirection)
        self.setTickPosition(scalePosition)
        self.scale = 1.

    def setRange(self, start, end, step):
        self.scale = 1. / step
        QSlider.setRange(self, start / step, end / step)

    def setValue(self, value):
        QSlider.setValue(self, int(value*self.scale))

try:
    glowSlider = Qwt.QwtSlider
    glowTopScale = Qwt.QwtSlider.TopScale
except:  # analysis:ignore
    glowSlider = mySlider
    glowTopScale = QSlider.TicksAbove
<|endoftext|>


<commit_before>from IRCMessage import IRCMessage
from IRCResponse import IRCResponse, ResponseType
from Function import Function
import GlobalVars

import string
import pickle
import re

class Instantiate(Function):
	Help = "hugs [nick] -- How many hugs has this person given and received?"

	def GetResponse(self, message):
		if message.Type == "ACTION":
			filename = "hugs/hugs.pkl"
			pkl_file = open(filename, "rb")
			hug_dict = pickle.load(pkl_file)
			pkl_file.close()
			commonWords = ["and", "of", "all", "to", "the", "both", "back", "again", "any", "one", "<3", "with"]
			pattern = "hug|cuddle|snuggle|snug|squeeze|glomp"
			match = re.search(pattern, message.MessageList[0] , re.IGNORECASE)
			if match:
				receivers = []
				for nick in message.MessageList[1:]:
					if string.lower(nick) not in commonWords:
						nick = string.rstrip(nick, "\x01")
						nick = string.rstrip(nick, ".")
						nick = string.rstrip(nick, "!")
						nick = string.rstrip(nick, ",")
						nick = string.lower(nick)
						receivers.append(nick)
				for index in range(0, len(receivers)):
					giver = message.User.Name
					receiver = receivers[index]
					if giver not in hug_dict:
						hug_dict[giver] = [1,0]
					else:
						hug_dict[giver] = list(hug_dict[giver])
						hug_dict[giver][0] += 1
					if receiver not in hug_dict:
						hug_dict[receiver] = [0,1]
					else:
						hug_dict[receiver] = list(hug_dict[receiver])
						hug_dict[receiver][1] += 1
				output = open(filename, "wb")
				pickle.dump(hug_dict, output)
				output.close()

		elif message.Type == "PRIVMSG":
			if message.Command == "hugs":
				filename = "hugs/hugs.pkl"
				pkl_file = open(filename, "rb")
				hug_dict = pickle.load(pkl_file)
				pkl_file.close()
				if len(message.ParameterList) == 0:
					target = message.User.Name
				else:
					target = message.ParameterList[0]

				hugData = [0,0]
				matches = []
				for (user, hugCounts) in hug_dict.items():
					try:
						match = re.search(target, user, re.IGNORECASE)
					except:
						match = False
					if match:
						matches.append(match.string)
						hugData[0] += hugCounts[0]
						hugData[1] += hugCounts[1]

				HugString = target + " has received " + str(hugData[1]) + " hugs and given " + str(hugData[0]) + " hugs."
				matchedNicksString = "Matches found: "
				numberOfMatches = 0
				for name in matches:
					if (numberOfMatches > 9):
						matchedNicksString += "..."
						break
					elif (matches.index(name) == len(matches)-1):
						matchedNicksString += name
						numberOfMatches += 1
					else:
						matchedNicksString = matchedNicksString + name + ", "
						numberOfMatches += 1
				returnString = matchedNicksString + "\n" + HugString
				return IRCResponse(ResponseType.Say, returnString, message.ReplyTo)<commit_msg>Better regex for more hugtracking accuracy<commit_after>from IRCMessage import IRCMessage
from IRCResponse import IRCResponse, ResponseType
from Function import Function
import GlobalVars

import string
import pickle
import re

class Instantiate(Function):
	Help = "hugs [nick] -- How many hugs has this person given and received?"

	def GetResponse(self, message):
		if message.Type == "ACTION":
			filename = "hugs/hugs.pkl"
			pkl_file = open(filename, "rb")
			hug_dict = pickle.load(pkl_file)
			pkl_file.close()
			commonWords = ["and", "of", "all", "to", "the", "both", "back", "again", "any", "one", "<3", "with"]
			pattern = "hu+g|cuddle|snu+ggle|snu+g|squeeze|glomp"
			match = re.search(pattern, message.MessageList[0] , re.IGNORECASE)
			if match:
				receivers = []
				for nick in message.MessageList[1:]:
					if string.lower(nick) not in commonWords:
						nick = string.rstrip(nick, "\x01")
						nick = string.rstrip(nick, ".")
						nick = string.rstrip(nick, "!")
						nick = string.rstrip(nick, ",")
						nick = string.lower(nick)
						receivers.append(nick)
				for index in range(0, len(receivers)):
					giver = message.User.Name
					receiver = receivers[index]
					if giver not in hug_dict:
						hug_dict[giver] = [1,0]
					else:
						hug_dict[giver] = list(hug_dict[giver])
						hug_dict[giver][0] += 1
					if receiver not in hug_dict:
						hug_dict[receiver] = [0,1]
					else:
						hug_dict[receiver] = list(hug_dict[receiver])
						hug_dict[receiver][1] += 1
				output = open(filename, "wb")
				pickle.dump(hug_dict, output)
				output.close()

		elif message.Type == "PRIVMSG":
			if message.Command == "hugs":
				filename = "hugs/hugs.pkl"
				pkl_file = open(filename, "rb")
				hug_dict = pickle.load(pkl_file)
				pkl_file.close()
				if len(message.ParameterList) == 0:
					target = message.User.Name
				else:
					target = message.ParameterList[0]

				hugData = [0,0]
				matches = []
				for (user, hugCounts) in hug_dict.items():
					try:
						match = re.search(target, user, re.IGNORECASE)
					except:
						match = False
					if match:
						matches.append(match.string)
						hugData[0] += hugCounts[0]
						hugData[1] += hugCounts[1]

				HugString = target + " has received " + str(hugData[1]) + " hugs and given " + str(hugData[0]) + " hugs."
				matchedNicksString = "Matches found: "
				numberOfMatches = 0
				for name in matches:
					if (numberOfMatches > 9):
						matchedNicksString += "..."
						break
					elif (matches.index(name) == len(matches)-1):
						matchedNicksString += name
						numberOfMatches += 1
					else:
						matchedNicksString = matchedNicksString + name + ", "
						numberOfMatches += 1
				returnString = matchedNicksString + "\n" + HugString
				return IRCResponse(ResponseType.Say, returnString, message.ReplyTo)<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# © 2016 Daniel Reis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
    'name': 'Improved Name Search',
    'summary': 'Friendlier search when typing in relation fields',
    'version': '8.0.1.0.0',
    'category': 'Uncategorized',
    'website': 'https://odoo-community.org/',
    'author': 'Daniel Reis, Odoo Community Association (OCA)',
    'license': 'AGPL-3',
    'data': [
        'views/ir_model.xml',
    ],
    'installable': True,
    'depends': [
        'base',
    ],
}
<commit_msg>Bump version<commit_after># -*- coding: utf-8 -*-
# © 2016 Daniel Reis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
    'name': 'Improved Name Search',
    'summary': 'Friendlier search when typing in relation fields',
    'version': '8.0.1.0.1',
    'category': 'Uncategorized',
    'website': 'https://odoo-community.org/',
    'author': 'Daniel Reis, Odoo Community Association (OCA)',
    'license': 'AGPL-3',
    'data': [
        'views/ir_model.xml',
    ],
    'installable': True,
    'depends': [
        'base',
    ],
}
<|endoftext|>