<commit_before>import socket
from functools import reduce
from directions.models import Issledovaniya
from laboratory.settings import DICOM_SEARCH_TAGS, DICOM_SERVER, DICOM_PORT, DICOM_ADDRESS, DICOM_SERVER_DELETE, ACSN_MODE, REMOTE_DICOM_SERVER, REMOTE_DICOM_PEER, RMIS_PROXY
import requests
import simplejson as json

def sum(x, y):
    return int(x) + int(y)

def check_sum_ean13(num):
    evensum = reduce(sum, num[-2::-2])
    oddsum = reduce(sum, num[-1::-2])
    return (10 - ((evensum + oddsum * 3) % 10)) % 10

def check_server_port(address, port):
    TCP_IP = address or '127.0.0.1'
    TCP_PORT = port or 4242
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(0.2)
    try:
        s.connect((TCP_IP, TCP_PORT))
    except socket.error:
        available = False
    else:
        available = True
    finally:
        s.close()

    return available

def search_dicom_study(direction=None):
    if direction:
        research_obj = Issledovaniya.objects.filter(napravleniye__pk=direction).first()
        if not research_obj.research.podrazdeleniye or not research_obj.research.podrazdeleniye.can_has_pacs:
            return ''
        dicom_study = Issledovaniya.objects.values('study_instance_uid').filter(napravleniye=direction).first()
        if dicom_study and dicom_study['study_instance_uid']:
            return f'{DICOM_SERVER}/osimis-viewer/app/index.html?study={dicom_study["study_instance_uid"]}'
        else:
            if not check_server_port(DICOM_ADDRESS, DICOM_PORT):
                return ''
            try:
                str_dir = str(direction)
                ean13_dir = str(direction + 460000000000)
                check_sum = check_sum_ean13(ean13_dir)
                ean13_dir = f'{ean13_dir}{check_sum}'

                dicom_study_link = find_image_firstly([ean13_dir, str_dir])
                if ACSN_MODE:
                    acsn = Issledovaniya.objects.values('acsn_id').filter(napravleniye=direction).first()
                    dicom_study_link = change_acsn(dicom_study_link, acsn['acsn_id'])

                if dicom_study_link:
                    Issledovaniya.objects.filter(napravleniye=direction).update(study_instance_uid=dicom_study_link)
                    return f'{DICOM_SERVER}/osimis-viewer/app/index.html?study={dicom_study_link}'

            except Exception as e:
                print(e)  # noqa: T001
    return ''

def find_image_firstly(data_direction):
    for tag in DICOM_SEARCH_TAGS:
        for dir in data_direction:
            data = {'Level': 'Study', 'Query': {tag: dir}}
            dicom_study = requests.post(f'{DICOM_SERVER}/tools/find', data=json.dumps(data))
            if len(dicom_study.json()) > 0:
                return dicom_study.json()[0]
    return None

def change_acsn(link_study, accession_number):
    data_replace = {"Replace": {"AccessionNumber": accession_number}}
    dicom_study = requests.post(f'{DICOM_SERVER}/studies/{link_study}/modify', data=json.dumps(data_replace))
    if dicom_study and dicom_study.json()['ID']:
        requests.delete(f'{DICOM_SERVER_DELETE}/studies/{link_study}')
        link_study = dicom_study.json()['ID']
    if REMOTE_DICOM_SERVER:
        requests.post(f'{REMOTE_DICOM_SERVER}/peers/{REMOTE_DICOM_PEER}/store', data=link_study)

    return link_study
<commit_msg>add proxy<commit_after>import socket
from functools import reduce
from directions.models import Issledovaniya
from laboratory.settings import DICOM_SEARCH_TAGS, DICOM_SERVER, DICOM_PORT, DICOM_ADDRESS, DICOM_SERVER_DELETE, ACSN_MODE, REMOTE_DICOM_SERVER, REMOTE_DICOM_PEER
import requests
import simplejson as json

def sum(x, y):
    return int(x) + int(y)

def check_sum_ean13(num):
    evensum = reduce(sum, num[-2::-2])
    oddsum = reduce(sum, num[-1::-2])
    return (10 - ((evensum + oddsum * 3) % 10)) % 10

def check_server_port(address, port):
    TCP_IP = address or '127.0.0.1'
    TCP_PORT = port or 4242
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(0.2)
    try:
        s.connect((TCP_IP, TCP_PORT))
    except socket.error:
        available = False
    else:
        available = True
    finally:
        s.close()

    return available

def search_dicom_study(direction=None):
    if direction:
        research_obj = Issledovaniya.objects.filter(napravleniye__pk=direction).first()
        if not research_obj.research.podrazdeleniye or not research_obj.research.podrazdeleniye.can_has_pacs:
            return ''
        dicom_study = Issledovaniya.objects.values('study_instance_uid').filter(napravleniye=direction).first()
        if dicom_study and dicom_study['study_instance_uid']:
            return f'{DICOM_SERVER}/osimis-viewer/app/index.html?study={dicom_study["study_instance_uid"]}'
        else:
            if not check_server_port(DICOM_ADDRESS, DICOM_PORT):
                return ''
            try:
                str_dir = str(direction)
                ean13_dir = str(direction + 460000000000)
                check_sum = check_sum_ean13(ean13_dir)
                ean13_dir = f'{ean13_dir}{check_sum}'

                dicom_study_link = find_image_firstly([ean13_dir, str_dir])
                if ACSN_MODE:
                    acsn = Issledovaniya.objects.values('acsn_id').filter(napravleniye=direction).first()
                    dicom_study_link = change_acsn(dicom_study_link, acsn['acsn_id'])

                if dicom_study_link:
                    Issledovaniya.objects.filter(napravleniye=direction).update(study_instance_uid=dicom_study_link)
                    return f'{DICOM_SERVER}/osimis-viewer/app/index.html?study={dicom_study_link}'

            except Exception as e:
                print(e)  # noqa: T001
    return ''

def find_image_firstly(data_direction):
    for tag in DICOM_SEARCH_TAGS:
        for dir in data_direction:
            data = {'Level': 'Study', 'Query': {tag: dir}}
            dicom_study = requests.post(f'{DICOM_SERVER}/tools/find', data=json.dumps(data))
            if len(dicom_study.json()) > 0:
                return dicom_study.json()[0]
    return None

def change_acsn(link_study, accession_number):
    data_replace = {"Replace": {"AccessionNumber": accession_number}}
    dicom_study = requests.post(f'{DICOM_SERVER}/studies/{link_study}/modify', data=json.dumps(data_replace))
    if dicom_study and dicom_study.json()['ID']:
        requests.delete(f'{DICOM_SERVER_DELETE}/studies/{link_study}')
        link_study = dicom_study.json()['ID']
    if REMOTE_DICOM_SERVER:
        requests.post(f'{REMOTE_DICOM_SERVER}/peers/{REMOTE_DICOM_PEER}/store', data=link_study)

    return link_study
<|endoftext|>


<commit_before>"""
______ _____ _____ _____    __
| ___ \  ___/  ___|_   _|  / _|                                           | |
| |_/ / |__ \ `--.  | |   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| |__
|    /|  __| `--. \ | |   |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
| |\ \| |___/\__/ / | |   | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
\_| \_\____/\____/  \_/   |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_|
"""

__title__ = 'Django REST framework'
__version__ = '3.0.3'
__author__ = 'Tom Christie'
__license__ = 'BSD 2-Clause'
__copyright__ = 'Copyright 2011-2015 Tom Christie'

# Version synonym
VERSION = __version__

# Header encoding (see RFC5987)
HTTP_HEADER_ENCODING = 'iso-8859-1'

# Default datetime input and output formats
ISO_8601 = 'iso-8601'
<commit_msg>Bumped the version.<commit_after>"""
______ _____ _____ _____    __
| ___ \  ___/  ___|_   _|  / _|                                           | |
| |_/ / |__ \ `--.  | |   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| |__
|    /|  __| `--. \ | |   |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
| |\ \| |___/\__/ / | |   | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
\_| \_\____/\____/  \_/   |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_|
"""

__title__ = 'Django REST framework'
__version__ = '3.0.4'
__author__ = 'Tom Christie'
__license__ = 'BSD 2-Clause'
__copyright__ = 'Copyright 2011-2015 Tom Christie'

# Version synonym
VERSION = __version__

# Header encoding (see RFC5987)
HTTP_HEADER_ENCODING = 'iso-8859-1'

# Default datetime input and output formats
ISO_8601 = 'iso-8601'
<|endoftext|>


<commit_before>from sql.magic import execute
import sys
import nose
import re

def test_memory_db():
    execute('', 'sqlite:// CREATE TABLE test (n INT, name TEXT)')
    execute('', "sqlite:// INSERT INTO test VALUES (1, 'foo');")
    execute('', "sqlite:// INSERT INTO test VALUES (2, 'bar');")
    assert execute('', "sqlite:// SELECT * FROM test;")[0][0] == 1
    assert execute('', "sqlite:// SELECT * FROM test;")[1]['name'] == 'bar'

def test_html():
    result = execute('', "sqlite:// SELECT * FROM test;")
    assert 'foo	' in result._repr_html_().lower()

def test_print():
    result = execute('', "sqlite:// SELECT * FROM test;")
    assert re.search(r'1\s+\|\s+foo', str(result))

def test_plain_style():
    result = execute('', "sqlite:// SELECT * FROM test;", {'style': 'PLAIN_COLUMNS'})
    assert re.search(r'1\s+foo', str(result))

def test_multi_sql():
    result = execute('', """
        sqlite://
        CREATE TABLE writer (first_name, last_name, year_of_death);
        INSERT INTO writer VALUES ('William', 'Shakespeare', 1616);
        INSERT INTO writer VALUES ('Bertold', 'Brecht', 1956);
        SELECT last_name FROM writer;
        """, {})
    assert 'Shakespeare' in str(result) and 'Brecht' in str(result)<commit_msg>Added test for duplicate column names<commit_after>from sql.magic import execute
import sys
import nose
import re

def test_memory_db():
    execute('', 'sqlite:// CREATE TABLE test (n INT, name TEXT)')
    execute('', "sqlite:// INSERT INTO test VALUES (1, 'foo');")
    execute('', "sqlite:// INSERT INTO test VALUES (2, 'bar');")
    assert execute('', "sqlite:// SELECT * FROM test;")[0][0] == 1
    assert execute('', "sqlite:// SELECT * FROM test;")[1]['name'] == 'bar'

def test_html():
    result = execute('', "sqlite:// SELECT * FROM test;")
    assert 'foo	' in result._repr_html_().lower()

def test_print():
    result = execute('', "sqlite:// SELECT * FROM test;")
    assert re.search(r'1\s+\|\s+foo', str(result))

def test_plain_style():
    result = execute('', "sqlite:// SELECT * FROM test;", {'style': 'PLAIN_COLUMNS'})
    assert re.search(r'1\s+foo', str(result))

def test_multi_sql():
    result = execute('', """
        sqlite://
        CREATE TABLE writer (first_name, last_name, year_of_death);
        INSERT INTO writer VALUES ('William', 'Shakespeare', 1616);
        INSERT INTO writer VALUES ('Bertold', 'Brecht', 1956);
        SELECT last_name FROM writer;
        """, {})
    assert 'Shakespeare' in str(result) and 'Brecht' in str(result)

def test_duplicate_column_names_accepted():
    result = execute('', """
        sqlite://
        SELECT last_name, last_name FROM writer;
        """, {})
    assert (u'Brecht', u'Brecht') in result
<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2012, Luis Alberto Perez Lazaro <luisperlazaro@gmail.com>
# (c) 2015, Jakub Jirutka <jakub@jirutka.cz>
#
# 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: patch
author:
    - "Jakub Jirutka (@jirutka)"
    - "Luis Alberto Perez Lazaro (@luisperlaz)"
version_added: 1.9
description:
    - Apply patch files using the GNU patch tool.
short_description: Apply patch files using the GNU patch tool.
options:
  basedir:
    description:
      - Path of a base directory in which the patch file will be applied.
        May be ommitted when C(dest) option is specified, otherwise required.
    required: false
  dest:
    description:
      - Path of the file on the remote machine to be patched.
      - The names of the files to be patched are usually taken from the patch
        file, but if there's just one file to be patched it can specified with
        this option.
    required: false
    aliases: [ "originalfile" ]
  src:
    description:
      - Path of the patch file as accepted by the GNU patch tool. If
        C(remote_src) is 'no', the patch source file is looked up from the
        module's "files" directory.
    required: true
    aliases: [ "patchfile" ]
  remote_src:
    description:
      - If C(no), it will search for src at originating/master machine, if C(yes) it will
        go to the remote/target machine for the src. Default is C(no).
    choices: [ "yes", "no" ]
    required: false
    default: "no"
  strip:
    description:
      - Number that indicates the smallest prefix containing leading slashes
        that will be stripped from each file name found in the patch file.
        For more information see the strip parameter of the GNU patch tool.
    required: false
    type: "int"
    default: "0"
  backup:
    version_added: "2.0"
    description:
      - passes --backup --version-control=numbered to patch,
        producing numbered backup copies
    choices: [ 'yes', 'no' ]
    default: 'no'
  binary:
    version_added: "2.0"
    description:
      - Setting to C(yes) will disable patch's heuristic for transforming CRLF
        line endings into LF. Line endings of src and dest must match. If set to
        C(no), patch will replace CRLF in src files on POSIX.
    required: false
    type: "bool"
    default: "no"
note:
  - This module requires GNU I(patch) utility to be installed on the remote host.
'''

EXAMPLES = '''
- name: apply patch to one file
  patch: >
    src=/tmp/index.html.patch
    dest=/var/www/index.html

- name: apply patch to multiple files under basedir
  patch: >
    src=/tmp/customize.patch
    basedir=/var/www
    strip=1
'''

import os
from os import path, R_OK, W_OK

class PatchError(Exception):
    pass

def is_already_applied(patch_func, patch_file, basedir, dest_file=None, binary=False, strip=0):
    opts = ['--quiet', '--reverse', '--forward', '--dry-run',
            "--strip=%s" % strip, "--directory='%s'" % basedir,
            "--input='%s'" % patch_file]
    if binary:
        opts.append('--binary')
    if dest_file:
        opts.append("'%s'" % dest_file)

    (rc, _, _) = patch_func(opts)
    return rc == 0

def apply_patch(patch_func, patch_file, basedir, dest_file=None, binary=False, strip=0, dry_run=False, backup=False):
    opts = ['--quiet', '--forward', '--batch', '--reject-file=-',
            "--strip=%s" % strip, "--directory='%s'" % basedir,
            "--input='%s'" % patch_file]
    if dry_run:
        opts.append('--dry-run')
    if binary:
        opts.append('--binary')
    if dest_file:
        opts.append("'%s'" % dest_file)
    if backup:
        opts.append('--backup --version-control=numbered')

    (rc, out, err) = patch_func(opts)
    if rc != 0:
        msg = err or out
        raise PatchError(msg)

def main():
    module = AnsibleModule(
        argument_spec={
            'src':     {'required': True, 'aliases': ['patchfile']},
            'dest':    {'aliases': ['originalfile']},
            'basedir': {},
            'strip':   {'default': 0, 'type': 'int'},
            'remote_src': {'default': False, 'type': 'bool'},
            # NB: for 'backup' parameter, semantics is slightly different from standard
            #     since patch will create numbered copies, not strftime("%Y-%m-%d@%H:%M:%S~")
            'backup': {'default': False, 'type': 'bool'},
            'binary': {'default': False, 'type': 'bool'},
        },
        required_one_of=[['dest', 'basedir']],
        supports_check_mode=True
    )

    # Create type object as namespace for module params
    p = type('Params', (), module.params)

    p.src = os.path.expanduser(p.src)
    if not os.access(p.src, R_OK):
        module.fail_json(msg="src %s doesn't exist or not readable" % (p.src))

    if p.dest and not os.access(p.dest, W_OK):
        module.fail_json(msg="dest %s doesn't exist or not writable" % (p.dest))

    if p.basedir and not path.exists(p.basedir):
        module.fail_json(msg="basedir %s doesn't exist" % (p.basedir))

    if not p.basedir:
        p.basedir = path.dirname(p.dest)

    patch_bin = module.get_bin_path('patch')
    if patch_bin is None:
        module.fail_json(msg="patch command not found")
    patch_func = lambda opts: module.run_command("%s %s" % (patch_bin, ' '.join(opts)))

    # patch need an absolute file name
    p.src = os.path.abspath(p.src)

    changed = False
    if not is_already_applied(patch_func, p.src, p.basedir, dest_file=p.dest, binary=p.binary, strip=p.strip):
        try:
            apply_patch( patch_func, p.src, p.basedir, dest_file=p.dest, binary=p.binary, strip=p.strip,
                         dry_run=module.check_mode, backup=p.backup )
            changed = True
        except PatchError:
            e = get_exception()
            module.fail_json(msg=str(e))

    module.exit_json(changed=changed)

# import module snippets
from ansible.module_utils.basic import *
main()
<commit_msg>Make `main()` calls conditional - files (#3658)<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2012, Luis Alberto Perez Lazaro <luisperlazaro@gmail.com>
# (c) 2015, Jakub Jirutka <jakub@jirutka.cz>
#
# 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: patch
author:
    - "Jakub Jirutka (@jirutka)"
    - "Luis Alberto Perez Lazaro (@luisperlaz)"
version_added: 1.9
description:
    - Apply patch files using the GNU patch tool.
short_description: Apply patch files using the GNU patch tool.
options:
  basedir:
    description:
      - Path of a base directory in which the patch file will be applied.
        May be ommitted when C(dest) option is specified, otherwise required.
    required: false
  dest:
    description:
      - Path of the file on the remote machine to be patched.
      - The names of the files to be patched are usually taken from the patch
        file, but if there's just one file to be patched it can specified with
        this option.
    required: false
    aliases: [ "originalfile" ]
  src:
    description:
      - Path of the patch file as accepted by the GNU patch tool. If
        C(remote_src) is 'no', the patch source file is looked up from the
        module's "files" directory.
    required: true
    aliases: [ "patchfile" ]
  remote_src:
    description:
      - If C(no), it will search for src at originating/master machine, if C(yes) it will
        go to the remote/target machine for the src. Default is C(no).
    choices: [ "yes", "no" ]
    required: false
    default: "no"
  strip:
    description:
      - Number that indicates the smallest prefix containing leading slashes
        that will be stripped from each file name found in the patch file.
        For more information see the strip parameter of the GNU patch tool.
    required: false
    type: "int"
    default: "0"
  backup:
    version_added: "2.0"
    description:
      - passes --backup --version-control=numbered to patch,
        producing numbered backup copies
    choices: [ 'yes', 'no' ]
    default: 'no'
  binary:
    version_added: "2.0"
    description:
      - Setting to C(yes) will disable patch's heuristic for transforming CRLF
        line endings into LF. Line endings of src and dest must match. If set to
        C(no), patch will replace CRLF in src files on POSIX.
    required: false
    type: "bool"
    default: "no"
note:
  - This module requires GNU I(patch) utility to be installed on the remote host.
'''

EXAMPLES = '''
- name: apply patch to one file
  patch: >
    src=/tmp/index.html.patch
    dest=/var/www/index.html

- name: apply patch to multiple files under basedir
  patch: >
    src=/tmp/customize.patch
    basedir=/var/www
    strip=1
'''

import os
from os import path, R_OK, W_OK

class PatchError(Exception):
    pass

def is_already_applied(patch_func, patch_file, basedir, dest_file=None, binary=False, strip=0):
    opts = ['--quiet', '--reverse', '--forward', '--dry-run',
            "--strip=%s" % strip, "--directory='%s'" % basedir,
            "--input='%s'" % patch_file]
    if binary:
        opts.append('--binary')
    if dest_file:
        opts.append("'%s'" % dest_file)

    (rc, _, _) = patch_func(opts)
    return rc == 0

def apply_patch(patch_func, patch_file, basedir, dest_file=None, binary=False, strip=0, dry_run=False, backup=False):
    opts = ['--quiet', '--forward', '--batch', '--reject-file=-',
            "--strip=%s" % strip, "--directory='%s'" % basedir,
            "--input='%s'" % patch_file]
    if dry_run:
        opts.append('--dry-run')
    if binary:
        opts.append('--binary')
    if dest_file:
        opts.append("'%s'" % dest_file)
    if backup:
        opts.append('--backup --version-control=numbered')

    (rc, out, err) = patch_func(opts)
    if rc != 0:
        msg = err or out
        raise PatchError(msg)

def main():
    module = AnsibleModule(
        argument_spec={
            'src':     {'required': True, 'aliases': ['patchfile']},
            'dest':    {'aliases': ['originalfile']},
            'basedir': {},
            'strip':   {'default': 0, 'type': 'int'},
            'remote_src': {'default': False, 'type': 'bool'},
            # NB: for 'backup' parameter, semantics is slightly different from standard
            #     since patch will create numbered copies, not strftime("%Y-%m-%d@%H:%M:%S~")
            'backup': {'default': False, 'type': 'bool'},
            'binary': {'default': False, 'type': 'bool'},
        },
        required_one_of=[['dest', 'basedir']],
        supports_check_mode=True
    )

    # Create type object as namespace for module params
    p = type('Params', (), module.params)

    p.src = os.path.expanduser(p.src)
    if not os.access(p.src, R_OK):
        module.fail_json(msg="src %s doesn't exist or not readable" % (p.src))

    if p.dest and not os.access(p.dest, W_OK):
        module.fail_json(msg="dest %s doesn't exist or not writable" % (p.dest))

    if p.basedir and not path.exists(p.basedir):
        module.fail_json(msg="basedir %s doesn't exist" % (p.basedir))

    if not p.basedir:
        p.basedir = path.dirname(p.dest)

    patch_bin = module.get_bin_path('patch')
    if patch_bin is None:
        module.fail_json(msg="patch command not found")
    patch_func = lambda opts: module.run_command("%s %s" % (patch_bin, ' '.join(opts)))

    # patch need an absolute file name
    p.src = os.path.abspath(p.src)

    changed = False
    if not is_already_applied(patch_func, p.src, p.basedir, dest_file=p.dest, binary=p.binary, strip=p.strip):
        try:
            apply_patch( patch_func, p.src, p.basedir, dest_file=p.dest, binary=p.binary, strip=p.strip,
                         dry_run=module.check_mode, backup=p.backup )
            changed = True
        except PatchError:
            e = get_exception()
            module.fail_json(msg=str(e))

    module.exit_json(changed=changed)

# import module snippets
from ansible.module_utils.basic import *

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


<commit_before># (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# 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/>.

import os

from ansible import utils
import ansible.utils.template as template
from ansible import errors
from ansible.runner.return_data import ReturnData
import base64
import stat
import tempfile
import pipes

## fixes https://github.com/ansible/ansible/issues/3518
# http://mypy.pythonblogs.com/12_mypy/archive/1253_workaround_for_python_bug_ascii_codec_cant_encode_character_uxa0_in_position_111_ordinal_not_in_range128.html
import sys
reload(sys)
sys.setdefaultencoding("utf8")

class ActionModule(object):

    TRANSFERS_FILES = True

    def __init__(self, runner):
        self.runner = runner

    def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
        ''' handler for file transfer operations '''

        # load up options
        options = {}
        if complex_args:
            options.update(complex_args)
        options.update(utils.parse_kv(module_args))
        source  = options.get('src', None)
        content = options.get('content', None)
        dest    = options.get('dest', None)
        raw     = utils.boolean(options.get('raw', 'no'))
        force   = utils.boolean(options.get('force', 'yes'))

        if (source is None and content is None and not 'first_available_file' in inject) or dest is None:
            result=dict(failed=True, msg="src (or content) and dest are required")
            return ReturnData(conn=conn, result=result)
        elif (source is not None or 'first_available_file' in inject) and content is not None:
            result=dict(failed=True, msg="src and content are mutually exclusive")
            return ReturnData(conn=conn, result=result)

        source_trailing_slash = False
        if source:
            source_trailing_slash = source.endswith("/")

        # if we have first_available_file in our vars
        # look up the files and use the first one we find as src
        if 'first_available_file' in inject:
            found = False
            for fn in inject.get('first_available_file'):
                fn_orig = fn
                fnt = template.template(self.runner.basedir, fn, inject)
                fnd = utils.path_dwim(self.runner.basedir, fnt)
                if not os.path.exists(fnd) and '_original_file' in inject:
                    fnd = utils.path_dwim_relative(inject['_original_file'], 'files', fnt, self.runner.basedir, check=False)
                if os.path.exists(fnd):
                    source = fnd
                    found = True
                    break
            if not found:
                results=dict(failed=True, msg="could not find src in first_available_file list")
                return ReturnData(conn=conn, result=results)
        elif content is not None:
            fd, tmp_content = tempfile.mkstemp()
            f = os.fdopen(fd, 'w')
            try:
                f.write(content)
            except Exception, err:
                os.remove(tmp_content)
                result = dict(failed=True, msg="could not write content temp file: %s" % err)
                return ReturnData(conn=conn, result=result)
            f.close()
            source = tmp_content
        else:
            source = template.template(self.runner.basedir, source, inject)
            if '_original_file' in inject:
                source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir)
            else:
                source = utils.path_dwim(self.runner.basedir, source)

        source_files = []
        if os.path.isdir(source):
            # Implement rsync-like behavior: if source is "dir/" , only
            # inside its contents will be copied to destination. Otherwise
            # if it's "dir", dir itself will be copied to destination.
            if source_trailing_slash:
                sz = len(source) + 1
            else:
                sz = len(source.rsplit('/', 1)[0]) + 1
            for base_path, sub_folders, files in os.walk(source):
                for file in files:
                    full_path = os.path.join(base_path, file)
                    rel_path = full_path[sz:]
                    source_files.append((full_path, rel_path))
            # If it's recursive copy, destination is always a dir,
            # explictly mark it so (note - copy module relies on this).
            if not dest.endswith("/"):
                dest += "/"
        else:
            source_files.append((source, os.path.basename(source)))

        changed = False
        diffs = []
        module_result = {"changed": False}
        # Remove tmp path since a new one is created below.  Should be empty.
        if tmp.find("tmp") != -1:
            self.runner._low_level_exec_command(conn, "rm -rf %s > /dev/null 2>&1" % tmp, tmp)
        for source_full, source_rel in source_files:
            # We need to get a new tmp path for each file, otherwise the copy module deletes the folder.
            tmp = self.runner._make_tmp_path(conn)
            local_md5 = utils.md5(source_full)

            if local_md5 is None:
                result=dict(failed=True, msg="could not find src=%s" % source_full)
                return ReturnData(conn=conn, result=result)

            # This is kind of optimization - if user told us destination is
            # dir, do path manipulation right away, otherwise we still check
            # for dest being a dir via remote call below.
            if dest.endswith("/"):
                dest_file = os.path.join(dest, source_rel)
            else:
                dest_file = dest

            remote_md5 = self.runner._remote_md5(conn, tmp, dest_file)
            if remote_md5 == '3':
                # Destination is a directory
                if content is not None:
                    os.remove(tmp_content)
                    result = dict(failed=True, msg="can not use content with a dir as dest")
                    return ReturnData(conn=conn, result=result)
                dest_file = os.path.join(dest, source_rel)
                remote_md5 = self.runner._remote_md5(conn, tmp, dest_file)

            # remote_md5 == '1' would mean that the file does not exist.
            if remote_md5 != '1' and not force:
                continue

            exec_rc = None
            if local_md5 != remote_md5:
                # Assume we either really change file or error out
                changed = True

                if self.runner.diff and not raw:
                    diff = self._get_diff_data(conn, tmp, inject, dest_file, source_full)
                else:
                    diff = {}

                if self.runner.noop_on_check(inject):
                    if content is not None:
                        os.remove(tmp_content)
                    diffs.append(diff)
                    changed = True
                    module_result = dict(changed=True)
                    continue

                # transfer the file to a remote tmp location
                tmp_src = tmp + 'source'

                if not raw:
                    conn.put_file(source_full, tmp_src)
                else:
                    conn.put_file(source_full, dest_file)

                if content is not None:
                    os.remove(tmp_content)

                # fix file permissions when the copy is done as a different user
                if self.runner.sudo and self.runner.sudo_user != 'root' and not raw:
                    self.runner._low_level_exec_command(conn, "chmod a+r %s" % tmp_src, tmp)

                if raw:
                    continue

                # run the copy module
                if raw:
                    # don't send down raw=no
                    module_args.pop('raw')

                # src and dest here come after original and override them
                # we pass dest only to make sure it includes trailing slash
                # in case of recursive copy
                module_args_tmp = "%s src=%s dest=%s original_basename=%s" % (module_args,
                                  pipes.quote(tmp_src), pipes.quote(dest), pipes.quote(source_rel))
                module_return = self.runner._execute_module(conn, tmp, 'copy', module_args_tmp, inject=inject, complex_args=complex_args)

            else:
                # no need to transfer the file, already correct md5, but still need to call
                # the file module in case we want to change attributes
                if content is not None:
                    os.remove(tmp_content)

                if raw:
                    continue

                tmp_src = tmp + source_rel
                if raw:
                    # don't send down raw=no
                    module_args.pop('raw')
                module_args_tmp = "%s src=%s original_basename=%s" % (module_args,
                                  pipes.quote(tmp_src), pipes.quote(source_rel))
                if self.runner.noop_on_check(inject):
                    module_args_tmp = "%s CHECKMODE=True" % module_args_tmp
                module_return = self.runner._execute_module(conn, tmp, 'file', module_args_tmp, inject=inject, complex_args=complex_args)

            module_result = module_return.result
            if module_result.get('failed') == True:
                return module_return
            if module_result.get('changed') == True:
                changed = True

        # TODO: Support detailed status/diff for multiple files
        if len(source_files) == 1:
            result = module_result
        else:
            result = dict(dest=dest, src=source, changed=changed)
        if len(diffs) == 1:
            return ReturnData(conn=conn, result=result, diff=diffs[0])
        else:
            return ReturnData(conn=conn, result=result)

    def _get_diff_data(self, conn, tmp, inject, destination, source):
        peek_result = self.runner._execute_module(conn, tmp, 'file', "path=%s diff_peek=1" % destination, inject=inject, persist_files=True)

        if not peek_result.is_successful():
            return {}

        diff = {}
        if peek_result.result['state'] == 'absent':
            diff['before'] = ''
        elif peek_result.result['appears_binary']:
            diff['dst_binary'] = 1
        elif peek_result.result['size'] > utils.MAX_FILE_SIZE_FOR_DIFF:
            diff['dst_larger'] = utils.MAX_FILE_SIZE_FOR_DIFF
        else:
            dest_result = self.runner._execute_module(conn, tmp, 'slurp', "path=%s" % destination, inject=inject, persist_files=True)
            if 'content' in dest_result.result:
                dest_contents = dest_result.result['content']
                if dest_result.result['encoding'] == 'base64':
                    dest_contents = base64.b64decode(dest_contents)
                else:
                    raise Exception("unknown encoding, failed: %s" % dest_result.result)
                diff['before_header'] = destination
                diff['before'] = dest_contents

        src = open(source)
        src_contents = src.read(8192)
        st = os.stat(source)
        if src_contents.find("\x00") != -1:
            diff['src_binary'] = 1
        elif st[stat.ST_SIZE] > utils.MAX_FILE_SIZE_FOR_DIFF:
            diff['src_larger'] = utils.MAX_FILE_SIZE_FOR_DIFF
        else:
            src.seek(0)
            diff['after_header'] = source
            diff['after'] = src.read()

        return diff

    def _result_key_merge(self, options, results):
        # add keys to file module results to mimic copy
        if 'path' in results.result and 'dest' not in results.result:
            results.result['dest'] = results.result['path']
            del results.result['path']
        return results
<commit_msg>remove useless create/delete remote tmp dir roundtrip in copy module<commit_after># (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# 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/>.

import os

from ansible import utils
import ansible.utils.template as template
from ansible import errors
from ansible.runner.return_data import ReturnData
import base64
import stat
import tempfile
import pipes

## fixes https://github.com/ansible/ansible/issues/3518
# http://mypy.pythonblogs.com/12_mypy/archive/1253_workaround_for_python_bug_ascii_codec_cant_encode_character_uxa0_in_position_111_ordinal_not_in_range128.html
import sys
reload(sys)
sys.setdefaultencoding("utf8")

class ActionModule(object):

    def __init__(self, runner):
        self.runner = runner

    def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
        ''' handler for file transfer operations '''

        # load up options
        options = {}
        if complex_args:
            options.update(complex_args)
        options.update(utils.parse_kv(module_args))
        source  = options.get('src', None)
        content = options.get('content', None)
        dest    = options.get('dest', None)
        raw     = utils.boolean(options.get('raw', 'no'))
        force   = utils.boolean(options.get('force', 'yes'))

        if (source is None and content is None and not 'first_available_file' in inject) or dest is None:
            result=dict(failed=True, msg="src (or content) and dest are required")
            return ReturnData(conn=conn, result=result)
        elif (source is not None or 'first_available_file' in inject) and content is not None:
            result=dict(failed=True, msg="src and content are mutually exclusive")
            return ReturnData(conn=conn, result=result)

        source_trailing_slash = False
        if source:
            source_trailing_slash = source.endswith("/")

        # if we have first_available_file in our vars
        # look up the files and use the first one we find as src
        if 'first_available_file' in inject:
            found = False
            for fn in inject.get('first_available_file'):
                fn_orig = fn
                fnt = template.template(self.runner.basedir, fn, inject)
                fnd = utils.path_dwim(self.runner.basedir, fnt)
                if not os.path.exists(fnd) and '_original_file' in inject:
                    fnd = utils.path_dwim_relative(inject['_original_file'], 'files', fnt, self.runner.basedir, check=False)
                if os.path.exists(fnd):
                    source = fnd
                    found = True
                    break
            if not found:
                results=dict(failed=True, msg="could not find src in first_available_file list")
                return ReturnData(conn=conn, result=results)
        elif content is not None:
            fd, tmp_content = tempfile.mkstemp()
            f = os.fdopen(fd, 'w')
            try:
                f.write(content)
            except Exception, err:
                os.remove(tmp_content)
                result = dict(failed=True, msg="could not write content temp file: %s" % err)
                return ReturnData(conn=conn, result=result)
            f.close()
            source = tmp_content
        else:
            source = template.template(self.runner.basedir, source, inject)
            if '_original_file' in inject:
                source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir)
            else:
                source = utils.path_dwim(self.runner.basedir, source)

        source_files = []
        if os.path.isdir(source):
            # Implement rsync-like behavior: if source is "dir/" , only
            # inside its contents will be copied to destination. Otherwise
            # if it's "dir", dir itself will be copied to destination.
            if source_trailing_slash:
                sz = len(source) + 1
            else:
                sz = len(source.rsplit('/', 1)[0]) + 1
            for base_path, sub_folders, files in os.walk(source):
                for file in files:
                    full_path = os.path.join(base_path, file)
                    rel_path = full_path[sz:]
                    source_files.append((full_path, rel_path))
            # If it's recursive copy, destination is always a dir,
            # explictly mark it so (note - copy module relies on this).
            if not dest.endswith("/"):
                dest += "/"
        else:
            source_files.append((source, os.path.basename(source)))

        changed = False
        diffs = []
        module_result = {"changed": False}
        for source_full, source_rel in source_files:
            # We need to get a new tmp path for each file, otherwise the copy module deletes the folder.
            tmp = self.runner._make_tmp_path(conn)
            local_md5 = utils.md5(source_full)

            if local_md5 is None:
                result=dict(failed=True, msg="could not find src=%s" % source_full)
                return ReturnData(conn=conn, result=result)

            # This is kind of optimization - if user told us destination is
            # dir, do path manipulation right away, otherwise we still check
            # for dest being a dir via remote call below.
            if dest.endswith("/"):
                dest_file = os.path.join(dest, source_rel)
            else:
                dest_file = dest

            remote_md5 = self.runner._remote_md5(conn, tmp, dest_file)
            if remote_md5 == '3':
                # Destination is a directory
                if content is not None:
                    os.remove(tmp_content)
                    result = dict(failed=True, msg="can not use content with a dir as dest")
                    return ReturnData(conn=conn, result=result)
                dest_file = os.path.join(dest, source_rel)
                remote_md5 = self.runner._remote_md5(conn, tmp, dest_file)

            # remote_md5 == '1' would mean that the file does not exist.
            if remote_md5 != '1' and not force:
                continue

            exec_rc = None
            if local_md5 != remote_md5:
                # Assume we either really change file or error out
                changed = True

                if self.runner.diff and not raw:
                    diff = self._get_diff_data(conn, tmp, inject, dest_file, source_full)
                else:
                    diff = {}

                if self.runner.noop_on_check(inject):
                    if content is not None:
                        os.remove(tmp_content)
                    diffs.append(diff)
                    changed = True
                    module_result = dict(changed=True)
                    continue

                # transfer the file to a remote tmp location
                tmp_src = tmp + 'source'

                if not raw:
                    conn.put_file(source_full, tmp_src)
                else:
                    conn.put_file(source_full, dest_file)

                if content is not None:
                    os.remove(tmp_content)

                # fix file permissions when the copy is done as a different user
                if self.runner.sudo and self.runner.sudo_user != 'root' and not raw:
                    self.runner._low_level_exec_command(conn, "chmod a+r %s" % tmp_src, tmp)

                if raw:
                    continue

                # run the copy module
                if raw:
                    # don't send down raw=no
                    module_args.pop('raw')

                # src and dest here come after original and override them
                # we pass dest only to make sure it includes trailing slash
                # in case of recursive copy
                module_args_tmp = "%s src=%s dest=%s original_basename=%s" % (module_args,
                                  pipes.quote(tmp_src), pipes.quote(dest), pipes.quote(source_rel))
                module_return = self.runner._execute_module(conn, tmp, 'copy', module_args_tmp, inject=inject, complex_args=complex_args)

            else:
                # no need to transfer the file, already correct md5, but still need to call
                # the file module in case we want to change attributes
                if content is not None:
                    os.remove(tmp_content)

                if raw:
                    continue

                tmp_src = tmp + source_rel
                if raw:
                    # don't send down raw=no
                    module_args.pop('raw')
                module_args_tmp = "%s src=%s original_basename=%s" % (module_args,
                                  pipes.quote(tmp_src), pipes.quote(source_rel))
                if self.runner.noop_on_check(inject):
                    module_args_tmp = "%s CHECKMODE=True" % module_args_tmp
                module_return = self.runner._execute_module(conn, tmp, 'file', module_args_tmp, inject=inject, complex_args=complex_args)

            module_result = module_return.result
            if module_result.get('failed') == True:
                return module_return
            if module_result.get('changed') == True:
                changed = True

        # TODO: Support detailed status/diff for multiple files
        if len(source_files) == 1:
            result = module_result
        else:
            result = dict(dest=dest, src=source, changed=changed)
        if len(diffs) == 1:
            return ReturnData(conn=conn, result=result, diff=diffs[0])
        else:
            return ReturnData(conn=conn, result=result)

    def _get_diff_data(self, conn, tmp, inject, destination, source):
        peek_result = self.runner._execute_module(conn, tmp, 'file', "path=%s diff_peek=1" % destination, inject=inject, persist_files=True)

        if not peek_result.is_successful():
            return {}

        diff = {}
        if peek_result.result['state'] == 'absent':
            diff['before'] = ''
        elif peek_result.result['appears_binary']:
            diff['dst_binary'] = 1
        elif peek_result.result['size'] > utils.MAX_FILE_SIZE_FOR_DIFF:
            diff['dst_larger'] = utils.MAX_FILE_SIZE_FOR_DIFF
        else:
            dest_result = self.runner._execute_module(conn, tmp, 'slurp', "path=%s" % destination, inject=inject, persist_files=True)
            if 'content' in dest_result.result:
                dest_contents = dest_result.result['content']
                if dest_result.result['encoding'] == 'base64':
                    dest_contents = base64.b64decode(dest_contents)
                else:
                    raise Exception("unknown encoding, failed: %s" % dest_result.result)
                diff['before_header'] = destination
                diff['before'] = dest_contents

        src = open(source)
        src_contents = src.read(8192)
        st = os.stat(source)
        if src_contents.find("\x00") != -1:
            diff['src_binary'] = 1
        elif st[stat.ST_SIZE] > utils.MAX_FILE_SIZE_FOR_DIFF:
            diff['src_larger'] = utils.MAX_FILE_SIZE_FOR_DIFF
        else:
            src.seek(0)
            diff['after_header'] = source
            diff['after'] = src.read()

        return diff

    def _result_key_merge(self, options, results):
        # add keys to file module results to mimic copy
        if 'path' in results.result and 'dest' not in results.result:
            results.result['dest'] = results.result['path']
            del results.result['path']
        return results
<|endoftext|>


<commit_before>
from fastats.maths.activations import relu, softplus
from fastats.maths.deriv import deriv
from fastats.maths.erf import erf
from fastats.maths.logistic import logistic
from fastats.maths.norm_pdf import norm_pdf
from fastats.maths.sum_sq_dev import sum_sq_dev

__all__ = [
    'deriv',
    'erf',
    'logistic',
    'norm_pdf',
    'sum_sq_dev',
    'relu',
    'softplus',
]
<commit_msg>Add to maths init<commit_after>
from fastats.maths.activations import relu, softplus
from fastats.maths.deriv import deriv
from fastats.maths.erf import erf
from fastats.maths.ewma import ewma
from fastats.maths.logistic import logistic
from fastats.maths.norm_pdf import norm_pdf
from fastats.maths.sum_sq_dev import sum_sq_dev

__all__ = [
    'deriv',
    'erf',
    'ewma',
    'logistic',
    'norm_pdf',
    'sum_sq_dev',
    'relu',
    'softplus',
]
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
#    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 errno
import functools
import itertools
import logging
import os
import threading
import time

import six

from fasteners import _utils

LOG = logging.getLogger(__name__)

def _noop_delay(attempts):
    return None

def _ensure_tree(path):
    """Create a directory (and any ancestor directories required).

    :param path: Directory to create
    """
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno == errno.EEXIST:
            if not os.path.isdir(path):
                raise
            else:
                return False
        else:
            raise
    else:
        return True

class _InterProcessLock(object):
    """An interprocess locking implementation.

    This is a lock implementation which allows multiple locks, working around
    issues like http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and
    does not require any cleanup. Since the lock is always held on a file
    descriptor rather than outside of the process, the lock gets dropped
    automatically if the process crashes, even if ``__exit__`` is not
    executed.

    There are no guarantees regarding usage by multiple threads in a
    single process here. This lock works only between processes.

    Note these locks are released when the descriptor is closed, so it's not
    safe to close the file descriptor while another thread holds the
    lock. Just opening and closing the lock file can break synchronization,
    so lock files must be accessed only using this abstraction.
    """

    MAX_DELAY = 0.1
    """
    Default maximum delay we will wait to try to acquire the lock (when
    it's busy/being held by another process).
    """

    DELAY_INCREMENT = 0.01
    """
    Default increment we will use (up to max delay) after each attempt before
    next attempt to acquire the lock. For example if 3 attempts have been made
    the calling thread will sleep (0.01 * 3) before the next attempt to
    acquire the lock (and repeat).
    """

    def __init__(self, path, sleep_func=time.sleep):
        self.lockfile = None
        self.path = path
        self.acquired = False
        self.sleep_func = sleep_func

    def _do_acquire(self, delay_func, blocking, watch):
        attempts_iter = itertools.count(1)
        while True:
            attempts = six.next(attempts_iter)
            try:
                self.trylock()
            except IOError as e:
                if e.errno in (errno.EACCES, errno.EAGAIN):
                    if not blocking or watch.expired():
                        return (False, attempts)
                    else:
                        delay_func(attempts)
                else:
                    raise threading.ThreadError("Unable to acquire lock on"
                                                " `%(path)s` due to"
                                                " %(exception)s" %
                                                {
                                                    'path': self.path,
                                                    'exception': e,
                                                })
            else:
                return (True, attempts)

    def _do_open(self):
        basedir = os.path.dirname(self.path)
        made_basedir = _ensure_tree(basedir)
        if made_basedir:
            LOG.info('Created lock base path `%s`', basedir)
        # Open in append mode so we don't overwrite any potential contents of
        # the target file. This eliminates the possibility of an attacker
        # creating a symlink to an important file in our lock path.
        if self.lockfile is None or self.lockfile.closed:
            self.lockfile = open(self.path, 'a')

    def _backoff_multiplier_delay(self, attempts, delay, max_delay):
        maybe_delay = attempts * delay
        if maybe_delay < max_delay:
            actual_delay = maybe_delay
        else:
            actual_delay = max_delay
        actual_delay = max(0.0, actual_delay)
        self.sleep_func(actual_delay)

    def acquire(self, blocking=True,
                delay=DELAY_INCREMENT, max_delay=MAX_DELAY,
                timeout=None):
        if delay < 0:
            raise ValueError("Delay must be greater than or equal to zero")
        if timeout is not None and timeout < 0:
            raise ValueError("Timeout must be greater than or equal to zero")
        if delay >= max_delay:
            max_delay = delay
        self._do_open()
        watch = _utils.StopWatch(duration=timeout)
        if blocking:
            delay_func = functools.partial(self._backoff_multiplier_delay,
                                           delay=delay, max_delay=max_delay)
        else:
            delay_func = _noop_delay
        with watch:
            gotten, attempts = self._do_acquire(delay_func, blocking, watch)
        if not gotten:
            self.acquired = False
            return False
        else:
            self.acquired = True
            LOG.debug("Acquired file lock `%s` after waiting %0.3fs [%s"
                      " attempts were required]", self.path, watch.elapsed(),
                      attempts)
            return True

    def _do_close(self):
        if self.lockfile is not None:
            self.lockfile.close()
            self.lockfile = None

    def __enter__(self):
        self.acquire()
        return self

    def release(self):
        if not self.acquired:
            raise threading.ThreadError("Unable to release an unacquired"
                                        " lock")
        try:
            self.unlock()
        except IOError:
            LOG.exception("Could not unlock the acquired lock opened"
                          " on `%s`", self.path)
        else:
            self.acquired = False
            try:
                self._do_close()
            except IOError:
                LOG.exception("Could not close the file handle"
                              " opened on `%s`", self.path)
            else:
                LOG.debug("Unlocked and closed file lock open on"
                          " `%s`", self.path)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.release()

    def exists(self):
        return os.path.exists(self.path)

    def trylock(self):
        raise NotImplementedError()

    def unlock(self):
        raise NotImplementedError()

class _WindowsLock(_InterProcessLock):

    def trylock(self):
        msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1)

    def unlock(self):
        msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)

class _FcntlLock(_InterProcessLock):

    def trylock(self):
        fcntl.lockf(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)

    def unlock(self):
        fcntl.lockf(self.lockfile, fcntl.LOCK_UN)

if os.name == 'nt':
    import msvcrt

    #: Interprocess lock implementation that works on your system.
    InterProcessLock = _WindowsLock
else:
    import fcntl

    #: Interprocess lock implementation that works on your system.
    InterProcessLock = _FcntlLock

def interprocess_locked(path):
    """Acquires & releases a interprocess lock around call into
       decorated function."""

    lock = InterProcessLock(path)

    def decorator(f):

        @six.wraps(f)
        def wrapper(*args, **kwargs):
            with lock:
                return f(*args, **kwargs)

        return wrapper

    return decorator
<commit_msg>Add more docstrings to process lock<commit_after># -*- coding: utf-8 -*-

# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
#    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 errno
import functools
import itertools
import logging
import os
import threading
import time

import six

from fasteners import _utils

LOG = logging.getLogger(__name__)

def _noop_delay(attempts):
    return None

def _ensure_tree(path):
    """Create a directory (and any ancestor directories required).

    :param path: Directory to create
    """
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno == errno.EEXIST:
            if not os.path.isdir(path):
                raise
            else:
                return False
        else:
            raise
    else:
        return True

class _InterProcessLock(object):
    """An interprocess locking implementation.

    This is a lock implementation which allows multiple locks, working around
    issues like http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and
    does not require any cleanup. Since the lock is always held on a file
    descriptor rather than outside of the process, the lock gets dropped
    automatically if the process crashes, even if ``__exit__`` is not
    executed.

    There are no guarantees regarding usage by multiple threads in a
    single process here. This lock works only between processes.

    Note these locks are released when the descriptor is closed, so it's not
    safe to close the file descriptor while another thread holds the
    lock. Just opening and closing the lock file can break synchronization,
    so lock files must be accessed only using this abstraction.
    """

    MAX_DELAY = 0.1
    """
    Default maximum delay we will wait to try to acquire the lock (when
    it's busy/being held by another process).
    """

    DELAY_INCREMENT = 0.01
    """
    Default increment we will use (up to max delay) after each attempt before
    next attempt to acquire the lock. For example if 3 attempts have been made
    the calling thread will sleep (0.01 * 3) before the next attempt to
    acquire the lock (and repeat).
    """

    def __init__(self, path, sleep_func=time.sleep):
        self.lockfile = None
        self.path = path
        self.acquired = False
        self.sleep_func = sleep_func

    def _do_acquire(self, delay_func, blocking, watch):
        attempts_iter = itertools.count(1)
        while True:
            attempts = six.next(attempts_iter)
            try:
                self.trylock()
            except IOError as e:
                if e.errno in (errno.EACCES, errno.EAGAIN):
                    if not blocking or watch.expired():
                        return (False, attempts)
                    else:
                        delay_func(attempts)
                else:
                    raise threading.ThreadError("Unable to acquire lock on"
                                                " `%(path)s` due to"
                                                " %(exception)s" %
                                                {
                                                    'path': self.path,
                                                    'exception': e,
                                                })
            else:
                return (True, attempts)

    def _do_open(self):
        basedir = os.path.dirname(self.path)
        made_basedir = _ensure_tree(basedir)
        if made_basedir:
            LOG.info('Created lock base path `%s`', basedir)
        # Open in append mode so we don't overwrite any potential contents of
        # the target file. This eliminates the possibility of an attacker
        # creating a symlink to an important file in our lock path.
        if self.lockfile is None or self.lockfile.closed:
            self.lockfile = open(self.path, 'a')

    def _backoff_multiplier_delay(self, attempts, delay, max_delay):
        maybe_delay = attempts * delay
        if maybe_delay < max_delay:
            actual_delay = maybe_delay
        else:
            actual_delay = max_delay
        actual_delay = max(0.0, actual_delay)
        self.sleep_func(actual_delay)

    def acquire(self, blocking=True,
                delay=DELAY_INCREMENT, max_delay=MAX_DELAY,
                timeout=None):
        """Attempt to acquire the given lock.

        :param blocking: whether to wait forever to try to acquire the lock
        :type blocking: bool
        :param delay: when blocking this is the delay time in seconds that
                      will be added after each failed acquisition
        :type delay: int/float
        :param max_delay: the maximum delay to have (this limits the
                          accumulated delay(s) added after each failed
                          acquisition)
        :type max_delay: int/float
        :param timeout: an optional timeout (limits how long blocking
                        will occur for)
        :type timeout: int/float
        :returns: whether or not the acquisition succeeded
        :rtype: bool
        """
        if delay < 0:
            raise ValueError("Delay must be greater than or equal to zero")
        if timeout is not None and timeout < 0:
            raise ValueError("Timeout must be greater than or equal to zero")
        if delay >= max_delay:
            max_delay = delay
        self._do_open()
        watch = _utils.StopWatch(duration=timeout)
        if blocking:
            delay_func = functools.partial(self._backoff_multiplier_delay,
                                           delay=delay, max_delay=max_delay)
        else:
            delay_func = _noop_delay
        with watch:
            gotten, attempts = self._do_acquire(delay_func, blocking, watch)
        if not gotten:
            self.acquired = False
            return False
        else:
            self.acquired = True
            LOG.debug("Acquired file lock `%s` after waiting %0.3fs [%s"
                      " attempts were required]", self.path, watch.elapsed(),
                      attempts)
            return True

    def _do_close(self):
        if self.lockfile is not None:
            self.lockfile.close()
            self.lockfile = None

    def __enter__(self):
        self.acquire()
        return self

    def release(self):
        """Release the previously acquired lock."""
        if not self.acquired:
            raise threading.ThreadError("Unable to release an unacquired"
                                        " lock")
        try:
            self.unlock()
        except IOError:
            LOG.exception("Could not unlock the acquired lock opened"
                          " on `%s`", self.path)
        else:
            self.acquired = False
            try:
                self._do_close()
            except IOError:
                LOG.exception("Could not close the file handle"
                              " opened on `%s`", self.path)
            else:
                LOG.debug("Unlocked and closed file lock open on"
                          " `%s`", self.path)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.release()

    def exists(self):
        """Checks if the path that this lock exists at actually exists."""
        return os.path.exists(self.path)

    def trylock(self):
        raise NotImplementedError()

    def unlock(self):
        raise NotImplementedError()

class _WindowsLock(_InterProcessLock):

    def trylock(self):
        msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1)

    def unlock(self):
        msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)

class _FcntlLock(_InterProcessLock):

    def trylock(self):
        fcntl.lockf(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)

    def unlock(self):
        fcntl.lockf(self.lockfile, fcntl.LOCK_UN)

if os.name == 'nt':
    import msvcrt

    #: Interprocess lock implementation that works on your system.
    InterProcessLock = _WindowsLock
else:
    import fcntl

    #: Interprocess lock implementation that works on your system.
    InterProcessLock = _FcntlLock

def interprocess_locked(path):
    """Acquires & releases a interprocess lock around call into
       decorated function."""

    lock = InterProcessLock(path)

    def decorator(f):

        @six.wraps(f)
        def wrapper(*args, **kwargs):
            with lock:
                return f(*args, **kwargs)

        return wrapper

    return decorator
<|endoftext|>


<commit_before>r"""
Finite difference solution of the 2D wave equation for isotropic media.

Simulates both elastic and acoustic waves:

* :func:`~fatiando.seis.wavefd2d.elastic_psv`: Simulates the coupled P and SV
  elastic waves
* :func:`~fatiando.seis.wavefd2d.elastic_sh`: Simulates SH elastic waves

**Auxiliary function**

* :func:`~fatiando.seis.wavefd2d.lame`: Calculate the Lame constants from P and
  S wave velocities and density

**Sources**

* :class:`~fatiando.seis.wavefd2d.MexHatSource`: Mexican hat wavelet source

**Theory**

We start with the wave equation for elastic isotropic media

.. math::

    (\lambda + \mu)\nabla(\nabla\cdot\mathbf{u})
    +
    \mu\nabla^2\mathbf{u}
    - \rho \partial_t^2 \mathbf{u} = - \mathbf{f}

where :math:`\mathbf{u} = (u_x, u_y, y_z)` is the particle movement vector,
:math:`\rho` is the density,
:math:`\lambda` and :math:`\mu` are the Lame constants,
and :math:`\mathbf{f}` is the source vector.

In the 2D approximation, we assume all derivatives in the y direction
are zero and consider only x and z coordinates
(though :math:`u_y` remains).
The three equations in the vector equation above can be separated into
two groups:

.. math::

    \mu\left(\partial_x^2 u_y + \partial_z^2 u_y\right)
    - \rho \partial_t^2 u_y = f_y

and

.. math::

    (\lambda + 2\mu)\partial_x^2 u_x + \mu\partial_z^2 u_x
    + (\lambda + \mu)\partial_x\partial_z u_z
    - \rho \partial_t^2 u_x = f_x

.. math::

    (\lambda + 2\mu)\partial_z^2 u_z + \mu\partial_x^2 u_z
    + (\lambda + \mu)\partial_x\partial_z u_x
    - \rho \partial_t^2 u_z = f_z

The first equation depends only on :math:`u_y` and represents SH waves.
The other two depend on :math:`u_x` and :math:`u_z` and are coupled.
They represent P and SV waves.

The explicit finite difference solution for the SH waves is:

.. math::
   :nowrap:

    \begin{align*}
        u_y[i,j]_{t+1} =& 2u_y[i,j]_{t} - u_y[i,j]_{t-1}
        + \frac{\Delta t^2}{\rho[i,j]}
        \left[
            -f_y[i,j]_t +
            \mu[i,j]
                \left(
                    \frac{u_y[i+1,j]_{t} - 2u_y[i,j]_{t} + u_y[i-1,j]_{t}}{
                        \Delta x^2}
                \right.
        \right.
        \\[0.3cm] &
        \left.
            \left.
                +
                \frac{u_y[i,j+1]_{t} - 2u_y[i,j]_{t} + u_y[i,j-1]_{t}}{\Delta z^2}
            \right)
        \right]
    \end{align*}

where :math:`[i,j]_t` is the quantity at the grid node i,j at a
time t.

The solution for P and SV waves is:

.. math::
   :nowrap:

    \begin{align*}
    u_x[i,j]_{t+1} =& 2u_x[i,j]_{t} - u_x[i,j]_{t-1}
    \\&
    + \frac{\Delta t^2}{\rho[i,j]}
    \left\lbrace
        -f_x[i,j]_{t} +
        (\lambda[i,j] + 2\mu[i,j])
        \left(
            \frac{u_x[i+1,j]_{t} - 2u_x[i,j]_{t} + u_x[i-1,j]_{t}}{
                \Delta x^2}
        \right)
    \right.
    \\[0.3cm]&
        +
        \mu[i,j]
        \left(
            \frac{u_x[i,j+1]_{t} - 2u_x[i,j]_{t} + u_x[i,j-1]_{t}}{
                \Delta z^2}
        \right)
    \\[0.3cm]&
    \left.
        +
        (\lambda[i,j] + \mu[i,j])
        \left(
            \frac{u_z[i,j]_{t} - u_z[i-1,j]_{t} - u_z[i,j-1]_{t} +
            u_z[i-1,j-1]_{t}
            }{\Delta x\Delta z}
        \right)
    \right\rbrace
    \end{align*}

.. math::
   :nowrap:

    \begin{align*}
    u_z[i,j]_{t+1} =& 2u_z[i,j]_{t} - u_z[i,j]_{t-1}
    \\&
    + \frac{\Delta t^2}{\rho[i,j]}
    \left\lbrace
        -f_z[i,j]_{t} +
        (\lambda[i,j] + 2\mu[i,j])
        \left(
            \frac{u_z[i,j+1]_{t} - 2u_z[i,j]_{t} + u_z[i,j-1]_{t}}{
                \Delta z^2}
        \right)
    \right.
    \\[0.3cm]&
        +
        \mu[i,j]
        \left(
            \frac{u_z[i+1,j]_{t} - 2u_z[i,j]_{t} + u_z[i-1,j]_{t}}{
                \Delta x^2}
        \right)
    \\[0.3cm]&
    \left.
        +
        (\lambda[i,j] + \mu[i,j])
        \left(
            \frac{u_x[i,j]_{t} - u_x[i-1,j]_{t} - u_x[i,j-1]_{t} +
            u_x[i-1,j-1]_{t}
            }{\Delta x\Delta z}
        \right)
    \right\rbrace
    \end{align*}

----

"""
import numpy

import fatiando.log

log = fatiando.log.dummy('fatiando.seis.wavefd2d')

class MexHatSource(object):
    r"""
    A wave source that vibrates as a mexicam hat (Ricker) wavelet.

    .. math::

        \psi(t) = A\frac{2}{\sqrt{3\sigma}\pi^{\frac{1}{4}}}
        \left( 1 - \frac{t^2}{\sigma^2} \right)
        \exp\left(\frac{-t^2}{2\sigma^2}\right)

    Parameters:

    * i, j : int
        The i,j coordinates of the source in the target finite difference grid
    * amp : float
        The amplitude of the source (:math:`A`)
    * std : float
        The "wave length" (:math:`\sigma`)
    * delay : float
        The delay before the source starts

        .. note:: If you want the source to start with amplitude close to 0, use
            ``delay = 3.5*std``.

    """

    def __init__(self, i, j, amp, std, delay=0):
        self.i = i
        self.j = j
        self.amp = amp
        self.std = std
        self.delay = delay

    def __call__(self, time):
        t = time - self.delay
        psi = (self.amp*
            (2./(numpy.sqrt(3.*self.std)*(numpy.pi**0.25)))*
            (1. - (t**2)/(self.std**2))*
            numpy.exp(-(t**2)/(2.*self.std**2)))
        return psi

    def coords(self):
        """
        Get the i,j coordinates of the source in the finite difference grid.

        Returns:

        * (i,j) : tuple
            The i,j coordinates

        """
        return (self.i, self.j)

def lame(pvel, svel, dens):
    r"""
    Calculate the Lame constants :math:`\lambda` and :math:`\mu` from the
    P and S wave velocities (:math:`\alpha` and :math:`\beta`) and the density
    (:math:`\rho`).

    .. math::

        \mu = \beta^2 \rho

    .. math::

        \lambda = \alpha^2 \rho - 2\mu

    Parameters:

    * pvel : float or array
        The P wave velocity
    * svel : float or array
        The S wave velocity
    * dens : float or array
        The density

    Returns:

    * [lambda, mu] : floats or arrays
        The Lame constants

    Examples::

        >>> print lame(2000, 1000, 2700)
        (5400000000, 2700000000)
        >>> import numpy as np
        >>> pv = np.array([2000, 3000])
        >>> sv = np.array([1000, 1700])
        >>> dens = np.array([2700, 3100])
        >>> lamb, mu = lame(pv, sv, dens)
        >>> print lamb
        [5400000000 9982000000]
        >>> print mu
        [2700000000 8959000000]

    """
    mu = dens*svel**2
    lamb = dens*pvel**2 - 2*mu
    return lamb, mu

def elastic_sh(spacing, shape, mu, dens, deltat, iterations, sources):
    """
    Simulate SH waves using an explicit finite differences scheme.

    Parameters:

    * spacing : (dz, dx)
        The node spacing of the finite differences grid
    * shape : (nz, nx)
        The number of nodes in the grid in the z and x directions
    * mu : 2D-array (shape = *shape*)
        The value of the mu Lame constant at all the grid nodes
    * dens : 2D-array (shape = *shape*)
        The value of the density at all the grid nodes
    * deltat : float
        The time interval between iterations
    * iterations : int
        Number of time steps to take
    * sources : list
        A list of the sources of waves
        (see :class:`~fatiando.seis.wavefd2d.MexHatSource` for an example
        source)

    Yields:

    * uy : 2D-array
        The particle movement in the y direction at each time step

    """
    u_tm1 = numpy.zeros(shape)
    u_t = numpy.zeros(shape)
    u_tp1 = numpy.zeros(shape)

def elastic_psv():
    """
    """
    pass
<commit_msg>Code for elastic SH waves. Not tested<commit_after>r"""
Finite difference solution of the 2D wave equation for isotropic media.

Simulates both elastic and acoustic waves:

* :func:`~fatiando.seis.wavefd2d.elastic_psv`: Simulates the coupled P and SV
  elastic waves
* :func:`~fatiando.seis.wavefd2d.elastic_sh`: Simulates SH elastic waves

**Auxiliary function**

* :func:`~fatiando.seis.wavefd2d.lame`: Calculate the Lame constants from P and
  S wave velocities and density

**Sources**

* :class:`~fatiando.seis.wavefd2d.MexHatSource`: Mexican hat wavelet source

**Theory**

We start with the wave equation for elastic isotropic media

.. math::

    (\lambda + \mu)\nabla(\nabla\cdot\mathbf{u})
    +
    \mu\nabla^2\mathbf{u}
    - \rho \partial_t^2 \mathbf{u} = - \mathbf{f}

where :math:`\mathbf{u} = (u_x, u_y, y_z)` is the particle movement vector,
:math:`\rho` is the density,
:math:`\lambda` and :math:`\mu` are the Lame constants,
and :math:`\mathbf{f}` is the source vector.

In the 2D approximation, we assume all derivatives in the y direction
are zero and consider only x and z coordinates
(though :math:`u_y` remains).
The three equations in the vector equation above can be separated into
two groups:

.. math::

    \mu\left(\partial_x^2 u_y + \partial_z^2 u_y\right)
    - \rho \partial_t^2 u_y = f_y

and

.. math::

    (\lambda + 2\mu)\partial_x^2 u_x + \mu\partial_z^2 u_x
    + (\lambda + \mu)\partial_x\partial_z u_z
    - \rho \partial_t^2 u_x = f_x

.. math::

    (\lambda + 2\mu)\partial_z^2 u_z + \mu\partial_x^2 u_z
    + (\lambda + \mu)\partial_x\partial_z u_x
    - \rho \partial_t^2 u_z = f_z

The first equation depends only on :math:`u_y` and represents SH waves.
The other two depend on :math:`u_x` and :math:`u_z` and are coupled.
They represent P and SV waves.

The explicit finite difference solution for the SH waves is:

.. math::
   :nowrap:

    \begin{align*}
        u_y[i,j]_{t+1} =& 2u_y[i,j]_{t} - u_y[i,j]_{t-1}
        + \frac{\Delta t^2}{\rho[i,j]}
        \left[
            -f_y[i,j]_t +
            \mu[i,j]
                \left(
                    \frac{u_y[i+1,j]_{t} - 2u_y[i,j]_{t} + u_y[i-1,j]_{t}}{
                        \Delta x^2}
                \right.
        \right.
        \\[0.3cm] &
        \left.
            \left.
                +
                \frac{u_y[i,j+1]_{t} - 2u_y[i,j]_{t} + u_y[i,j-1]_{t}}{\Delta z^2}
            \right)
        \right]
    \end{align*}

where :math:`[i,j]_t` is the quantity at the grid node i,j at a
time t.

The solution for P and SV waves is:

.. math::
   :nowrap:

    \begin{align*}
    u_x[i,j]_{t+1} =& 2u_x[i,j]_{t} - u_x[i,j]_{t-1}
    \\&
    + \frac{\Delta t^2}{\rho[i,j]}
    \left\lbrace
        -f_x[i,j]_{t} +
        (\lambda[i,j] + 2\mu[i,j])
        \left(
            \frac{u_x[i+1,j]_{t} - 2u_x[i,j]_{t} + u_x[i-1,j]_{t}}{
                \Delta x^2}
        \right)
    \right.
    \\[0.3cm]&
        +
        \mu[i,j]
        \left(
            \frac{u_x[i,j+1]_{t} - 2u_x[i,j]_{t} + u_x[i,j-1]_{t}}{
                \Delta z^2}
        \right)
    \\[0.3cm]&
    \left.
        +
        (\lambda[i,j] + \mu[i,j])
        \left(
            \frac{u_z[i,j]_{t} - u_z[i-1,j]_{t} - u_z[i,j-1]_{t} +
            u_z[i-1,j-1]_{t}
            }{\Delta x\Delta z}
        \right)
    \right\rbrace
    \end{align*}

.. math::
   :nowrap:

    \begin{align*}
    u_z[i,j]_{t+1} =& 2u_z[i,j]_{t} - u_z[i,j]_{t-1}
    \\&
    + \frac{\Delta t^2}{\rho[i,j]}
    \left\lbrace
        -f_z[i,j]_{t} +
        (\lambda[i,j] + 2\mu[i,j])
        \left(
            \frac{u_z[i,j+1]_{t} - 2u_z[i,j]_{t} + u_z[i,j-1]_{t}}{
                \Delta z^2}
        \right)
    \right.
    \\[0.3cm]&
        +
        \mu[i,j]
        \left(
            \frac{u_z[i+1,j]_{t} - 2u_z[i,j]_{t} + u_z[i-1,j]_{t}}{
                \Delta x^2}
        \right)
    \\[0.3cm]&
    \left.
        +
        (\lambda[i,j] + \mu[i,j])
        \left(
            \frac{u_x[i,j]_{t} - u_x[i-1,j]_{t} - u_x[i,j-1]_{t} +
            u_x[i-1,j-1]_{t}
            }{\Delta x\Delta z}
        \right)
    \right\rbrace
    \end{align*}

----

"""
import numpy

import fatiando.log

log = fatiando.log.dummy('fatiando.seis.wavefd2d')

class MexHatSource(object):
    r"""
    A wave source that vibrates as a mexicam hat (Ricker) wavelet.

    .. math::

        \psi(t) = A\frac{2}{\sqrt{3\sigma}\pi^{\frac{1}{4}}}
        \left( 1 - \frac{t^2}{\sigma^2} \right)
        \exp\left(\frac{-t^2}{2\sigma^2}\right)

    Parameters:

    * i, j : int
        The i,j coordinates of the source in the target finite difference grid.
        i is the index for z, j for x

        .. warning:: Don't put sources in the boundaries of the grid!

    * amp : float
        The amplitude of the source (:math:`A`)
    * std : float
        The "wave length" (:math:`\sigma`)
    * delay : float
        The delay before the source starts

        .. note:: If you want the source to start with amplitude close to 0, use
            ``delay = 3.5*std``.

    """

    def __init__(self, i, j, amp, std, delay=0):
        self.i = i
        self.j = j
        self.amp = amp
        self.std = std
        self.delay = delay

    def __call__(self, time):
        t = time - self.delay
        psi = (self.amp*
            (2./(numpy.sqrt(3.*self.std)*(numpy.pi**0.25)))*
            (1. - (t**2)/(self.std**2))*
            numpy.exp(-(t**2)/(2.*self.std**2)))
        return psi

    def coords(self):
        """
        Get the i,j coordinates of the source in the finite difference grid.

        Returns:

        * (i,j) : tuple
            The i,j coordinates

        """
        return (self.i, self.j)

def lame(pvel, svel, dens):
    r"""
    Calculate the Lame constants :math:`\lambda` and :math:`\mu` from the
    P and S wave velocities (:math:`\alpha` and :math:`\beta`) and the density
    (:math:`\rho`).

    .. math::

        \mu = \beta^2 \rho

    .. math::

        \lambda = \alpha^2 \rho - 2\mu

    Parameters:

    * pvel : float or array
        The P wave velocity
    * svel : float or array
        The S wave velocity
    * dens : float or array
        The density

    Returns:

    * [lambda, mu] : floats or arrays
        The Lame constants

    Examples::

        >>> print lame(2000, 1000, 2700)
        (5400000000, 2700000000)
        >>> import numpy as np
        >>> pv = np.array([2000, 3000])
        >>> sv = np.array([1000, 1700])
        >>> dens = np.array([2700, 3100])
        >>> lamb, mu = lame(pv, sv, dens)
        >>> print lamb
        [5400000000 9982000000]
        >>> print mu
        [2700000000 8959000000]

    """
    mu = dens*svel**2
    lamb = dens*pvel**2 - 2*mu
    return lamb, mu

def elastic_sh(spacing, shape, mu, dens, deltat, iterations, sources):
    """
    Simulate SH waves using an explicit finite differences scheme.

    Parameters:

    * spacing : (dz, dx)
        The node spacing of the finite differences grid
    * shape : (nz, nx)
        The number of nodes in the grid in the z and x directions
    * mu : 2D-array (shape = *shape*)
        The value of the mu Lame constant at all the grid nodes
    * dens : 2D-array (shape = *shape*)
        The value of the density at all the grid nodes
    * deltat : float
        The time interval between iterations
    * iterations : int
        Number of time steps to take
    * sources : list
        A list of the sources of waves
        (see :class:`~fatiando.seis.wavefd2d.MexHatSource` for an example
        source)

    Yields:

    * uy : 2D-array
        The particle movement in the y direction at each time step

    """
    nz, nx = shape
    dz, dx = spacing
    dt_sqr = deltat**2
    dx_sqr = dx**2
    dz_sqr = dz**2
    u_tm1 = numpy.zeros(shape)
    u_t = numpy.zeros(shape)
    u_tp1 = numpy.zeros(shape)
    for src in sources:
        u_t[src.coords()] = src(0)
    for t in xrange(iterations - 1):
        for i in xrange(nz):
            for j in xrange(nx):
                u_tp1[i,j] = 2.*u_t[i,j] - u_tm1[i,j] + dt_sqr/dens[i,j]*(
                    (u_t[i + 1,j] - 2.*u_t[i,j] + u_t[i - 1,j])/dz_sqr +
                    (u_t[i,j + 1] - 2.*u_t[i,j] + u_t[i,j - 1])/dx_sqr)
        # Update the sources
        for src in sources:
            pos = src.coords()
            u_tp1[pos] -= (dt_sqr/dens[pos])*src(t*deltat)
        # Set the boundary conditions
        u_tp1[0,:] = u_tp1[1,:]
        u_tp1[-1,:] = 0
        u_tp1[:,0] = 0
        u_tp1[:,-1] = 0

        yield u_tp1

        u_tm1 = u_t
        u_t = u_tp1

def elastic_psv():
    """
    """
    pass
<|endoftext|>


<commit_before>#!/usr/bin/env python3
#
# gpgsign.py - part of the FDroid server tools
# Copyright (C) 2015, Ciaran Gultnieks, ciaran@ciarang.com
#
# 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/>.

import os
import zipfile
from argparse import ArgumentParser
import logging

from . import _
from . import common
from .exception import FDroidException

config = None
options = None

def sign_jar(jar):
    """
    Sign a JAR file with Java's jarsigner.

    This method requires a properly initialized config object.

    This does use old hashing algorithms, i.e. SHA1, but that's not
    broken yet for file verification.  This could be set to SHA256,
    but then Android < 4.3 would not be able to verify it.
    https://code.google.com/p/android/issues/detail?id=38321
    """
    args = [config['jarsigner'], '-keystore', config['keystore'],
            '-storepass:env', 'FDROID_KEY_STORE_PASS',
            '-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA',
            jar, config['repo_keyalias']]
    if config['keystore'] == 'NONE':
        args += config['smartcardoptions']
    else:  # smardcards never use -keypass
        args += ['-keypass:env', 'FDROID_KEY_PASS']
    env_vars = {
        'FDROID_KEY_STORE_PASS': config['keystorepass'],
        'FDROID_KEY_PASS': config['keypass'],
    }
    p = common.FDroidPopen(args, envs=env_vars)
    if p.returncode != 0:
        raise FDroidException("Failed to sign %s!" % jar)

def sign_index_v1(repodir, json_name):
    """
    Sign index-v1.json to make index-v1.jar

    This is a bit different than index.jar: instead of their being index.xml
    and index_unsigned.jar, the presence of index-v1.json means that there is
    unsigned data.  That file is then stuck into a jar and signed by the
    signing process.  index-v1.json is never published to the repo.  It is
    included in the binary transparency log, if that is enabled.
    """
    name, ext = common.get_extension(json_name)
    index_file = os.path.join(repodir, json_name)
    jar_file = os.path.join(repodir, name + '.jar')
    with zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED) as jar:
        jar.write(index_file, json_name)
    sign_jar(jar_file)

def main():

    global config, options

    # Parse command line...
    parser = ArgumentParser(usage="%(prog)s [options]")
    common.setup_global_opts(parser)
    options = parser.parse_args()

    config = common.read_config(options)

    if 'jarsigner' not in config:
        raise FDroidException(
            _('Java jarsigner not found! Install in standard location or set java_paths!'))

    repodirs = ['repo']
    if config['archive_older'] != 0:
        repodirs.append('archive')

    signed = 0
    for output_dir in repodirs:
        if not os.path.isdir(output_dir):
            raise FDroidException("Missing output directory '" + output_dir + "'")

        unsigned = os.path.join(output_dir, 'index_unsigned.jar')
        if os.path.exists(unsigned):
            sign_jar(unsigned)
            os.rename(unsigned, os.path.join(output_dir, 'index.jar'))
            logging.info('Signed index in ' + output_dir)
            signed += 1

        json_name = 'index-v1.json'
        index_file = os.path.join(output_dir, json_name)
        if os.path.exists(index_file):
            sign_index_v1(output_dir, json_name)
            os.remove(index_file)
            logging.info('Signed ' + index_file)
            signed += 1

    if signed == 0:
        logging.info(_("Nothing to do"))

if __name__ == "__main__":
    main()
<commit_msg>signindex: write status JSON<commit_after>#!/usr/bin/env python3
#
# gpgsign.py - part of the FDroid server tools
# Copyright (C) 2015, Ciaran Gultnieks, ciaran@ciarang.com
#
# 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/>.

import os
import time
import zipfile
from argparse import ArgumentParser
import logging

from . import _
from . import common
from .exception import FDroidException

config = None
options = None
start_timestamp = time.gmtime()

def sign_jar(jar):
    """
    Sign a JAR file with Java's jarsigner.

    This method requires a properly initialized config object.

    This does use old hashing algorithms, i.e. SHA1, but that's not
    broken yet for file verification.  This could be set to SHA256,
    but then Android < 4.3 would not be able to verify it.
    https://code.google.com/p/android/issues/detail?id=38321
    """
    args = [config['jarsigner'], '-keystore', config['keystore'],
            '-storepass:env', 'FDROID_KEY_STORE_PASS',
            '-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA',
            jar, config['repo_keyalias']]
    if config['keystore'] == 'NONE':
        args += config['smartcardoptions']
    else:  # smardcards never use -keypass
        args += ['-keypass:env', 'FDROID_KEY_PASS']
    env_vars = {
        'FDROID_KEY_STORE_PASS': config['keystorepass'],
        'FDROID_KEY_PASS': config['keypass'],
    }
    p = common.FDroidPopen(args, envs=env_vars)
    if p.returncode != 0:
        raise FDroidException("Failed to sign %s!" % jar)

def sign_index_v1(repodir, json_name):
    """
    Sign index-v1.json to make index-v1.jar

    This is a bit different than index.jar: instead of their being index.xml
    and index_unsigned.jar, the presence of index-v1.json means that there is
    unsigned data.  That file is then stuck into a jar and signed by the
    signing process.  index-v1.json is never published to the repo.  It is
    included in the binary transparency log, if that is enabled.
    """
    name, ext = common.get_extension(json_name)
    index_file = os.path.join(repodir, json_name)
    jar_file = os.path.join(repodir, name + '.jar')
    with zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED) as jar:
        jar.write(index_file, json_name)
    sign_jar(jar_file)

def status_update_json(signed):
    """Output a JSON file with metadata about this run"""

    logging.debug(_('Outputting JSON'))
    output = common.setup_status_output(start_timestamp)
    if signed:
        output['signed'] = signed
    common.write_status_json(output)

def main():

    global config, options

    # Parse command line...
    parser = ArgumentParser(usage="%(prog)s [options]")
    common.setup_global_opts(parser)
    options = parser.parse_args()

    config = common.read_config(options)

    if 'jarsigner' not in config:
        raise FDroidException(
            _('Java jarsigner not found! Install in standard location or set java_paths!'))

    repodirs = ['repo']
    if config['archive_older'] != 0:
        repodirs.append('archive')

    signed = []
    for output_dir in repodirs:
        if not os.path.isdir(output_dir):
            raise FDroidException("Missing output directory '" + output_dir + "'")

        unsigned = os.path.join(output_dir, 'index_unsigned.jar')
        if os.path.exists(unsigned):
            sign_jar(unsigned)
            index_jar = os.path.join(output_dir, 'index.jar')
            os.rename(unsigned, index_jar)
            logging.info('Signed index in ' + output_dir)
            signed.append(index_jar)

        json_name = 'index-v1.json'
        index_file = os.path.join(output_dir, json_name)
        if os.path.exists(index_file):
            sign_index_v1(output_dir, json_name)
            os.remove(index_file)
            logging.info('Signed ' + index_file)
            signed.append(index_file)

    if not signed:
        logging.info(_("Nothing to do"))
    status_update_json(signed)

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