<commit_before>"""setuptools-based installation script.

File is based on this template: https://github.com/pypa/sampleproject
"""

import os
import sys
import unittest
# Always prefer setuptools over distutils
from setuptools import find_packages
from setuptools import setup

_DEPENDENCIES = [
    # dependencies for dsub, ddel, dstat
    'google-api-python-client',
    'google-auth',
    'python-dateutil',
    'pytz',
    'pyyaml<=5.2',
    'retrying',
    'six',
    'tabulate',

    # dependencies for test code
    'parameterized',
    'mock',
]

if sys.version_info[0] == 2:
  _DEPENDENCIES.append('cachetools==3.1.1')

def unittest_suite():
  """Get test suite (Python unit tests only)."""
  test_loader = unittest.TestLoader()
  test_suite = test_loader.discover('test/unit', pattern='test_*.py')
  return test_suite

def get_dsub_version():
  """Get the dsub version out of the _dsub_version.py source file.

  Setup.py should not import dsub version from dsub directly since ambiguity in
  import order could lead to an old version of dsub setting the version number.
  Parsing the file directly is simpler than using import tools (whose interface
  varies between python 2.7, 3.4, and 3.5).

  Returns:
    string of dsub version.

  Raises:
    ValueError: if the version is not found.
  """
  filename = os.path.join(os.path.dirname(__file__), 'dsub/_dsub_version.py')
  with open(filename, 'r') as versionfile:
    for line in versionfile:
      if line.startswith('DSUB_VERSION ='):
        # Get the version then strip whitespace and quote characters.
        version = line.partition('=')[2]
        return version.strip().strip('\'"')
  raise ValueError('Could not find version.')

def get_readme_contents():
  """Get the README.md contents."""
  with open('README.md', 'r') as f:
    return f.read()

setup(
    name='dsub',

    # Versions should comply with PEP440.
    version=get_dsub_version(),
    description=('A command-line tool that makes it easy to submit and run'
                 ' batch scripts in the cloud'),
    long_description=get_readme_contents(),
    long_description_content_type='text/markdown',

    # The project's main homepage.
    url='https://github.com/DataBiosphere/dsub',

    # Author details
    author='Verily',
    # Choose your license
    license='Apache',
    # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
    classifiers=[
        # How mature is this project? Common values are
        #   3 - Alpha
        #   4 - Beta
        #   5 - Production/Stable
        'Development Status :: 3 - Alpha',

        # Indicate who your project is intended for
        'Intended Audience :: Developers',
        'Topic :: Scientific/Engineering :: Bio-Informatics',
        'Topic :: Scientific/Engineering :: Information Analysis',
        'Topic :: System :: Distributed Computing',

        # Pick your license as you wish (should match "license" above)
        'License :: OSI Approved :: Apache Software License',

        # Specify the Python versions you support here. In particular, ensure
        # that you indicate whether you support Python 2, Python 3 or both.
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
    ],

    # What does your project relate to?
    keywords='cloud bioinformatics',

    # Packages to distribute.
    packages=find_packages(),
    include_package_data=True,

    # List run-time dependencies here.  These will be installed by pip when
    # your project is installed.
    install_requires=_DEPENDENCIES,

    # Define a test suite for Python unittests only.
    test_suite='setup.unittest_suite',

    # Provide executable scripts - these will be added to the user's path.
    entry_points={
        'console_scripts': [
            'dsub=dsub.commands.dsub:main',
            'dstat=dsub.commands.dstat:main',
            'ddel=dsub.commands.ddel:main',
        ],
    },
)
<commit_msg>Pin all dsub dependencies to a max version. This prevents episodic breakages caused by updates to dependent packages.<commit_after>"""setuptools-based installation script.

File is based on this template: https://github.com/pypa/sampleproject
"""

import os
import sys
import unittest
# Always prefer setuptools over distutils
from setuptools import find_packages
from setuptools import setup

_DEPENDENCIES = [
    # dependencies for dsub, ddel, dstat
    # Pin to known working versions to prevent episodic breakage from library
    # version mismatches.
    # This version list generated: 01/10/2020

    # direct dependencies
    'google-api-python-client<=1.7.11',
    'google-auth<=1.10.0',
    'python-dateutil<=2.8.1',
    'pytz<=2019.3',
    'pyyaml<=5.2',
    'retrying<=1.3.3',
    'six<=1.13.0',
    'tabulate<=0.8.6',

    # downstream dependencies
    'funcsigs<=1.0.2',
    'google-auth-httplib2<=0.0.3',
    'httplib2<=0.15.0',
    'pyasn1<=0.4.8',
    'pyasn1-modules<=0.2.8',
    'rsa<=4.0',
    'uritemplate<=3.0.1',

    # dependencies for test code
    'parameterized<=0.7.1',
    'mock<=3.0.5',
]

if sys.version_info[0] == 2:
  _DEPENDENCIES.append('cachetools==3.1.1')

def unittest_suite():
  """Get test suite (Python unit tests only)."""
  test_loader = unittest.TestLoader()
  test_suite = test_loader.discover('test/unit', pattern='test_*.py')
  return test_suite

def get_dsub_version():
  """Get the dsub version out of the _dsub_version.py source file.

  Setup.py should not import dsub version from dsub directly since ambiguity in
  import order could lead to an old version of dsub setting the version number.
  Parsing the file directly is simpler than using import tools (whose interface
  varies between python 2.7, 3.4, and 3.5).

  Returns:
    string of dsub version.

  Raises:
    ValueError: if the version is not found.
  """
  filename = os.path.join(os.path.dirname(__file__), 'dsub/_dsub_version.py')
  with open(filename, 'r') as versionfile:
    for line in versionfile:
      if line.startswith('DSUB_VERSION ='):
        # Get the version then strip whitespace and quote characters.
        version = line.partition('=')[2]
        return version.strip().strip('\'"')
  raise ValueError('Could not find version.')

def get_readme_contents():
  """Get the README.md contents."""
  with open('README.md', 'r') as f:
    return f.read()

setup(
    name='dsub',

    # Versions should comply with PEP440.
    version=get_dsub_version(),
    description=('A command-line tool that makes it easy to submit and run'
                 ' batch scripts in the cloud'),
    long_description=get_readme_contents(),
    long_description_content_type='text/markdown',

    # The project's main homepage.
    url='https://github.com/DataBiosphere/dsub',

    # Author details
    author='Verily',
    # Choose your license
    license='Apache',
    # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
    classifiers=[
        # How mature is this project? Common values are
        #   3 - Alpha
        #   4 - Beta
        #   5 - Production/Stable
        'Development Status :: 3 - Alpha',

        # Indicate who your project is intended for
        'Intended Audience :: Developers',
        'Topic :: Scientific/Engineering :: Bio-Informatics',
        'Topic :: Scientific/Engineering :: Information Analysis',
        'Topic :: System :: Distributed Computing',

        # Pick your license as you wish (should match "license" above)
        'License :: OSI Approved :: Apache Software License',

        # Specify the Python versions you support here. In particular, ensure
        # that you indicate whether you support Python 2, Python 3 or both.
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
    ],

    # What does your project relate to?
    keywords='cloud bioinformatics',

    # Packages to distribute.
    packages=find_packages(),
    include_package_data=True,

    # List run-time dependencies here.  These will be installed by pip when
    # your project is installed.
    install_requires=_DEPENDENCIES,

    # Define a test suite for Python unittests only.
    test_suite='setup.unittest_suite',

    # Provide executable scripts - these will be added to the user's path.
    entry_points={
        'console_scripts': [
            'dsub=dsub.commands.dsub:main',
            'dstat=dsub.commands.dstat:main',
            'ddel=dsub.commands.ddel:main',
        ],
    },
)
<|endoftext|>


<commit_before>#!/usr/bin/env python
from setuptools import setup, find_packages

setup(
    name="uscensus",
    version="0.1.8",
    packages=find_packages(),
    description="US Census API discovery wrappers",
    long_description="""This module fetches metadata for the Census Data API to make it easier to find relevant data sets and variables to query, and returns data as a Pandas dataframe.""",
    license="Apache Software License 2.0",
    keywords="census demographics economics data api discovery",
    url="https://github.com/nkrishnaswami/uscensus",

    test_suite='nose.collector',
    tests_require=['nose'],

    install_requires=[
        'docutils>=0.3',
        'python-dateutil',
        'fiona',
        'geopandas',
        'gevent',
        'grequests',
        'numpy',
        'pandas',
        'pymongo',
        'pytz',
        'requests',
        'shapely',
        'sqlalchemy',
        'whoosh',
    ],

    author="Natarajan Krishnaswami",
    author_email="nkrish@acm.org",
    classifiers=[
        'Development Status :: 3 - Alpha',
        'Intended Audience :: Developers',
        'Intended Audience :: Science/Research',
        'License :: OSI Approved :: Apache Software License',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Topic :: Sociology',
        'Topic :: Scientific/Engineering :: GIS',
    ],
)
<commit_msg>Bump version<commit_after>#!/usr/bin/env python
from setuptools import setup, find_packages

setup(
    name="uscensus",
    version="0.1.9",
    packages=find_packages(),
    description="US Census API discovery wrappers",
    long_description="""This module fetches metadata for the Census Data API to make it easier to find relevant data sets and variables to query, and returns data as a Pandas dataframe.""",
    license="Apache Software License 2.0",
    keywords="census demographics economics data api discovery",
    url="https://github.com/nkrishnaswami/uscensus",

    test_suite='nose.collector',
    tests_require=['nose'],

    install_requires=[
        'docutils>=0.3',
        'python-dateutil',
        'fiona',
        'geopandas',
        'gevent',
        'grequests',
        'numpy',
        'pandas',
        'pymongo',
        'pytz',
        'requests',
        'shapely',
        'sqlalchemy',
        'whoosh',
    ],

    author="Natarajan Krishnaswami",
    author_email="nkrish@acm.org",
    classifiers=[
        'Development Status :: 3 - Alpha',
        'Intended Audience :: Developers',
        'Intended Audience :: Science/Research',
        'License :: OSI Approved :: Apache Software License',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Topic :: Sociology',
        'Topic :: Scientific/Engineering :: GIS',
    ],
)
<|endoftext|>


<commit_before>import pip
from setuptools import setup

description = (
    'Generalized reactive(1) synthesis from Promela specifications.')
README = 'README.md'
VERSION_FILE = 'openpromela/_version.py'
MAJOR = 0
MINOR = 0
MICRO = 1
version = '{major}.{minor}.{micro}'.format(
    major=MAJOR, minor=MINOR, micro=MICRO)
s = (
    '# This file was generated from setup.py\n'
    "version = '{version}'\n").format(version=version)

def build_parser_table():
    from openpromela import logic
    tabmodule = logic.TABMODULE.split('.')[-1]
    outputdir = 'openpromela/'
    parser = logic.Parser()
    parser.build(tabmodule, outputdir=outputdir, write_tables=True)

if __name__ == '__main__':
    with open(VERSION_FILE, 'w') as f:
        f.write(s)
    pip.main([
        'install',
        'psutil >= 2.2.0',
        'humanize >= 0.5.1'])
    build_parser_table()
    setup(
        name='openpromela',
        version=version,
        description=description,
        long_description=open(README).read(),
        author='Ioannis Filippidis',
        author_email='jfilippidis@gmail.com',
        url='https://github.com/johnyf/openpromela',
        license='BSD',
        install_requires=[
            'promela >= 0.0.1',
            'networkx >= 1.9.1',
            'psutil >= 2.2.0'],
        tests_require=['nose'],
        packages=['openpromela'],
        package_dir={'openpromela': 'openpromela'},
        entry_points={
            'console_scripts':
                ['ospin = openpromela.logic:command_line_wrapper']})
<commit_msg>install all requirements before building the parser<commit_after>import pip
from setuptools import setup

description = (
    'Generalized reactive(1) synthesis from Promela specifications.')
README = 'README.md'
VERSION_FILE = 'openpromela/_version.py'
MAJOR = 0
MINOR = 0
MICRO = 1
version = '{major}.{minor}.{micro}'.format(
    major=MAJOR, minor=MINOR, micro=MICRO)
s = (
    '# This file was generated from setup.py\n'
    "version = '{version}'\n").format(version=version)
install_requires = [
    'dd >= 0.0.3',
    'humanize >= 0.5.1',
    'natsort >= 3.5.3',
    'networkx >= 1.9.1',
    'omega >= 0.0.1',
    'ply == 3.4',
    'promela >= 0.0.1',
    'psutil >= 2.2.0',
    'subprocess32 >= 3.2.6']

def build_parser_table():
    from openpromela import logic
    tabmodule = logic.TABMODULE.split('.')[-1]
    outputdir = 'openpromela/'
    parser = logic.Parser()
    parser.build(tabmodule, outputdir=outputdir, write_tables=True)

if __name__ == '__main__':
    with open(VERSION_FILE, 'w') as f:
        f.write(s)
    pip.main(['install'] + install_requires)
    build_parser_table()
    setup(
        name='openpromela',
        version=version,
        description=description,
        long_description=open(README).read(),
        author='Ioannis Filippidis',
        author_email='jfilippidis@gmail.com',
        url='https://github.com/johnyf/openpromela',
        license='BSD',
        install_requires=install_requires,
        tests_require=['nose'],
        packages=['openpromela'],
        package_dir={'openpromela': 'openpromela'},
        entry_points={
            'console_scripts':
                ['ospin = openpromela.logic:command_line_wrapper']})
<|endoftext|>


<commit_before>from setuptools import setup, find_packages

setup(
    name="page_object",
    version="0.0.2",
    description='PageObject pattern python implementation',
    packages=find_packages('src'),
    package_dir={'': 'src'},

    install_requires=[
        'pyvirtualdisplay==0.2',
        'selenium==2.53.6'
    ]
)
<commit_msg>Bumped to v0.0.4<commit_after>from setuptools import setup, find_packages

setup(
    name="page_object",
    version="0.0.4",
    description='PageObject pattern python implementation',
    packages=find_packages('src'),
    package_dir={'': 'src'},

    install_requires=[
        'pyvirtualdisplay==0.2',
        'selenium==2.53.6'
    ]
)
<|endoftext|>


<commit_before>from distutils.core import setup

setup(name='cauldron',
      version='1.0.1',
      author='Ankit Chandawala',
      author_email='ankitchandawala@gmail.com',
      url='https://github.com/nerandell/cauldron',
      description='Utils to reduce boilerplate code',
      packages=['cauldron'], install_requires=['aiopg'])
<commit_msg>Bumping up version number<commit_after>from distutils.core import setup

setup(name='cauldron',
      version='1.0.2',
      author='Ankit Chandawala',
      author_email='ankitchandawala@gmail.com',
      url='https://github.com/nerandell/cauldron',
      description='Utils to reduce boilerplate code',
      packages=['cauldron'], install_requires=['aiopg'])
<|endoftext|>


<commit_before>#!/usr/bin/env python
# Licensed under a 3-clause BSD style license - see LICENSE.rst

import glob
import os
import sys

#import ah_bootstrap
from setuptools import setup

#A dirty hack to get around some early import/configurations ambiguities
if sys.version_info[0] >= 3:
    import builtins
else:
    import __builtin__ as builtins
builtins._ASTROPY_SETUP_ = True

from astropy_helpers.setup_helpers import (
    register_commands, adjust_compiler, get_debug_option, get_package_info)
from astropy_helpers.git_helpers import get_git_devstr
from astropy_helpers.version_helpers import generate_version_py

# Get some values from the setup.cfg
try:
    from ConfigParser import ConfigParser
except ImportError:
    from configparser import ConfigParser

conf = ConfigParser()

conf.read(['setup.cfg'])
metadata = dict(conf.items('metadata'))

PACKAGENAME = metadata.get('package_name', 'packagename')
DESCRIPTION = metadata.get('description', 'Astropy affiliated package')
AUTHOR = metadata.get('author', '')
AUTHOR_EMAIL = metadata.get('author_email', '')
LICENSE = metadata.get('license', 'unknown')
URL = metadata.get('url', 'http://astropy.org')

# Get the long description from the package's docstring
__import__(PACKAGENAME)
package = sys.modules[PACKAGENAME]
LONG_DESCRIPTION = package.__doc__

# Store the package name in a built-in variable so it's easy
# to get from other parts of the setup infrastructure
builtins._ASTROPY_PACKAGE_NAME_ = PACKAGENAME

# VERSION should be PEP386 compatible (http://www.python.org/dev/peps/pep-0386)
VERSION = '0.4.8.dev'

# Indicates if this version is a release version
RELEASE = 'dev' not in VERSION

if not RELEASE:
    VERSION += get_git_devstr(False)

# Populate the dict of setup command overrides; this should be done before
# invoking any other functionality from distutils since it can potentially
# modify distutils' behavior.
cmdclassd = register_commands(PACKAGENAME, VERSION, RELEASE)

# Freeze build information in version.py
generate_version_py(PACKAGENAME, VERSION, RELEASE,
                    get_debug_option(PACKAGENAME))

# Treat everything in scripts except README.rst as a script to be installed
scripts = [fname for fname in glob.glob(os.path.join('scripts', '*'))
           if os.path.basename(fname) != 'README.rst']

# Get configuration information from all of the various subpackages.
# See the docstring for setup_helpers.update_package_files for more
# details.
package_info = get_package_info()

# Add the project-global data
package_info['package_data'].setdefault(PACKAGENAME, [])
package_info['package_data'][PACKAGENAME].append('data/*.*')
package_info['package_data'][PACKAGENAME].append('data/template-build-files/*.*')
package_info['package_data'][PACKAGENAME].append('data/template-build-files/.*')
package_info['package_data'][PACKAGENAME].append('data/template-build-files/recipe-templates/aplpy/*.*')

# Package now included as part of MANIFEST.in

# Define entry points for command-line scripts
entry_points = {'console_scripts': []}

entry_point_list = conf.items('entry_points')
for entry_point in entry_point_list:
    entry_points['console_scripts'].append('{0} = {1}'.format(entry_point[0],
                                                              entry_point[1]))

# Include all .c files, recursively, including those generated by
# Cython, since we can not do this in MANIFEST.in with a "dynamic"
# directory name.
c_files = []
for root, dirs, files in os.walk(PACKAGENAME):
    for filename in files:
        if filename.endswith('.c'):
            c_files.append(
                os.path.join(
                    os.path.relpath(root, PACKAGENAME), filename))
package_info['package_data'][PACKAGENAME].extend(c_files)

# Note that requires and provides should not be included in the call to
# ``setup``, since these are now deprecated. See this link for more details:
# https://groups.google.com/forum/#!topic/astropy-dev/urYO8ckB2uM

setup(name=PACKAGENAME,
      version=VERSION,
      description=DESCRIPTION,
      scripts=scripts,
      install_requires=['jinja2', 'ruamel.yaml'],
      author=AUTHOR,
      author_email=AUTHOR_EMAIL,
      license=LICENSE,
      url=URL,
      long_description=LONG_DESCRIPTION,
      cmdclass=cmdclassd,
      zip_safe=False,
      use_2to3=True,
      entry_points=entry_points,
      **package_info
)
<commit_msg>Version 0.4.8<commit_after>#!/usr/bin/env python
# Licensed under a 3-clause BSD style license - see LICENSE.rst

import glob
import os
import sys

#import ah_bootstrap
from setuptools import setup

#A dirty hack to get around some early import/configurations ambiguities
if sys.version_info[0] >= 3:
    import builtins
else:
    import __builtin__ as builtins
builtins._ASTROPY_SETUP_ = True

from astropy_helpers.setup_helpers import (
    register_commands, adjust_compiler, get_debug_option, get_package_info)
from astropy_helpers.git_helpers import get_git_devstr
from astropy_helpers.version_helpers import generate_version_py

# Get some values from the setup.cfg
try:
    from ConfigParser import ConfigParser
except ImportError:
    from configparser import ConfigParser

conf = ConfigParser()

conf.read(['setup.cfg'])
metadata = dict(conf.items('metadata'))

PACKAGENAME = metadata.get('package_name', 'packagename')
DESCRIPTION = metadata.get('description', 'Astropy affiliated package')
AUTHOR = metadata.get('author', '')
AUTHOR_EMAIL = metadata.get('author_email', '')
LICENSE = metadata.get('license', 'unknown')
URL = metadata.get('url', 'http://astropy.org')

# Get the long description from the package's docstring
__import__(PACKAGENAME)
package = sys.modules[PACKAGENAME]
LONG_DESCRIPTION = package.__doc__

# Store the package name in a built-in variable so it's easy
# to get from other parts of the setup infrastructure
builtins._ASTROPY_PACKAGE_NAME_ = PACKAGENAME

# VERSION should be PEP386 compatible (http://www.python.org/dev/peps/pep-0386)
VERSION = '0.4.8'

# Indicates if this version is a release version
RELEASE = 'dev' not in VERSION

if not RELEASE:
    VERSION += get_git_devstr(False)

# Populate the dict of setup command overrides; this should be done before
# invoking any other functionality from distutils since it can potentially
# modify distutils' behavior.
cmdclassd = register_commands(PACKAGENAME, VERSION, RELEASE)

# Freeze build information in version.py
generate_version_py(PACKAGENAME, VERSION, RELEASE,
                    get_debug_option(PACKAGENAME))

# Treat everything in scripts except README.rst as a script to be installed
scripts = [fname for fname in glob.glob(os.path.join('scripts', '*'))
           if os.path.basename(fname) != 'README.rst']

# Get configuration information from all of the various subpackages.
# See the docstring for setup_helpers.update_package_files for more
# details.
package_info = get_package_info()

# Add the project-global data
package_info['package_data'].setdefault(PACKAGENAME, [])
package_info['package_data'][PACKAGENAME].append('data/*.*')
package_info['package_data'][PACKAGENAME].append('data/template-build-files/*.*')
package_info['package_data'][PACKAGENAME].append('data/template-build-files/.*')
package_info['package_data'][PACKAGENAME].append('data/template-build-files/recipe-templates/aplpy/*.*')

# Package now included as part of MANIFEST.in

# Define entry points for command-line scripts
entry_points = {'console_scripts': []}

entry_point_list = conf.items('entry_points')
for entry_point in entry_point_list:
    entry_points['console_scripts'].append('{0} = {1}'.format(entry_point[0],
                                                              entry_point[1]))

# Include all .c files, recursively, including those generated by
# Cython, since we can not do this in MANIFEST.in with a "dynamic"
# directory name.
c_files = []
for root, dirs, files in os.walk(PACKAGENAME):
    for filename in files:
        if filename.endswith('.c'):
            c_files.append(
                os.path.join(
                    os.path.relpath(root, PACKAGENAME), filename))
package_info['package_data'][PACKAGENAME].extend(c_files)

# Note that requires and provides should not be included in the call to
# ``setup``, since these are now deprecated. See this link for more details:
# https://groups.google.com/forum/#!topic/astropy-dev/urYO8ckB2uM

setup(name=PACKAGENAME,
      version=VERSION,
      description=DESCRIPTION,
      scripts=scripts,
      install_requires=['jinja2', 'ruamel.yaml'],
      author=AUTHOR,
      author_email=AUTHOR_EMAIL,
      license=LICENSE,
      url=URL,
      long_description=LONG_DESCRIPTION,
      cmdclass=cmdclassd,
      zip_safe=False,
      use_2to3=True,
      entry_points=entry_points,
      **package_info
)
<|endoftext|>


<commit_before>from typing import Callable
from time import sleep, monotonic
from math import ceil
from abc import ABC, abstractmethod
from threading import Lock, Timer, Thread

class RateLimiter(ABC):
    @property
    @abstractmethod
    def permits_issued(self) -> int:
        pass

    @abstractmethod
    def reset_permits_issued(self) -> None:
        pass

    @abstractmethod
    def __enter__(self) -> "RateLimiter":
        pass

    @abstractmethod
    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        pass

    def limit(self, method: Callable) -> Callable:
        def limited(*args, **kwargs):
            with self:
                return method(*args, **kwargs)
        return limited

class MultiRateLimiter(RateLimiter):
    def __init__(self, *limiters: RateLimiter) -> None:
        self._limiters = limiters

        self._total_permits_issued = 0
        self._total_permits_issued_lock = Lock()

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        for limiter in self._limiters:
            limiter.__exit__(exc_type, exc_val, exc_tb)

    def __enter__(self) -> "RateLimiter":
        for limiter in self._limiters:
            limiter.__enter__()

        # Increment total count
        with self._total_permits_issued_lock:
            self._total_permits_issued += 1

        return self

    @property
    def permits_issued(self) -> int:
        with self._total_permits_issued_lock:
            return self._total_permits_issued

    def reset_permits_issued(self) -> None:
        with self._total_permits_issued_lock:
            self._total_permits_issued = 0

class FixedWindowRateLimiter(RateLimiter):
    def __init__(self, window_seconds: int, window_permits: int) -> None:
        self._window_seconds = window_seconds
        self._window_permits = window_permits

        self._total_permits_issued = 0
        self._total_permits_issued_lock = Lock()

        self._permitter = Lock()
        self._permits = window_permits
        self._permits_lock = Lock()

        self._currently_processing = 0
        self._currently_processing_lock = Lock()

        self._resetter = None
        self._resetter_lock = Lock()

    def __enter__(self) -> "FixedWindowRateLimiter":
        # Grab the permit lock and decrement remaining permits. If this leaves it at 0, don't release the permit lock. It will be released by the resetter.
        self._permitter.acquire()
        with self._permits_lock:
            self._permits -= 1
            if self._permits > 0:
                self._permitter.release()

        # Increment total count
        with self._total_permits_issued_lock:
            self._total_permits_issued += 1

        # Increment current count
        with self._currently_processing_lock:
            self._currently_processing += 1

        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        # Decrement current count
        with self._currently_processing_lock:
            self._currently_processing -= 1

        # The fixed window starts after processing the first permit ends. The presence of a resetter indicates whether we're in a fixed window already, or need to start one.
        with self._resetter_lock:
            if not self._resetter:
                self._resetter = Timer(self._window_seconds, self._reset)
                self._resetter.daemon = True
                self._resetter.start()

    def _reset(self):
        with self._permits_lock, self._currently_processing_lock:
            self._permits = self._window_permits - self._currently_processing
            try:
                self._permitter.release()
            except RuntimeError:
                # Wasn't waiting on any acquire
                pass

            with self._resetter_lock:
                self._resetter = None

    @property
    def permits_issued(self) -> int:
        with self._total_permits_issued_lock:
            return self._total_permits_issued

    def reset_permits_issued(self) -> None:
        with self._total_permits_issued_lock:
            self._total_permits_issued = 0

class TokenBucketRateLimiter(RateLimiter):
    def __init__(self, epoch_seconds: int, epoch_permits: int, max_burst: int, token_update_frequency: float) -> None:
        if max_burst < 1 or max_burst > epoch_permits:
            raise ValueError("Max burst must be >= 1 and <= epoch permits!")

        if token_update_frequency <= 0 or token_update_frequency > epoch_seconds:
            raise ValueError("Token update frequency must be > 0 and <= epoch seconds!")

        self._epoch_seconds = epoch_seconds
        self._epoch_permits = epoch_permits

        self._permitter = Lock()
        self._token_limit = max_burst
        self._tokens = max_burst
        self._tokens_lock = Lock()

        self._token_update = token_update_frequency

        self._token_provider = None
        self._token_provider_lock = Lock()

        self._total_permits_issued = 0
        self._total_permits_issued_lock = Lock()

    def __enter__(self) -> "TokenBucketRateLimiter":
        # Grab the permit lock and decrement remaining permits. If this leaves it at 0, don't release the permit lock. It will be released by the resetter.
        self._permitter.acquire()
        with self._tokens_lock:
            self._tokens -= 1
            if self._tokens >= 1:
                self._permitter.release()

        # Increment total count
        with self._total_permits_issued_lock:
            self._total_permits_issued += 1

        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        # We don't want a thread sitting around dumping tokens into a filled bucket during downtimes. We construct one when needed and it cleans itself up if the bucket is full for an entire epoch.
        with self._token_provider_lock:
            if not self._token_provider:
                self._token_provider = Thread(target=self._provide_tokens)
                self._token_provider.daemon = True
                self._token_provider.start()

    def _provide_tokens(self):
        tokens_per_segment = self._epoch_permits / (self._epoch_seconds / self._token_update)
        segments_full = 0

        start_time = monotonic()
        next_time = start_time + self._token_update

        # If we go an entire epoch with a full bucket we'll stop this provider
        segments_per_epoch = int(ceil(self._epoch_seconds / self._token_update))
        while segments_full < segments_per_epoch:
            sleep(max(next_time - monotonic(), 0))
            next_time = next_time + self._token_update

            with self._tokens_lock:
                if self._tokens == self._token_limit:
                    segments_full += 1
                elif self._tokens < 1:
                    self._tokens = min(self._tokens + tokens_per_segment, self._token_limit)
                    segments_full = 0
                    if self._tokens >= 1:
                        try:
                            self._permitter.release()
                        except RuntimeError:
                            # Wasn't waiting on any acquire
                            pass
                else:
                    self._tokens = min(self._tokens + tokens_per_segment, self._token_limit)
                    segments_full = 0

        # Clean up
        with self._token_provider_lock:
            self._token_provider = None

    @property
    def permits_issued(self) -> int:
        with self._total_permits_issued_lock:
            return self._total_permits_issued

    def reset_permits_issued(self) -> None:
        with self._total_permits_issued_lock:
            self._total_permits_issued = 0
<commit_msg>fix race conditions<commit_after>from typing import Callable
from time import sleep, monotonic
from math import ceil
from abc import ABC, abstractmethod
from threading import Lock, Timer, Thread

class RateLimiter(ABC):
    @property
    @abstractmethod
    def permits_issued(self) -> int:
        pass

    @abstractmethod
    def reset_permits_issued(self) -> None:
        pass

    @abstractmethod
    def __enter__(self) -> "RateLimiter":
        pass

    @abstractmethod
    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        pass

    def limit(self, method: Callable) -> Callable:
        def limited(*args, **kwargs):
            with self:
                return method(*args, **kwargs)
        return limited

class MultiRateLimiter(RateLimiter):
    def __init__(self, *limiters: RateLimiter) -> None:
        self._limiters = limiters

        self._total_permits_issued = 0
        self._total_permits_issued_lock = Lock()

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        for limiter in self._limiters:
            limiter.__exit__(exc_type, exc_val, exc_tb)

    def __enter__(self) -> "RateLimiter":
        for limiter in self._limiters:
            limiter.__enter__()

        # Increment total count
        with self._total_permits_issued_lock:
            self._total_permits_issued += 1

        return self

    @property
    def permits_issued(self) -> int:
        with self._total_permits_issued_lock:
            return self._total_permits_issued

    def reset_permits_issued(self) -> None:
        with self._total_permits_issued_lock:
            self._total_permits_issued = 0

class FixedWindowRateLimiter(RateLimiter):
    def __init__(self, window_seconds: int, window_permits: int) -> None:
        self._window_seconds = window_seconds
        self._window_permits = window_permits

        self._permitter = Lock()
        self._permits = window_permits

        self._total_permits_issued = 0
        self._total_permits_issued_lock = Lock()

        self._enter_exit_lock = Lock()
        self._currently_processing = 0
        self._resetter = None

    def __enter__(self) -> "FixedWindowRateLimiter":
        # Grab the permit lock and decrement remaining permits. If this leaves it at 0, don't release the permit lock. It will be released by the resetter.
        self._permitter.acquire()
        with self._enter_exit_lock, self._total_permits_issued_lock:
            self._permits -= 1

            self._total_permits_issued += 1
            self._currently_processing += 1

            if self._permits > 0:
                self._permitter.release()

        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        with self._enter_exit_lock:
            self._currently_processing -= 1

            # The fixed window starts after processing the first permit ends. The presence of a resetter indicates whether we're in a fixed window already or if we need to start one.
            if not self._resetter:
                self._resetter = Timer(self._window_seconds, self._reset)
                self._resetter.daemon = True
                self._resetter.start()

    def _reset(self):
        with self._enter_exit_lock:
            self._permits = self._window_permits - self._currently_processing
            self._resetter = None

            try:
                self._permitter.release()
            except RuntimeError:
                # Wasn't waiting on any acquire
                pass

    @property
    def permits_issued(self) -> int:
        with self._total_permits_issued_lock:
            return self._total_permits_issued

    def reset_permits_issued(self) -> None:
        with self._total_permits_issued_lock:
            self._total_permits_issued = 0

class TokenBucketRateLimiter(RateLimiter):
    def __init__(self, epoch_seconds: int, epoch_permits: int, max_burst: int, token_update_frequency: float) -> None:
        if max_burst < 1 or max_burst > epoch_permits:
            raise ValueError("Max burst must be >= 1 and <= epoch permits!")

        if token_update_frequency <= 0 or token_update_frequency > epoch_seconds:
            raise ValueError("Token update frequency must be > 0 and <= epoch seconds!")

        self._epoch_seconds = epoch_seconds
        self._epoch_permits = epoch_permits

        self._permitter = Lock()
        self._token_limit = max_burst
        self._tokens = max_burst

        self._total_permits_issued = 0
        self._total_permits_issued_lock = Lock()

        self._enter_exit_lock = Lock()

        self._token_update = token_update_frequency
        self._token_provider = None

    def __enter__(self) -> "TokenBucketRateLimiter":
        # Grab the permit lock and decrement remaining permits. If this leaves it at 0, don't release the permit lock. It will be released by the token provider.
        self._permitter.acquire()
        with self._enter_exit_lock, self._total_permits_issued_lock:
            self._tokens -= 1

            self._total_permits_issued += 1

            if self._tokens >= 1:
                self._permitter.release()

        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        # We don't want a thread sitting around dumping tokens into a filled bucket during downtimes. We construct one when needed and it cleans itself up if the bucket is full for an entire epoch.
        with self._enter_exit_lock:
            if not self._token_provider:
                self._token_provider = Thread(target=self._provide_tokens)
                self._token_provider.daemon = True
                self._token_provider.start()

    def _provide_tokens(self):
        tokens_per_segment = self._epoch_permits / (self._epoch_seconds / self._token_update)
        segments_full = 0

        start_time = monotonic()
        next_time = start_time + self._token_update

        # If we go an entire epoch with a full bucket we'll stop this provider
        segments_per_epoch = int(ceil(self._epoch_seconds / self._token_update))
        while True:
            sleep(max(next_time - monotonic(), 0))
            next_time = next_time + self._token_update

            with self._enter_exit_lock:
                if self._tokens == self._token_limit:
                    segments_full += 1
                elif self._tokens < 1:
                    self._tokens = min(self._tokens + tokens_per_segment, self._token_limit)
                    segments_full = 0
                    if self._tokens >= 1:
                        try:
                            self._permitter.release()
                        except RuntimeError:
                            # Wasn't waiting on any acquire
                            pass
                else:
                    self._tokens = min(self._tokens + tokens_per_segment, self._token_limit)
                    segments_full = 0

                if segments_full >= segments_per_epoch:
                    # End this thread
                    self._token_provider = None
                    break

    @property
    def permits_issued(self) -> int:
        with self._total_permits_issued_lock:
            return self._total_permits_issued

    def reset_permits_issued(self) -> None:
        with self._total_permits_issued_lock:
            self._total_permits_issued = 0
<|endoftext|>


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

# Copyright 2015-2016 The Meson development team

# 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 json
import sys, os
import configparser
import shutil

from glob import glob

from .wrap import API_ROOT, open_wrapdburl

help_templ = '''This program allows you to manage your Wrap dependencies
using the online wrap database http://wrapdb.mesonbuild.com.

Run this command in your top level source directory.

Usage:

%s <command> [options]

Commands:

 list - show all available projects
 search - search the db by name
 install - install the specified project
 update - update the project to its newest available release
 info - show available versions of a project
 status - show installed and available versions of your projects

'''

def print_help():
    print(help_templ % sys.argv[0])

def get_result(urlstring):
    u = open_wrapdburl(urlstring)
    data = u.read().decode('utf-8')
    jd = json.loads(data)
    if jd['output'] != 'ok':
        print('Got bad output from server.')
        print(data)
        sys.exit(1)
    return jd

def get_projectlist():
    jd = get_result(API_ROOT + 'projects')
    projects = jd['projects']
    return projects

def list_projects():
    projects = get_projectlist()
    for p in projects:
        print(p)

def search(name):
    jd = get_result(API_ROOT + 'query/byname/' + name)
    for p in jd['projects']:
        print(p)

def get_latest_version(name):
    jd = get_result(API_ROOT + 'query/get_latest/' + name)
    branch = jd['branch']
    revision = jd['revision']
    return (branch, revision)

def install(name):
    if not os.path.isdir('subprojects'):
        print('Subprojects dir not found. Run this script in your source root directory.')
        sys.exit(1)
    if os.path.isdir(os.path.join('subprojects', name)):
        print('Subproject directory for this project already exists.')
        sys.exit(1)
    wrapfile = os.path.join('subprojects', name + '.wrap')
    if os.path.exists(wrapfile):
        print('Wrap file already exists.')
        sys.exit(1)
    (branch, revision) = get_latest_version(name)
    u = open_wrapdburl(API_ROOT + 'projects/%s/%s/%s/get_wrap' % (name, branch, revision))
    data = u.read()
    with open(wrapfile, 'wb') as f:
        f.write(data)
    print('Installed', name, 'branch', branch, 'revision', revision)

def get_current_version(wrapfile):
    cp = configparser.ConfigParser()
    cp.read(wrapfile)
    cp = cp['wrap-file']
    patch_url = cp['patch_url']
    arr = patch_url.split('/')
    branch = arr[-3]
    revision = int(arr[-2])
    return (branch, revision, cp['directory'], cp['source_filename'], cp['patch_filename'])

def update(name):
    if not os.path.isdir('subprojects'):
        print('Subprojects dir not found. Run this command in your source root directory.')
        sys.exit(1)
    wrapfile = os.path.join('subprojects', name + '.wrap')
    if not os.path.exists(wrapfile):
        print('Project', name, 'is not in use.')
        sys.exit(1)
    (branch, revision, subdir, src_file, patch_file) = get_current_version(wrapfile)
    (new_branch, new_revision) = get_latest_version(name)
    if new_branch == branch and new_revision == revision:
        print('Project', name, 'is already up to date.')
        sys.exit(0)
    u = open_wrapdburl(API_ROOT + 'projects/%s/%s/%d/get_wrap' % (name, new_branch, new_revision))
    data = u.read()
    shutil.rmtree(os.path.join('subprojects', subdir), ignore_errors=True)
    try:
        os.unlink(os.path.join('subprojects/packagecache', src_file))
    except FileNotFoundError:
        pass
    try:
        os.unlink(os.path.join('subprojects/packagecache', patch_file))
    except FileNotFoundError:
        pass
    with open(wrapfile, 'wb') as f:
        f.write(data)
    print('Updated', name, 'to branch', new_branch, 'revision', new_revision)

def info(name):
    jd = get_result(API_ROOT + 'projects/' + name)
    versions = jd['versions']
    if len(versions) == 0:
        print('No available versions of', name)
        sys.exit(0)
    print('Available versions of %s:' % name)
    for v in versions:
        print(' ', v['branch'], v['revision'])

def status():
    print('Subproject status')
    for w in glob('subprojects/*.wrap'):
        name = os.path.split(w)[1][:-5]
        try:
            (latest_branch, latest_revision) = get_latest_version(name)
        except Exception:
            print('', name, 'not available in wrapdb.')
            continue
        try:
            (current_branch, current_revision, _, _, _) = get_current_version(w)
        except Exception:
            print('Wrap file not from wrapdb.')
            continue
        if current_branch == latest_branch and current_revision == latest_revision:
            print('', name, 'up to date. Branch %s, revision %d.' % (current_branch, current_revision))
        else:
            print('', name, 'not up to date. Have %s %d, but %s %d is available.' % (current_branch, current_revision, latest_branch, latest_revision))

def run(args):
    if len(args) == 0 or args[0] == '-h' or args[0] == '--help':
        print_help()
        return 0
    command = args[0]
    args = args[1:]
    if command == 'list':
        list_projects()
    elif command == 'search':
        if len(args) != 1:
            print('Search requires exactly one argument.')
            return 1
        search(args[0])
    elif command == 'install':
        if len(args) != 1:
            print('Install requires exactly one argument.')
            return 1
        install(args[0])
    elif command == 'update':
        if len(args) != 1:
            print('update requires exactly one argument.')
            return 1
        update(args[0])
    elif command == 'info':
        if len(args) != 1:
            print('info requires exactly one argument.')
            return 1
        info(args[0])
    elif command == 'status':
        status()
    else:
        print('Unknown command', command)
        return 1
    return 0

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
<commit_msg>remove shebang from wraptool<commit_after># Copyright 2015-2016 The Meson development team

# 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 json
import sys, os
import configparser
import shutil

from glob import glob

from .wrap import API_ROOT, open_wrapdburl

help_templ = '''This program allows you to manage your Wrap dependencies
using the online wrap database http://wrapdb.mesonbuild.com.

Run this command in your top level source directory.

Usage:

%s <command> [options]

Commands:

 list - show all available projects
 search - search the db by name
 install - install the specified project
 update - update the project to its newest available release
 info - show available versions of a project
 status - show installed and available versions of your projects

'''

def print_help():
    print(help_templ % sys.argv[0])

def get_result(urlstring):
    u = open_wrapdburl(urlstring)
    data = u.read().decode('utf-8')
    jd = json.loads(data)
    if jd['output'] != 'ok':
        print('Got bad output from server.')
        print(data)
        sys.exit(1)
    return jd

def get_projectlist():
    jd = get_result(API_ROOT + 'projects')
    projects = jd['projects']
    return projects

def list_projects():
    projects = get_projectlist()
    for p in projects:
        print(p)

def search(name):
    jd = get_result(API_ROOT + 'query/byname/' + name)
    for p in jd['projects']:
        print(p)

def get_latest_version(name):
    jd = get_result(API_ROOT + 'query/get_latest/' + name)
    branch = jd['branch']
    revision = jd['revision']
    return (branch, revision)

def install(name):
    if not os.path.isdir('subprojects'):
        print('Subprojects dir not found. Run this script in your source root directory.')
        sys.exit(1)
    if os.path.isdir(os.path.join('subprojects', name)):
        print('Subproject directory for this project already exists.')
        sys.exit(1)
    wrapfile = os.path.join('subprojects', name + '.wrap')
    if os.path.exists(wrapfile):
        print('Wrap file already exists.')
        sys.exit(1)
    (branch, revision) = get_latest_version(name)
    u = open_wrapdburl(API_ROOT + 'projects/%s/%s/%s/get_wrap' % (name, branch, revision))
    data = u.read()
    with open(wrapfile, 'wb') as f:
        f.write(data)
    print('Installed', name, 'branch', branch, 'revision', revision)

def get_current_version(wrapfile):
    cp = configparser.ConfigParser()
    cp.read(wrapfile)
    cp = cp['wrap-file']
    patch_url = cp['patch_url']
    arr = patch_url.split('/')
    branch = arr[-3]
    revision = int(arr[-2])
    return (branch, revision, cp['directory'], cp['source_filename'], cp['patch_filename'])

def update(name):
    if not os.path.isdir('subprojects'):
        print('Subprojects dir not found. Run this command in your source root directory.')
        sys.exit(1)
    wrapfile = os.path.join('subprojects', name + '.wrap')
    if not os.path.exists(wrapfile):
        print('Project', name, 'is not in use.')
        sys.exit(1)
    (branch, revision, subdir, src_file, patch_file) = get_current_version(wrapfile)
    (new_branch, new_revision) = get_latest_version(name)
    if new_branch == branch and new_revision == revision:
        print('Project', name, 'is already up to date.')
        sys.exit(0)
    u = open_wrapdburl(API_ROOT + 'projects/%s/%s/%d/get_wrap' % (name, new_branch, new_revision))
    data = u.read()
    shutil.rmtree(os.path.join('subprojects', subdir), ignore_errors=True)
    try:
        os.unlink(os.path.join('subprojects/packagecache', src_file))
    except FileNotFoundError:
        pass
    try:
        os.unlink(os.path.join('subprojects/packagecache', patch_file))
    except FileNotFoundError:
        pass
    with open(wrapfile, 'wb') as f:
        f.write(data)
    print('Updated', name, 'to branch', new_branch, 'revision', new_revision)

def info(name):
    jd = get_result(API_ROOT + 'projects/' + name)
    versions = jd['versions']
    if len(versions) == 0:
        print('No available versions of', name)
        sys.exit(0)
    print('Available versions of %s:' % name)
    for v in versions:
        print(' ', v['branch'], v['revision'])

def status():
    print('Subproject status')
    for w in glob('subprojects/*.wrap'):
        name = os.path.split(w)[1][:-5]
        try:
            (latest_branch, latest_revision) = get_latest_version(name)
        except Exception:
            print('', name, 'not available in wrapdb.')
            continue
        try:
            (current_branch, current_revision, _, _, _) = get_current_version(w)
        except Exception:
            print('Wrap file not from wrapdb.')
            continue
        if current_branch == latest_branch and current_revision == latest_revision:
            print('', name, 'up to date. Branch %s, revision %d.' % (current_branch, current_revision))
        else:
            print('', name, 'not up to date. Have %s %d, but %s %d is available.' % (current_branch, current_revision, latest_branch, latest_revision))

def run(args):
    if len(args) == 0 or args[0] == '-h' or args[0] == '--help':
        print_help()
        return 0
    command = args[0]
    args = args[1:]
    if command == 'list':
        list_projects()
    elif command == 'search':
        if len(args) != 1:
            print('Search requires exactly one argument.')
            return 1
        search(args[0])
    elif command == 'install':
        if len(args) != 1:
            print('Install requires exactly one argument.')
            return 1
        install(args[0])
    elif command == 'update':
        if len(args) != 1:
            print('update requires exactly one argument.')
            return 1
        update(args[0])
    elif command == 'info':
        if len(args) != 1:
            print('info requires exactly one argument.')
            return 1
        info(args[0])
    elif command == 'status':
        status()
    else:
        print('Unknown command', command)
        return 1
    return 0

if __name__ == '__main__':
    sys.exit(run(sys.argv[1:]))
<|endoftext|>


<commit_before>from rest_framework.test import APITestCase
from common.tests.test_views import LoginMixin
from django.core.urlresolvers import reverse
from model_mommy import mommy

from ..models import (
    WorldBorder,
    CountyBoundary,
    ConstituencyBoundary,
    WardBoundary
)
from ..serializers import WorldBorderDetailSerializer

class TestCountryBoundariesView(LoginMixin, APITestCase):

    def test_retrieve_single_country_boundary(self):
        country = mommy.make(WorldBorder)
        url = reverse(
            'api:mfl_gis:world_border_detail', kwargs={'pk': country.pk})
        response = self.client.get(url)
        expected_data = WorldBorderDetailSerializer(country).data
        # Silly issues with floats being rounded to different precisions
        # between the serializer and the "round trip through the view" version
        self.assertEqual(
            expected_data['properties']['code'],
            response.data['properties']['code']
        )

class TestCountyBoundaryViews(LoginMixin, APITestCase):
    def setUp(self):
        super(TestCountyBoundaryViews, self).setUp()
        self.list_url = reverse('api:mfl_gis:county_boundaries_list')

    def test_listing(self):
        mommy.make(CountyBoundary)
        mommy.make(CountyBoundary)
        boundary_list_response = self.client.get(self.list_url)
        self.assertEqual(200, boundary_list_response.status_code)
        self.assertEqual(2, len(boundary_list_response.data['results']))

class TestConstituencyBoundaryViews(LoginMixin, APITestCase):
    def setUp(self):
        super(TestConstituencyBoundaryViews, self).setUp()
        self.list_url = reverse('api:mfl_gis:constituency_boundaries_list')

    def test_listing(self):
        mommy.make(ConstituencyBoundary)
        mommy.make(ConstituencyBoundary)
        boundary_list_response = self.client.get(self.list_url)
        self.assertEqual(200, boundary_list_response.status_code)
        self.assertEqual(2, len(boundary_list_response.data['results']))

class TestWardBoundaryViews(LoginMixin, APITestCase):
    def setUp(self):
        super(TestWardBoundaryViews, self).setUp()
        self.list_url = reverse('api:mfl_gis:ward_boundaries_list')

    def test_listing(self):
        mommy.make(WardBoundary)
        mommy.make(WardBoundary)
        boundary_list_response = self.client.get(self.list_url)
        self.assertEqual(200, boundary_list_response.status_code)
        self.assertEqual(2, len(boundary_list_response.data['results']))
<commit_msg>Add tests<commit_after>from rest_framework.test import APITestCase
from common.tests.test_views import LoginMixin
from django.core.urlresolvers import reverse
from model_mommy import mommy

from ..models import (
    WorldBorder,
    CountyBoundary,
    ConstituencyBoundary,
    WardBoundary
)
from ..serializers import WorldBorderDetailSerializer

class TestCountryBoundariesView(LoginMixin, APITestCase):

    def test_retrieve_single_country_boundary(self):
        country = mommy.make(WorldBorder)
        url = reverse(
            'api:mfl_gis:world_border_detail', kwargs={'pk': country.pk})
        response = self.client.get(url)
        expected_data = WorldBorderDetailSerializer(country).data
        # Silly issues with floats being rounded to different precisions
        # between the serializer and the "round trip through the view" version
        self.assertEqual(
            expected_data['properties']['code'],
            response.data['properties']['code']
        )

class TestCountyBoundaryViews(LoginMixin, APITestCase):
    def setUp(self):
        super(TestCountyBoundaryViews, self).setUp()
        self.list_url = reverse('api:mfl_gis:county_boundaries_list')

    def test_listing(self):
        mommy.make(CountyBoundary)
        mommy.make(CountyBoundary)
        boundary_list_response = self.client.get(self.list_url)
        self.assertEqual(200, boundary_list_response.status_code)
        self.assertEqual(2, len(boundary_list_response.data['results']))
        self.assertIn('bound', boundary_list_response.data['results'])

class TestConstituencyBoundaryViews(LoginMixin, APITestCase):
    def setUp(self):
        super(TestConstituencyBoundaryViews, self).setUp()
        self.list_url = reverse('api:mfl_gis:constituency_boundaries_list')

    def test_listing(self):
        mommy.make(ConstituencyBoundary)
        mommy.make(ConstituencyBoundary)
        boundary_list_response = self.client.get(self.list_url)
        self.assertEqual(200, boundary_list_response.status_code)
        self.assertEqual(2, len(boundary_list_response.data['results']))

class TestWardBoundaryViews(LoginMixin, APITestCase):
    def setUp(self):
        super(TestWardBoundaryViews, self).setUp()
        self.list_url = reverse('api:mfl_gis:ward_boundaries_list')

    def test_listing(self):
        mommy.make(WardBoundary)
        mommy.make(WardBoundary)
        boundary_list_response = self.client.get(self.list_url)
        self.assertEqual(200, boundary_list_response.status_code)
        self.assertEqual(2, len(boundary_list_response.data['results']))
<|endoftext|>


<commit_before>import sys
import pytest
import mfr
if not sys.version_info >= (3, 0):

    from mfr_docx import Handler as DocxFileHandler
    from mfr_docx.render import render_docx

else:
    DocxFileHandler = render_docx = None

@pytest.mark.skipif(sys.version_info >= (3, 0),
                    reason="pydocx 0.3.14 does not support py3")
def setup_function(func):
    mfr.register_filehandler(DocxFileHandler)

@pytest.mark.skipif(sys.version_info >= (3, 0),
                    reason="pydocx 0.3.14 does not support py3")
def test_detect_docx(fakefile):
    # set file's name
    fakefile.name = 'mydoc.docx'
    handler = DocxFileHandler()

    assert handler.detect(fakefile) is True

@pytest.mark.skipif(sys.version_info >= (3, 0),
                    reason="pydocx 0.3.14 does not support py3")
def test_detect_nondocx(fakefile):
    fakefile.name = 'not_doc.odt'
    handler = DocxFileHandler()
    assert handler.detect(fakefile) is False

@pytest.mark.skipif(sys.version_info >= (3, 0),
                    reason="pydocx 0.3.14 does not support py3")
def test_render_docx():
    with open('mfr_docx/tests/test.docx') as fp:
        result = render_docx(fp)

    assert type(result) == mfr.core.RenderResult
<commit_msg>remove unnecessary else<commit_after>import sys
import pytest
import mfr

# Pydocx .3.14 does not support python 3
if not sys.version_info >= (3, 0):

    from mfr_docx import Handler as DocxFileHandler
    from mfr_docx.render import render_docx

@pytest.mark.skipif(sys.version_info >= (3, 0),
                    reason="pydocx 0.3.14 does not support py3")
def setup_function(func):
    mfr.register_filehandler(DocxFileHandler)

@pytest.mark.skipif(sys.version_info >= (3, 0),
                    reason="pydocx 0.3.14 does not support py3")
def test_detect_docx(fakefile):
    # set file's name
    fakefile.name = 'mydoc.docx'
    handler = DocxFileHandler()

    assert handler.detect(fakefile) is True

@pytest.mark.skipif(sys.version_info >= (3, 0),
                    reason="pydocx 0.3.14 does not support py3")
def test_detect_nondocx(fakefile):
    fakefile.name = 'not_doc.odt'
    handler = DocxFileHandler()
    assert handler.detect(fakefile) is False

@pytest.mark.skipif(sys.version_info >= (3, 0),
                    reason="pydocx 0.3.14 does not support py3")
def test_render_docx():
    with open('mfr_docx/tests/test.docx') as fp:
        result = render_docx(fp)

    assert type(result) == mfr.core.RenderResult
<|endoftext|>


<commit_before>"""
MIDI file reading and playback.

References:

http://home.roadrunner.com/~jgglatt/
http://home.roadrunner.com/~jgglatt/tech/miditech.htm
http://home.roadrunner.com/~jgglatt/tech/midifile.htm

http://www.sonicspot.com/guide/midifiles.html
http://www.ccarh.org/courses/253/assignment/midifile/
https://code.google.com/p/binasc/wiki/mainpage
http://stackoverflow.com/questions/2984608/midi-delta-time
http://www.recordingblogs.com/sa/tabid/82/EntryId/44/MIDI-Part-XIII-Delta-time-a
http://www.sonicspot.com/guide/midifiles.html
"""

from __future__ import print_function, division
import io
import time
import string
import struct
from numbers import Integral

from ..messages import Message, SPEC_BY_STATUS
from .meta import (MetaMessage, build_meta_message, meta_charset,
                   encode_variable_int)

from .tracks import MidiTrack, merge_tracks, fix_end_of_track
from .units import tick2second

# The default tempo is 120 BPM.
# (500000 microseconds per beat (quarter note).)
DEFAULT_TEMPO = 500000
DEFAULT_TICKS_PER_BEAT = 480

# Maximum message length to attempt to read.
MAX_MESSAGE_LENGTH = 1000000

def print_byte(byte, pos=0):
    char = chr(byte)
    if char.isspace() or char not in string.printable:
        char = '.'

    print('  {:06x}: {:02x}  {}'.format(pos, byte, char))

class DebugFileWrapper(object):
    def __init__(self, file):
        self.file = file

    def read(self, size):
        data = self.file.read(size)

        for byte in data:
            # Iterating gives us byte strings instead of ints in
            # Python 2.
            if isinstance(byte, str):
                byte = ord(byte)

            print_byte(byte, self.file.tell())

        return data

    def tell(self):
        return self.file.tell()

def read_byte(self):
    byte = self.read(1)
    if byte == b'':
        raise EOFError
    else:
        return ord(byte)

def read_bytes(infile, size):
    if size > MAX_MESSAGE_LENGTH:
        raise IOError('Message length {} exceeds maximum length {}'.format(
            size, MAX_MESSAGE_LENGTH))
    return [read_byte(infile) for _ in range(size)]

def _dbg(text=''):
    print(text)

# We can't use the chunk module for two reasons:
#
# 1. we may have mixed big and little endian chunk sizes. (RIFF is
# little endian while MTrk is big endian.)
#
# 2. the chunk module assumes that chunks are padded to the nearest
# multiple of 2. This is not true of MIDI files.

def read_chunk_header(infile):
    header = infile.read(8)
    if len(header) < 8:
        raise EOFError

    # TODO: check for b'RIFF' and switch endian?

    return struct.unpack('>4sL', header)

def read_file_header(infile):
    name, size = read_chunk_header(infile)

    if name != b'MThd':
        raise IOError('MThd not found. Probably not a MIDI file')
    else:
        data = infile.read(size)

        if len(data) < 6:
            raise EOFError

        return struct.unpack('>hhh', data[:6])

def read_message(infile, status_byte, peek_data, delta, clip=False):
    try:
        spec = SPEC_BY_STATUS[status_byte]
    except LookupError:
        raise IOError('undefined status byte 0x{:02x}'.format(status_byte))

    # Subtract 1 for status byte.
    size = spec['length'] - 1 - len(peek_data)
    data_bytes = peek_data + read_bytes(infile, size)

    if clip:
        data_bytes = [byte if byte < 127 else 127 for byte in data_bytes]
    else:
        for byte in data_bytes:
            if byte > 127:
                raise IOError('data byte must be in range 0..127')

    return Message.from_bytes([status_byte] + data_bytes, time=delta)

def read_sysex(infile, delta):
    length = read_variable_int(infile)
    data = read_bytes(infile, length)

    # Strip start and end bytes.
    # TODO: is this necessary?
    if data and data[0] == 0xf0:
        data = data[1:]
    if data and data[-1] == 0xf7:
        data = data[:-1]

    return Message('sysex', data=data, time=delta)

def read_variable_int(infile):
    delta = 0

    while True:
        byte = read_byte(infile)
        delta = (delta << 7) | (byte & 0x7f)
        if byte < 0x80:
            return delta

def read_meta_message(infile, delta):
    meta_type = read_byte(infile)
    length = read_variable_int(infile)
    data = read_bytes(infile, length)
    return build_meta_message(meta_type, data, delta)

def read_track(infile, debug=False, clip=False):
    track = MidiTrack()

    name, size = read_chunk_header(infile)

    if name != b'MTrk':
        raise IOError('no MTrk header at start of track')

    if debug:
        _dbg('-> size={}'.format(size))
        _dbg()

    start = infile.tell()
    last_status = None

    while True:
        # End of track reached.
        if infile.tell() - start == size:
            break

        if debug:
            _dbg('Message:')

        delta = read_variable_int(infile)

        if debug:
            _dbg('-> delta={}'.format(delta))

        status_byte = read_byte(infile)

        if status_byte < 0x80:
            if last_status is None:
                raise IOError('running status without last_status')
            peek_data = [status_byte]
            status_byte = last_status
        else:
            if status_byte != 0xff:
                # Meta messages don't set running status.
                last_status = status_byte
            peek_data = []

        if status_byte == 0xff:
            msg = read_meta_message(infile, delta)
        elif status_byte in [0xf0, 0xf7]:
            # TODO: I'm not quite clear on the difference between
            # f0 and f7 events.
            msg = read_sysex(infile, delta)
        else:
            msg = read_message(infile, status_byte, peek_data, delta, clip)

        track.append(msg)

        if debug:
            _dbg('-> {!r}'.format(msg))
            _dbg()

    return track

def write_chunk(outfile, name, data):
    """Write an IFF chunk to the file.

    `name` must be a bytestring."""
    outfile.write(name)
    outfile.write(struct.pack('>L', len(data)))
    outfile.write(data)

def write_track(outfile, track):
    data = bytearray()

    running_status_byte = None
    for msg in fix_end_of_track(track):
        if not isinstance(msg.time, Integral):
            raise ValueError('message time must be int in MIDI file')

        if msg.is_realtime:
            raise ValueError('realtime messages are not allowed in MIDI files')

        data.extend(encode_variable_int(msg.time))

        if msg.is_meta:
            data.extend(msg.bytes())
            running_status_byte = None
        elif msg.type == 'sysex':
            data.append(0xf0)
            # length (+ 1 for end byte (0xf7))
            data.extend(encode_variable_int(len(msg.data) + 1))
            data.extend(msg.data)
            data.append(0xf7)
            running_status_byte = None
        else:
            msg_bytes = msg.bytes()
            status_byte = msg_bytes[0]

            if status_byte == running_status_byte:
                data.extend(msg_bytes[1:])
            else:
                data.extend(msg_bytes)

            if status_byte < 0xf0:
                running_status_byte = status_byte
            else:
                running_status_byte = None

    write_chunk(outfile, b'MTrk', data)

def get_seconds_per_tick(tempo, ticks_per_beat):
    # Tempo is given in microseconds per beat (default 500000).
    # At this tempo there are (500000 / 1000000) == 0.5 seconds
    # per beat. At the default resolution of 480 ticks per beat
    # this is:
    #
    #    (500000 / 1000000) / 480 == 0.5 / 480 == 0.0010417
    #
    return (tempo / 1000000.0) / ticks_per_beat

class MidiFile(object):
    def __init__(self, filename=None, file=None,
                 type=1, ticks_per_beat=DEFAULT_TICKS_PER_BEAT,
                 charset='latin1',
                 debug=False,
                 clip=False
                 ):

        self.filename = filename
        self.type = type
        self.ticks_per_beat = ticks_per_beat
        self.charset = charset
        self.debug = debug
        self.clip = clip

        self.tracks = []

        if type not in range(3):
            raise ValueError(
                'invalid format {} (must be 0, 1 or 2)'.format(format))

        if file is not None:
            self._load(file)
        elif self.filename is not None:
            with io.open(filename, 'rb') as file:
                self._load(file)

    def add_track(self, name=None):
        """Add a new track to the file.

        This will create a new MidiTrack object and append it to the
        track list.
        """
        track = MidiTrack()
        if name is not None:
            track.name = name
        self.tracks.append(track)
        return track

    def _load(self, infile):
        if self.debug:
            infile = DebugFileWrapper(infile)

        with meta_charset(self.charset):
            if self.debug:
                _dbg('Header:')

            (self.type,
             num_tracks,
             self.ticks_per_beat) = read_file_header(infile)

            if self.debug:
                _dbg('-> type={}, tracks={}, ticks_per_beat={}'.format(
                    self.type, num_tracks, self.ticks_per_beat))
                _dbg()

            for i in range(num_tracks):
                if self.debug:
                    _dbg('Track {}:'.format(i))

                self.tracks.append(read_track(infile,
                                              debug=self.debug,
                                              clip=self.clip))
                # TODO: used to ignore EOFError. I hope things still work.

    @property
    def length(self):
        """Playback time in seconds.

        This will be computed by going through every message in every
        track and adding up delta times.
        """
        if self.type == 2:
            raise ValueError('impossible to compute length'
                             ' for type 2 (asynchronous) file')

        return sum(msg.time for msg in self)

    def __iter__(self):
        # The tracks of type 2 files are not in sync, so they can
        # not be played back like this.
        if self.type == 2:
            raise TypeError("can't merge tracks in type 2 (asynchronous) file")

        tempo = DEFAULT_TEMPO
        for msg in merge_tracks(self.tracks):
            # Convert message time from absolute time
            # in ticks to relative time in seconds.
            if msg.time > 0:
                delta = tick2second(msg.time, self.ticks_per_beat, tempo)
            else:
                delta = 0

            yield msg.copy(time=delta)

            if msg.type == 'set_tempo':
                tempo = msg.tempo

    def play(self, meta_messages=False):
        """Play back all tracks.

        The generator will sleep between each message by
        default. Messages are yielded with correct timing. The time
        attribute is set to the number of seconds slept since the
        previous message.

        By default you will only get normal MIDI messages. Pass
        meta_messages=True if you also want meta messages.

        You will receive copies of the original messages, so you can
        safely modify them without ruining the tracks.
        """
        t0 = time.time()
        combined_time = 0.0

        for msg in self:
            combined_time += msg.time

            # we compute the difference between the nominal combined time
            # and the actual time spent at this point
            duration_to_next_event = combined_time - (time.time() - t0)

            if (duration_to_next_event > 0.0):
                time.sleep(duration_to_next_event)

            if isinstance(msg, MetaMessage) and not meta_messages:
                continue
            else:
                yield msg

    def save(self, filename=None, file=None):
        """Save to a file.

        If file is passed the data will be saved to that file. This is
        typically an in-memory file or and already open file like sys.stdout.

        If filename is passed the data will be saved to that file.

        Raises ValueError if both file and filename are None,
        or if a type 0 file has != one track.
        """
        if self.type == 0 and len(self.tracks) != 1:
            raise ValueError('type 0 file must have exactly 1 track')

        if file is not None:
            self._save(file)
        elif filename is not None:
            with io.open(filename, 'wb') as file:
                self._save(file)
        else:
            raise ValueError('requires filename or file')

    def _save(self, outfile):
        with meta_charset(self.charset):
            header = struct.pack('>hhh', self.type,
                                 len(self.tracks),
                                 self.ticks_per_beat)

            write_chunk(outfile, b'MThd', header)

            for track in self.tracks:
                write_track(outfile, track)

    def print_tracks(self, meta_only=False):
        """Prints out all messages in a .midi file.

        May take argument meta_only to show only meta messages.

        Use:
        print_tracks() -> will print all messages
        print_tracks(meta_only=True) -> will print only MetaMessages
        """
        for i, track in enumerate(self.tracks):
            print('=== Track {}'.format(i))
            for msg in track:
                if not isinstance(msg, MetaMessage) and meta_only:
                    pass
                else:
                    print('{!r}'.format(msg))

    def __repr__(self):
        return '<midi file {!r} type {}, {} tracks, {} messages>'.format(
            self.filename, self.type, len(self.tracks),
            sum([len(track) for track in self.tracks]))

    # The context manager has no purpose but is kept around since it was
    # used in examples in the past.
    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        return False
<commit_msg>rename combined_time to input_time<commit_after>"""
MIDI file reading and playback.

References:

http://home.roadrunner.com/~jgglatt/
http://home.roadrunner.com/~jgglatt/tech/miditech.htm
http://home.roadrunner.com/~jgglatt/tech/midifile.htm

http://www.sonicspot.com/guide/midifiles.html
http://www.ccarh.org/courses/253/assignment/midifile/
https://code.google.com/p/binasc/wiki/mainpage
http://stackoverflow.com/questions/2984608/midi-delta-time
http://www.recordingblogs.com/sa/tabid/82/EntryId/44/MIDI-Part-XIII-Delta-time-a
http://www.sonicspot.com/guide/midifiles.html
"""

from __future__ import print_function, division
import io
import time
import string
import struct
from numbers import Integral

from ..messages import Message, SPEC_BY_STATUS
from .meta import (MetaMessage, build_meta_message, meta_charset,
                   encode_variable_int)

from .tracks import MidiTrack, merge_tracks, fix_end_of_track
from .units import tick2second

# The default tempo is 120 BPM.
# (500000 microseconds per beat (quarter note).)
DEFAULT_TEMPO = 500000
DEFAULT_TICKS_PER_BEAT = 480

# Maximum message length to attempt to read.
MAX_MESSAGE_LENGTH = 1000000

def print_byte(byte, pos=0):
    char = chr(byte)
    if char.isspace() or char not in string.printable:
        char = '.'

    print('  {:06x}: {:02x}  {}'.format(pos, byte, char))

class DebugFileWrapper(object):
    def __init__(self, file):
        self.file = file

    def read(self, size):
        data = self.file.read(size)

        for byte in data:
            # Iterating gives us byte strings instead of ints in
            # Python 2.
            if isinstance(byte, str):
                byte = ord(byte)

            print_byte(byte, self.file.tell())

        return data

    def tell(self):
        return self.file.tell()

def read_byte(self):
    byte = self.read(1)
    if byte == b'':
        raise EOFError
    else:
        return ord(byte)

def read_bytes(infile, size):
    if size > MAX_MESSAGE_LENGTH:
        raise IOError('Message length {} exceeds maximum length {}'.format(
            size, MAX_MESSAGE_LENGTH))
    return [read_byte(infile) for _ in range(size)]

def _dbg(text=''):
    print(text)

# We can't use the chunk module for two reasons:
#
# 1. we may have mixed big and little endian chunk sizes. (RIFF is
# little endian while MTrk is big endian.)
#
# 2. the chunk module assumes that chunks are padded to the nearest
# multiple of 2. This is not true of MIDI files.

def read_chunk_header(infile):
    header = infile.read(8)
    if len(header) < 8:
        raise EOFError

    # TODO: check for b'RIFF' and switch endian?

    return struct.unpack('>4sL', header)

def read_file_header(infile):
    name, size = read_chunk_header(infile)

    if name != b'MThd':
        raise IOError('MThd not found. Probably not a MIDI file')
    else:
        data = infile.read(size)

        if len(data) < 6:
            raise EOFError

        return struct.unpack('>hhh', data[:6])

def read_message(infile, status_byte, peek_data, delta, clip=False):
    try:
        spec = SPEC_BY_STATUS[status_byte]
    except LookupError:
        raise IOError('undefined status byte 0x{:02x}'.format(status_byte))

    # Subtract 1 for status byte.
    size = spec['length'] - 1 - len(peek_data)
    data_bytes = peek_data + read_bytes(infile, size)

    if clip:
        data_bytes = [byte if byte < 127 else 127 for byte in data_bytes]
    else:
        for byte in data_bytes:
            if byte > 127:
                raise IOError('data byte must be in range 0..127')

    return Message.from_bytes([status_byte] + data_bytes, time=delta)

def read_sysex(infile, delta):
    length = read_variable_int(infile)
    data = read_bytes(infile, length)

    # Strip start and end bytes.
    # TODO: is this necessary?
    if data and data[0] == 0xf0:
        data = data[1:]
    if data and data[-1] == 0xf7:
        data = data[:-1]

    return Message('sysex', data=data, time=delta)

def read_variable_int(infile):
    delta = 0

    while True:
        byte = read_byte(infile)
        delta = (delta << 7) | (byte & 0x7f)
        if byte < 0x80:
            return delta

def read_meta_message(infile, delta):
    meta_type = read_byte(infile)
    length = read_variable_int(infile)
    data = read_bytes(infile, length)
    return build_meta_message(meta_type, data, delta)

def read_track(infile, debug=False, clip=False):
    track = MidiTrack()

    name, size = read_chunk_header(infile)

    if name != b'MTrk':
        raise IOError('no MTrk header at start of track')

    if debug:
        _dbg('-> size={}'.format(size))
        _dbg()

    start = infile.tell()
    last_status = None

    while True:
        # End of track reached.
        if infile.tell() - start == size:
            break

        if debug:
            _dbg('Message:')

        delta = read_variable_int(infile)

        if debug:
            _dbg('-> delta={}'.format(delta))

        status_byte = read_byte(infile)

        if status_byte < 0x80:
            if last_status is None:
                raise IOError('running status without last_status')
            peek_data = [status_byte]
            status_byte = last_status
        else:
            if status_byte != 0xff:
                # Meta messages don't set running status.
                last_status = status_byte
            peek_data = []

        if status_byte == 0xff:
            msg = read_meta_message(infile, delta)
        elif status_byte in [0xf0, 0xf7]:
            # TODO: I'm not quite clear on the difference between
            # f0 and f7 events.
            msg = read_sysex(infile, delta)
        else:
            msg = read_message(infile, status_byte, peek_data, delta, clip)

        track.append(msg)

        if debug:
            _dbg('-> {!r}'.format(msg))
            _dbg()

    return track

def write_chunk(outfile, name, data):
    """Write an IFF chunk to the file.

    `name` must be a bytestring."""
    outfile.write(name)
    outfile.write(struct.pack('>L', len(data)))
    outfile.write(data)

def write_track(outfile, track):
    data = bytearray()

    running_status_byte = None
    for msg in fix_end_of_track(track):
        if not isinstance(msg.time, Integral):
            raise ValueError('message time must be int in MIDI file')

        if msg.is_realtime:
            raise ValueError('realtime messages are not allowed in MIDI files')

        data.extend(encode_variable_int(msg.time))

        if msg.is_meta:
            data.extend(msg.bytes())
            running_status_byte = None
        elif msg.type == 'sysex':
            data.append(0xf0)
            # length (+ 1 for end byte (0xf7))
            data.extend(encode_variable_int(len(msg.data) + 1))
            data.extend(msg.data)
            data.append(0xf7)
            running_status_byte = None
        else:
            msg_bytes = msg.bytes()
            status_byte = msg_bytes[0]

            if status_byte == running_status_byte:
                data.extend(msg_bytes[1:])
            else:
                data.extend(msg_bytes)

            if status_byte < 0xf0:
                running_status_byte = status_byte
            else:
                running_status_byte = None

    write_chunk(outfile, b'MTrk', data)

def get_seconds_per_tick(tempo, ticks_per_beat):
    # Tempo is given in microseconds per beat (default 500000).
    # At this tempo there are (500000 / 1000000) == 0.5 seconds
    # per beat. At the default resolution of 480 ticks per beat
    # this is:
    #
    #    (500000 / 1000000) / 480 == 0.5 / 480 == 0.0010417
    #
    return (tempo / 1000000.0) / ticks_per_beat

class MidiFile(object):
    def __init__(self, filename=None, file=None,
                 type=1, ticks_per_beat=DEFAULT_TICKS_PER_BEAT,
                 charset='latin1',
                 debug=False,
                 clip=False
                 ):

        self.filename = filename
        self.type = type
        self.ticks_per_beat = ticks_per_beat
        self.charset = charset
        self.debug = debug
        self.clip = clip

        self.tracks = []

        if type not in range(3):
            raise ValueError(
                'invalid format {} (must be 0, 1 or 2)'.format(format))

        if file is not None:
            self._load(file)
        elif self.filename is not None:
            with io.open(filename, 'rb') as file:
                self._load(file)

    def add_track(self, name=None):
        """Add a new track to the file.

        This will create a new MidiTrack object and append it to the
        track list.
        """
        track = MidiTrack()
        if name is not None:
            track.name = name
        self.tracks.append(track)
        return track

    def _load(self, infile):
        if self.debug:
            infile = DebugFileWrapper(infile)

        with meta_charset(self.charset):
            if self.debug:
                _dbg('Header:')

            (self.type,
             num_tracks,
             self.ticks_per_beat) = read_file_header(infile)

            if self.debug:
                _dbg('-> type={}, tracks={}, ticks_per_beat={}'.format(
                    self.type, num_tracks, self.ticks_per_beat))
                _dbg()

            for i in range(num_tracks):
                if self.debug:
                    _dbg('Track {}:'.format(i))

                self.tracks.append(read_track(infile,
                                              debug=self.debug,
                                              clip=self.clip))
                # TODO: used to ignore EOFError. I hope things still work.

    @property
    def length(self):
        """Playback time in seconds.

        This will be computed by going through every message in every
        track and adding up delta times.
        """
        if self.type == 2:
            raise ValueError('impossible to compute length'
                             ' for type 2 (asynchronous) file')

        return sum(msg.time for msg in self)

    def __iter__(self):
        # The tracks of type 2 files are not in sync, so they can
        # not be played back like this.
        if self.type == 2:
            raise TypeError("can't merge tracks in type 2 (asynchronous) file")

        tempo = DEFAULT_TEMPO
        for msg in merge_tracks(self.tracks):
            # Convert message time from absolute time
            # in ticks to relative time in seconds.
            if msg.time > 0:
                delta = tick2second(msg.time, self.ticks_per_beat, tempo)
            else:
                delta = 0

            yield msg.copy(time=delta)

            if msg.type == 'set_tempo':
                tempo = msg.tempo

    def play(self, meta_messages=False):
        """Play back all tracks.

        The generator will sleep between each message by
        default. Messages are yielded with correct timing. The time
        attribute is set to the number of seconds slept since the
        previous message.

        By default you will only get normal MIDI messages. Pass
        meta_messages=True if you also want meta messages.

        You will receive copies of the original messages, so you can
        safely modify them without ruining the tracks.
        """
        t0 = time.time()
        input_time = 0.0

        for msg in self:
            input_time += msg.time

            # we compute the difference between the nominal combined time
            # and the actual time spent at this point
            duration_to_next_event = input_time - (time.time() - t0)

            if (duration_to_next_event > 0.0):
                time.sleep(duration_to_next_event)

            if isinstance(msg, MetaMessage) and not meta_messages:
                continue
            else:
                yield msg

    def save(self, filename=None, file=None):
        """Save to a file.

        If file is passed the data will be saved to that file. This is
        typically an in-memory file or and already open file like sys.stdout.

        If filename is passed the data will be saved to that file.

        Raises ValueError if both file and filename are None,
        or if a type 0 file has != one track.
        """
        if self.type == 0 and len(self.tracks) != 1:
            raise ValueError('type 0 file must have exactly 1 track')

        if file is not None:
            self._save(file)
        elif filename is not None:
            with io.open(filename, 'wb') as file:
                self._save(file)
        else:
            raise ValueError('requires filename or file')

    def _save(self, outfile):
        with meta_charset(self.charset):
            header = struct.pack('>hhh', self.type,
                                 len(self.tracks),
                                 self.ticks_per_beat)

            write_chunk(outfile, b'MThd', header)

            for track in self.tracks:
                write_track(outfile, track)

    def print_tracks(self, meta_only=False):
        """Prints out all messages in a .midi file.

        May take argument meta_only to show only meta messages.

        Use:
        print_tracks() -> will print all messages
        print_tracks(meta_only=True) -> will print only MetaMessages
        """
        for i, track in enumerate(self.tracks):
            print('=== Track {}'.format(i))
            for msg in track:
                if not isinstance(msg, MetaMessage) and meta_only:
                    pass
                else:
                    print('{!r}'.format(msg))

    def __repr__(self):
        return '<midi file {!r} type {}, {} tracks, {} messages>'.format(
            self.filename, self.type, len(self.tracks),
            sum([len(track) for track in self.tracks]))

    # The context manager has no purpose but is kept around since it was
    # used in examples in the past.
    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        return False
<|endoftext|>


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

import unittest
import SeleniumFramework as sf

class TestPlan( unittest.TestCase ):
    def setUp( self ):
        self.driver = sf.Driver()

    def tearDown( self ):
        del self.driver

    def test_001_open_close_browser(self):
        self.assertTrue(False)

    def test_002_navigate_to_webpage(self):
        self.assertTrue(False)

if __name__ == '__main__':
    unittest.main( warnings='ignore' )
<commit_msg>Setup initial test failure to open and close a browser.<commit_after>#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import unittest
import SeleniumFramework as sf

class TestPlan( unittest.TestCase ):
    def setUp( self ):
        self.driver = sf.Driver()

    def tearDown( self ):
        del self.driver

    def test_001_open_close_browser(self):
        self.assertTrue(False)

    def test_002_navigate_to_webpage(self):
        self.assertTrue(False)

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