<commit_before>
import errno
import os
import sys
import shutil
import platform
import sysconfig
from os.path import abspath, exists, join, split

from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext

def prepend_variables(args, variables):
  for var in variables:
    temp = os.getenv(var)
    if temp:
      if var == 'CMAKE_GENERATOR':
        args = ['-G', temp] + args
      else:
        args.insert(0, '-D' + var + '=' +temp)
  return args

def get_lib_full_path(path, partial):
  for file in os.listdir(path):
    if partial in file:
      return os.path.join(path, file)
  return None

def makedirs(folder, *args, **kwargs):
  try:
    return os.makedirs(folder, exist_ok=True, *args, **kwargs)
  except TypeError:
    # Unexpected arguments encountered
    pass

  try:
    # Should work is TypeError was caused by exist_ok, eg., Py2
    return os.makedirs(folder, *args, **kwargs)
  except OSError as e:
    if e.errno != errno.EEXIST:
      raise

    if os.path.isfile(folder):
      # folder is a file, raise OSError just like os.makedirs() in Py3
      raise

def get_dir_if_exists(variable, default):
  value = os.getenv(variable, default)
  value = abspath(value)
  if not exists(value):
    return None
  return value

global SRC_DIR
SRC_DIR = get_dir_if_exists('COPASI_SRC_DIR', abspath('.'))
global DEP_DIR
DEP_DIR = get_dir_if_exists('COPASI_DEP_DIR', '../copasi_dependencies/')
DEP_SRC_DIR = get_dir_if_exists('COPASI_DEP_SRC', '../copasi-dependencies/')
DEP_DIR32 = get_dir_if_exists('COPASI_DEP_DIR_32', '../win_copasi_dependencies_32/')
DEP_DIR64 = get_dir_if_exists('COPASI_DEP_DIR_64', '../win_copasi_dependencies_64/')

if not SRC_DIR:
  src_defined = os.getenv('COPASI_SRC_DIR')
  if src_defined:
    raise ValueError("COPASI Source defined as: {0}, but couldn't be found".format(src_defined))
  else:
    raise ValueError("COPASI Source not specified or not present, define COPASI_SRC_DIR.")

print ("Using COPASI from: {0}".format(SRC_DIR))

version_file_name = join(join(SRC_DIR, 'copasi'), 'CopasiVersion.h')
print ("Using version file: {0}".format(version_file_name))

if not exists(version_file_name):
  print(os.listdir(SRC_DIR))
  raise ValueError("Invalid COPASI Source directory, no version file, consider running ./gitTools/UpdateCopasiVersion.")

with open(version_file_name, 'r') as version_file:
  COPASI_VERSION_MAJOR = ''
  COPASI_VERSION_MINOR = ''
  COPASI_VERSION_BUILD = ''
  for line in version_file:
    if 'COPASI_VERSION_MAJOR' in line:
      COPASI_VERSION_MAJOR = line[line.rfind(' '):].strip()
    if 'COPASI_VERSION_MINOR' in line:
      COPASI_VERSION_MINOR = line[line.rfind(' '):].strip()
    if 'COPASI_VERSION_BUILD' in line:
      COPASI_VERSION_BUILD = line[line.rfind(' '):].strip()
  VERSION = '{0}.{1}.{2}'.format(COPASI_VERSION_MAJOR, COPASI_VERSION_MINOR, COPASI_VERSION_BUILD)

print ("Version is: {0}".format(VERSION))
print ("building for python: {0}".format(sys.version))

if not exists('COPASI'):
  makedirs('COPASI')

class CMakeExtension(Extension):
    """Override the default setuptools extension building."""

    def __init__(self, name, sources=(), **kwargs):
        """Initialize by passing on arguments."""
        # Don't invoke the original `build_ext` for this special extension.
        try:
          super(CMakeExtension, self).__init__(name=name, sources=list(sources), **kwargs)
        except:
          Extension.__init__(self, name, list(sources), **kwargs)

class CMakeBuild(build_ext):
    """Override `build_ext` to then register it in the command classes."""

    def run(self):
        """
        Call Cmake and build every extension.

        Overrides parent's method.

        """
        for ext in self.extensions:
            self.build_cmake(ext)
        try:
            super(CMakeBuild, self).run()
        except:
            build_ext.run(self)

    def build_cmake(self, extension):
        """Configure `extension` with CMake and build modules."""
        cwd = os.getcwd()
        build_temp = self.build_temp
        suffix = build_temp[build_temp.find('temp.') + 5:]
        if '/' in suffix:
          suffix = suffix[:suffix.rfind('/')]
        if '\\' in suffix:
          suffix = suffix[:suffix.rfind('\\')]

        ext_dir = self.get_ext_fullpath(extension.name)
        makedirs(build_temp)
        target_lib_path = abspath(ext_dir)
        target_dir_path, name = split(target_lib_path)
        makedirs(target_dir_path)
        makedirs(join(cwd, 'copasi'))

        print ('name: {0}'.format(name))
        print ('build temp: {0}'.format(build_temp))
        print ('extension name: {0}'.format(extension.name))
        print ('extension dir: {0}'.format(ext_dir))
        print ('target_dir_path: {0}'.format(target_dir_path))
        print ('target_lib_path: {0}'.format(target_lib_path))
        print ('suffix: {0}'.format(suffix))
        print ('cwd: {0}'.format(cwd))

        # example of cmake args
        config = 'Debug' if self.debug else 'Release'
        print ('name: {0}, tmp: {1}'.format(name, build_temp))
        is_osx = platform.system() == 'Darwin'
        is_win = platform.system() == 'Windows'
        is_win_32 = is_win and ('win32' in name or 'win32' in build_temp)
        enable_jit = 'ON' if ('_64' in suffix or 'amd64' in suffix) else 'OFF'

        cmake_args = [
            '-DCMAKE_BUILD_TYPE=' + config
        ]

        if is_win:
          cmake_args.append('-DWITH_STATIC_RUNTIME=ON')

        cmake_args = prepend_variables(cmake_args, [
          'CMAKE_CXX_COMPILER',
          'CMAKE_C_COMPILER',
          'CMAKE_LINKER',
          'CMAKE_GENERATOR',
          'CMAKE_OSX_ARCHITECTURES',
          'CMAKE_SYSTEM_PROCESSOR'
        ])

        if is_win_32:
          if not '-G' in str(cmake_args):
            cmake_args.append('-A')
            cmake_args.append('win32')

        if is_osx:
          cmake_args.append('-DCLANG_USE_LIBCPP=ON')
          cmake_args.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9')

        # example of build args
        build_args = [
            '--config', config,
            '--'
        ]

        global DEP_DIR
        if not DEP_DIR and not self.dry_run:
            print("compiling dependencies")
            dep_suffix = sysconfig.get_platform()
            dep_inst_dir = os.path.join(cwd, 'install_dependencies_' + dep_suffix)
            if not exists(dep_inst_dir):
               dep_build_dir = os.path.join(cwd, 'build_dependencies_' + dep_suffix)
               dep_src_dir = DEP_SRC_DIR
               makedirs(dep_build_dir)
               os.chdir(dep_build_dir)
               self.spawn(['cmake', dep_src_dir] + cmake_args
                         + [
                             '-DCMAKE_INSTALL_PREFIX=' + dep_inst_dir,
                             '-DBUILD_UI_DEPS=OFF',
                             '-DBUILD_zlib=ON',
                             '-DBUILD_archive=OFF',
                             '-DBUILD_NativeJIT=' + enable_jit
                           ]
                         )
               self.spawn(['cmake', '--build', '.'] + build_args)
               os.chdir(cwd)
            DEP_DIR = dep_inst_dir

        copasi_args = [
            '-DBUILD_GUI=OFF',
            '-DENABLE_PYTHON=ON',
            '-DPYTHON_EXECUTABLE=' + sys.executable,
            '-DPYTHON_INCLUDE_DIR=' + sysconfig.get_paths()['include'],
            '-DENABLE_JIT=' + enable_jit
        ]

        copasi_args = prepend_variables(copasi_args, [
          'SWIG_DIR',
          'SWIG_EXECUTABLE'
        ])

        if not is_win:
          copasi_args.append('-DPYTHON_USE_DYNAMIC_LOOKUP=ON')

        if not is_win and not is_osx:
          copasi_args.append('-DCMAKE_CXX_FLAGS=-fPIC')

        cmake_args = cmake_args + copasi_args

        if DEP_DIR:
          cmake_args.append('-DCOPASI_DEPENDENCY_DIR=' + DEP_DIR)
          cmake_args.append('-DLIBEXPAT_INCLUDE_DIR=' + join(DEP_DIR, 'include'))

        if is_win_32:
          if DEP_DIR32:
            cmake_args.append('-DCOPASI_DEPENDENCY_DIR=' + DEP_DIR32)
            cmake_args.append('-DLIBEXPAT_INCLUDE_DIR=' + join(DEP_DIR32, 'include'))
        elif is_win:
          if DEP_DIR64:
            cmake_args.append('-DCOPASI_DEPENDENCY_DIR=' + DEP_DIR64)
            cmake_args.append('-DLIBEXPAT_INCLUDE_DIR=' + join(DEP_DIR64, 'include'))

        os.chdir(build_temp)
        self.spawn(['cmake', SRC_DIR] + cmake_args)
        if not self.dry_run:
            self.spawn(['cmake', '--build', '.', '--target', 'binding_python_lib'] + build_args)

            # at this point the build should be complete, and we have all the files
            # neeed in the temp build_folder

            init_py2 = None
            init_py3 = None
            dst_file = join(target_dir_path, '__init__.py')

            for root, dirs, files in os.walk(".", topdown=False):
              for name in files:
                # 1. find pyd and copy to target_lib_path
                if name.endswith('.pyd') or name == '_COPASI.so' or name == '_COPASI.dylib':
                  pyd_file = join(root, name)
                  print('copying pyd file to output file')
                  shutil.copyfile(pyd_file, target_lib_path)
                # 2. get scripts and copy to target_lib_path.parent.__init__.py corresponding to version
                if name == 'COPASI.py':
                  src_file = join(root, name)
                  shutil.copyfile(src_file, dst_file)
                if name == 'COPASI2.py':
                  init_py2 = join(root, name)
                if name == 'COPASI3.py':
                  init_py3 = join(root, name)

            if init_py2 and exists(init_py2) and sys.version_info.major == 2:
                  shutil.copyfile(init_py2, dst_file)

            if init_py3 and exists(init_py3) and sys.version_info.major == 3:
                  shutil.copyfile(init_py3, dst_file)

        os.chdir(cwd)

setup(name             = "python-copasi",
      version          = VERSION,
      description      = "COPASI Python API",
      long_description = ("COPASI is a software application for simulation and analysis of biochemical networks and their dynamics. COPASI is a stand-alone program that supports models in the SBML standard and can simulate their behavior using ODEs or Gillespie's stochastic simulation algorithm; arbitrary discrete events can be included in such simulations."),
      license          = "Artistic License",
      author           = "COPASI Team",
      author_email     = "copasi-devel@copasi.org",
      url              = "http://copasi.org",
      packages         = ["COPASI"],
      package_dir      = {'COPASI': 'COPASI'},
      ext_package      = "COPASI",
      ext_modules=[CMakeExtension('_COPASI')],
      cmdclass={
        'build_ext': CMakeBuild,
      }
)
<commit_msg>- fix an issue where sometimes setup.py does not build dependencies<commit_after>
import errno
import os
import sys
import shutil
import platform
import sysconfig
from os.path import abspath, exists, join, split

from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext

def prepend_variables(args, variables):
  for var in variables:
    temp = os.getenv(var)
    if temp:
      if var == 'CMAKE_GENERATOR':
        args = ['-G', temp] + args
      else:
        args.insert(0, '-D' + var + '=' +temp)
  return args

def get_lib_full_path(path, partial):
  for file in os.listdir(path):
    if partial in file:
      return os.path.join(path, file)
  return None

def makedirs(folder, *args, **kwargs):
  try:
    return os.makedirs(folder, exist_ok=True, *args, **kwargs)
  except TypeError:
    # Unexpected arguments encountered
    pass

  try:
    # Should work is TypeError was caused by exist_ok, eg., Py2
    return os.makedirs(folder, *args, **kwargs)
  except OSError as e:
    if e.errno != errno.EEXIST:
      raise

    if os.path.isfile(folder):
      # folder is a file, raise OSError just like os.makedirs() in Py3
      raise

def get_dir_if_exists(variable, default):
  value = os.getenv(variable, default)
  value = abspath(value)
  if not exists(value):
    return None
  return value

global SRC_DIR
SRC_DIR = get_dir_if_exists('COPASI_SRC_DIR', abspath('.'))
global DEP_DIR
DEP_DIR = get_dir_if_exists('COPASI_DEP_DIR', '../copasi_dependencies/')
DEP_SRC_DIR = get_dir_if_exists('COPASI_DEP_SRC', '../copasi-dependencies/')
DEP_DIR32 = get_dir_if_exists('COPASI_DEP_DIR_32', '../win_copasi_dependencies_32/')
DEP_DIR64 = get_dir_if_exists('COPASI_DEP_DIR_64', '../win_copasi_dependencies_64/')

if not SRC_DIR:
  src_defined = os.getenv('COPASI_SRC_DIR')
  if src_defined:
    raise ValueError("COPASI Source defined as: {0}, but couldn't be found".format(src_defined))
  else:
    raise ValueError("COPASI Source not specified or not present, define COPASI_SRC_DIR.")

print ("Using COPASI from:  {0}".format(SRC_DIR))
print ("Using Dependencies: {0}".format(DEP_DIR))

version_file_name = join(join(SRC_DIR, 'copasi'), 'CopasiVersion.h')
print ("Using version file: {0}".format(version_file_name))

if not exists(version_file_name):
  print(os.listdir(SRC_DIR))
  raise ValueError("Invalid COPASI Source directory, no version file, consider running ./gitTools/UpdateCopasiVersion.")

with open(version_file_name, 'r') as version_file:
  COPASI_VERSION_MAJOR = ''
  COPASI_VERSION_MINOR = ''
  COPASI_VERSION_BUILD = ''
  for line in version_file:
    if 'COPASI_VERSION_MAJOR' in line:
      COPASI_VERSION_MAJOR = line[line.rfind(' '):].strip()
    if 'COPASI_VERSION_MINOR' in line:
      COPASI_VERSION_MINOR = line[line.rfind(' '):].strip()
    if 'COPASI_VERSION_BUILD' in line:
      COPASI_VERSION_BUILD = line[line.rfind(' '):].strip()
  VERSION = '{0}.{1}.{2}'.format(COPASI_VERSION_MAJOR, COPASI_VERSION_MINOR, COPASI_VERSION_BUILD)

print ("Version is: {0}".format(VERSION))
print ("building for python: {0}".format(sys.version))

if not exists('COPASI'):
  makedirs('COPASI')

class CMakeExtension(Extension):
    """Override the default setuptools extension building."""

    def __init__(self, name, sources=(), **kwargs):
        """Initialize by passing on arguments."""
        # Don't invoke the original `build_ext` for this special extension.
        try:
          super(CMakeExtension, self).__init__(name=name, sources=list(sources), **kwargs)
        except:
          Extension.__init__(self, name, list(sources), **kwargs)

class CMakeBuild(build_ext):
    """Override `build_ext` to then register it in the command classes."""

    def run(self):
        """
        Call Cmake and build every extension.

        Overrides parent's method.

        """
        for ext in self.extensions:
            self.build_cmake(ext)
        try:
            super(CMakeBuild, self).run()
        except:
            build_ext.run(self)

    def build_cmake(self, extension):
        """Configure `extension` with CMake and build modules."""
        cwd = os.getcwd()
        build_temp = self.build_temp
        suffix = build_temp[build_temp.find('temp.') + 5:]
        if '/' in suffix:
          suffix = suffix[:suffix.rfind('/')]
        if '\\' in suffix:
          suffix = suffix[:suffix.rfind('\\')]

        ext_dir = self.get_ext_fullpath(extension.name)
        makedirs(build_temp)
        target_lib_path = abspath(ext_dir)
        target_dir_path, name = split(target_lib_path)
        makedirs(target_dir_path)
        makedirs(join(cwd, 'copasi'))

        print ('name: {0}'.format(name))
        print ('build temp: {0}'.format(build_temp))
        print ('extension name: {0}'.format(extension.name))
        print ('extension dir: {0}'.format(ext_dir))
        print ('target_dir_path: {0}'.format(target_dir_path))
        print ('target_lib_path: {0}'.format(target_lib_path))
        print ('suffix: {0}'.format(suffix))
        print ('cwd: {0}'.format(cwd))

        # example of cmake args
        config = 'Debug' if self.debug else 'Release'
        print ('name: {0}, tmp: {1}'.format(name, build_temp))
        is_osx = platform.system() == 'Darwin'
        is_win = platform.system() == 'Windows'
        is_win_32 = is_win and ('win32' in name or 'win32' in build_temp)
        enable_jit = 'ON' if ('_64' in suffix or 'amd64' in suffix) else 'OFF'

        cmake_args = [
            '-DCMAKE_BUILD_TYPE=' + config
        ]

        if is_win:
          cmake_args.append('-DWITH_STATIC_RUNTIME=ON')

        cmake_args = prepend_variables(cmake_args, [
          'CMAKE_CXX_COMPILER',
          'CMAKE_C_COMPILER',
          'CMAKE_LINKER',
          'CMAKE_GENERATOR',
          'CMAKE_OSX_ARCHITECTURES',
          'CMAKE_SYSTEM_PROCESSOR'
        ])

        if is_win_32:
          if not '-G' in str(cmake_args):
            cmake_args.append('-A')
            cmake_args.append('win32')

        if is_osx:
          cmake_args.append('-DCLANG_USE_LIBCPP=ON')
          cmake_args.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9')

        # example of build args
        build_args = [
            '--config', config,
            '--'
        ]

        global DEP_DIR
        if exists(DEP_DIR) and not self.dry_run:
            print("compiling dependencies")
            dep_suffix = sysconfig.get_platform()
            dep_inst_dir = os.path.join(cwd, 'install_dependencies_' + dep_suffix)
            if not exists(dep_inst_dir):
               dep_build_dir = os.path.join(cwd, 'build_dependencies_' + dep_suffix)
               dep_src_dir = DEP_SRC_DIR
               makedirs(dep_build_dir)
               os.chdir(dep_build_dir)
               self.spawn(['cmake', dep_src_dir] + cmake_args
                         + [
                             '-DCMAKE_INSTALL_PREFIX=' + dep_inst_dir,
                             '-DBUILD_UI_DEPS=OFF',
                             '-DBUILD_zlib=ON',
                             '-DBUILD_archive=OFF',
                             '-DBUILD_NativeJIT=' + enable_jit
                           ]
                         )
               self.spawn(['cmake', '--build', '.'] + build_args)
               os.chdir(cwd)
            DEP_DIR = dep_inst_dir

        copasi_args = [
            '-DBUILD_GUI=OFF',
            '-DENABLE_PYTHON=ON',
            '-DPYTHON_EXECUTABLE=' + sys.executable,
            '-DPYTHON_INCLUDE_DIR=' + sysconfig.get_paths()['include'],
            '-DENABLE_JIT=' + enable_jit
        ]

        copasi_args = prepend_variables(copasi_args, [
          'SWIG_DIR',
          'SWIG_EXECUTABLE'
        ])

        if not is_win:
          copasi_args.append('-DPYTHON_USE_DYNAMIC_LOOKUP=ON')

        if not is_win and not is_osx:
          copasi_args.append('-DCMAKE_CXX_FLAGS=-fPIC')

        cmake_args = cmake_args + copasi_args

        if DEP_DIR:
          cmake_args.append('-DCOPASI_DEPENDENCY_DIR=' + DEP_DIR)
          cmake_args.append('-DLIBEXPAT_INCLUDE_DIR=' + join(DEP_DIR, 'include'))

        if is_win_32:
          if DEP_DIR32:
            cmake_args.append('-DCOPASI_DEPENDENCY_DIR=' + DEP_DIR32)
            cmake_args.append('-DLIBEXPAT_INCLUDE_DIR=' + join(DEP_DIR32, 'include'))
        elif is_win:
          if DEP_DIR64:
            cmake_args.append('-DCOPASI_DEPENDENCY_DIR=' + DEP_DIR64)
            cmake_args.append('-DLIBEXPAT_INCLUDE_DIR=' + join(DEP_DIR64, 'include'))

        os.chdir(build_temp)
        self.spawn(['cmake', SRC_DIR] + cmake_args)
        if not self.dry_run:
            self.spawn(['cmake', '--build', '.', '--target', 'binding_python_lib'] + build_args)

            # at this point the build should be complete, and we have all the files
            # neeed in the temp build_folder

            init_py2 = None
            init_py3 = None
            dst_file = join(target_dir_path, '__init__.py')

            for root, dirs, files in os.walk(".", topdown=False):
              for name in files:
                # 1. find pyd and copy to target_lib_path
                if name.endswith('.pyd') or name == '_COPASI.so' or name == '_COPASI.dylib':
                  pyd_file = join(root, name)
                  print('copying pyd file to output file')
                  shutil.copyfile(pyd_file, target_lib_path)
                # 2. get scripts and copy to target_lib_path.parent.__init__.py corresponding to version
                if name == 'COPASI.py':
                  src_file = join(root, name)
                  shutil.copyfile(src_file, dst_file)
                if name == 'COPASI2.py':
                  init_py2 = join(root, name)
                if name == 'COPASI3.py':
                  init_py3 = join(root, name)

            if init_py2 and exists(init_py2) and sys.version_info.major == 2:
                  shutil.copyfile(init_py2, dst_file)

            if init_py3 and exists(init_py3) and sys.version_info.major == 3:
                  shutil.copyfile(init_py3, dst_file)

        os.chdir(cwd)

setup(name             = "python-copasi",
      version          = VERSION,
      description      = "COPASI Python API",
      long_description = ("COPASI is a software application for simulation and analysis of biochemical networks and their dynamics. COPASI is a stand-alone program that supports models in the SBML standard and can simulate their behavior using ODEs or Gillespie's stochastic simulation algorithm; arbitrary discrete events can be included in such simulations."),
      license          = "Artistic License",
      author           = "COPASI Team",
      author_email     = "copasi-devel@copasi.org",
      url              = "http://copasi.org",
      packages         = ["COPASI"],
      package_dir      = {'COPASI': 'COPASI'},
      ext_package      = "COPASI",
      ext_modules=[CMakeExtension('_COPASI')],
      cmdclass={
        'build_ext': CMakeBuild,
      }
)
<|endoftext|>


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

import unittest
import copyspecial

class TestCopySpecial(unittest.TestCase):

    def setUp(self):
        pass

    def test_get_special_paths(self):
        test_dir = '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial'
        result = copyspecial.get_special_paths(test_dir)

        expected_result = [
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/__pycache__',
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/xyz__hello__.txt',
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/zz__something__.jpg'
        ]

        self.assertEqual(len(expected_result), len(result),
                         'get_special_paths({}) expected {} but got {}'.format(test_dir,
                                                                               len(expected_result),
                                                                               len(result)))
        self.assertEqual(expected_result, result,
                         'get_special_paths({}) expected {} but got {}'.format(test_dir,
                                                                               expected_result,
                                                                               result))

    def test_is_special_path(self):

        test_path_index = 0
        expected_result_index = 1

        test_datas = [
            ['', False],
            ['abc', False],
            ['__bar', False],
            ['____', False],
            ['/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/copyspecial.py', False],
            ['__foo__', True],
            ['/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/xyz__hello__.txt', True],
        ]

        for test_data in test_datas:
            test_path = test_data[test_path_index]
            result = copyspecial.is_special_path(test_path)
            expected_result = test_data[expected_result_index]
            self.assertEqual(expected_result, result,
                            'is_special_path({}) expected {} but got {}'.format(test_path,
                                                                                expected_result,
                                                                                result))

if __name__ == "__main__": unittest.main()
<commit_msg>In test_get_special_paths add test case '.'<commit_after>#!/usr/bin/env python3

import unittest
import copyspecial

class TestCopySpecial(unittest.TestCase):

    def setUp(self):
        pass

    def test_get_special_paths(self):
        test_dir = '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial'
        result = copyspecial.get_special_paths(test_dir)

        expected_result = [
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/__pycache__',
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/xyz__hello__.txt',
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/zz__something__.jpg'
        ]

        self.assertEqual(len(expected_result), len(result),
                         'get_special_paths({}) expected {} but got {}'.format(test_dir,
                                                                               len(expected_result),
                                                                               len(result)))
        self.assertEqual(expected_result, result,
                         'get_special_paths({}) expected {} but got {}'.format(test_dir,
                                                                               expected_result,
                                                                               result))

        test_dir = '.'
        result = copyspecial.get_special_paths(test_dir)

        expected_result = [
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/__pycache__',
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/xyz__hello__.txt',
            '/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/zz__something__.jpg'
        ]

        self.assertEqual(len(expected_result), len(result),
                         'get_special_paths({}) expected {} but got {}'.format(test_dir,
                                                                               len(expected_result),
                                                                               len(result)))
        self.assertEqual(expected_result, result,
                         'get_special_paths({}) expected {} but got {}'.format(test_dir,
                                                                               expected_result,
                                                                               result))

    def test_is_special_path(self):

        test_path_index = 0
        expected_result_index = 1

        test_datas = [
            ['', False],
            ['abc', False],
            ['__bar', False],
            ['____', False],
            ['/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/copyspecial.py', False],
            ['__foo__', True],
            ['/Users/stevebaker/Documents/projects/pythonProjects/google-python-exercises/copyspecial/xyz__hello__.txt', True],
        ]

        for test_data in test_datas:
            test_path = test_data[test_path_index]
            result = copyspecial.is_special_path(test_path)
            expected_result = test_data[expected_result_index]
            self.assertEqual(expected_result, result,
                            'is_special_path({}) expected {} but got {}'.format(test_path,
                                                                                expected_result,
                                                                                result))

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


<commit_before># Software License Agreement (BSD License)
#
# Copyright (c) 2009-2012, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
# without modification, are permitted provided that the following conditions
# are met:
#
#   Redistributions of source code must retain the above
#   copyright notice, this list of conditions and the
#   following disclaimer.
#
#   Redistributions in binary form must reproduce the above
#   copyright notice, this list of conditions and the
#   following disclaimer in the documentation and/or other
#   materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from euca2ools import __version__
import glob
import os.path
import platform
import requestbuilder
import requests
import sys

class Euca2ools(object):
    '''
    A class with attributes and methods that define the entire euca2ools suite
    '''

    def __init__(self):
        self.__user_agent = None

    @staticmethod
    def print_version_and_exit():
        print >> sys.stderr, 'euca2ools', __version__, '(Sparta)'
        try:
            if os.path.isfile('/etc/eucalyptus/eucalyptus-version'):
                with open('/etc/eucalyptus/eucalyptus-version') as ver_file:
                    euca_version = ver_file.readline().strip()
                print >> sys.stderr, 'eucalyptus', euca_version
        except:
            # Those were just more crunchy bits.  If they don't work, oh well!
            pass
        sys.exit()

    @staticmethod
    def list_config_files():
        sys_config_files = ['/etc/euca2ools.ini']
        user_glob = os.path.join(os.path.expanduser('~/.euca'), '*.ini')
        user_config_files = sorted(glob.glob(user_glob))
        return sys_config_files + user_config_files

    def get_user_agent(self):
        if self.__user_agent is None:
            user_agent_bits = ['euca2ools/{0}'.format(__version__)]

            tokens = []
            impl = platform.python_implementation()
            if impl == 'PyPy':
                impl_version = '{0}.{1}.{2}'.format(
                        sys.pypy_version_info.major,
                        sys.pypy_version_info.minor,
                        sys.pypy_version_info.micro)
                if sys.pypy_version_info.releaselevel != 'final':
                    impl_version += sys.pypy_version_info.releaselevel
            else:
                # I'm guessing for non-CPython implementations; feel free to
                # submit patches or the needed implementation-specific API
                # references.
                impl_version = platform.python_version()
            tokens.append('{0} {1}'.format(impl, impl_version))
            plat = []
            try:
                plat.append(platform.system())
                plat.append(platform.release())
            except IOError:
                pass
            if plat:
                tokens.append(' '.join(plat))
            tokens.append(platform.machine())
            user_agent_bits.append('({0})'.format('; '.join(tokens)))

            user_agent_bits.append('requestbuilder/{0}'.format(
                    requestbuilder.__version__))
            user_agent_bits.append('requests/{0}'.format(requests.__version__))
            self.__user_agent = ' '.join(user_agent_bits)
        return self.__user_agent
<commit_msg>Also look for configuration in /etc/euca2ools/conf.d/*.ini<commit_after># Software License Agreement (BSD License)
#
# Copyright (c) 2009-2012, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
# without modification, are permitted provided that the following conditions
# are met:
#
#   Redistributions of source code must retain the above
#   copyright notice, this list of conditions and the
#   following disclaimer.
#
#   Redistributions in binary form must reproduce the above
#   copyright notice, this list of conditions and the
#   following disclaimer in the documentation and/or other
#   materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from euca2ools import __version__
import glob
import os.path
import platform
import requestbuilder
import requests
import sys

class Euca2ools(object):
    '''
    A class with attributes and methods that define the entire euca2ools suite
    '''

    CONFIG_PATHS = ('/etc/euca2ools/euca2ools.ini',
                    '/etc/euca2ools/conf.d/*.ini',
                    '~/.euca/*.ini')

    def __init__(self):
        self.__user_agent = None

    @staticmethod
    def print_version_and_exit():
        print >> sys.stderr, 'euca2ools', __version__, '(Sparta)'
        try:
            if os.path.isfile('/etc/eucalyptus/eucalyptus-version'):
                with open('/etc/eucalyptus/eucalyptus-version') as ver_file:
                    euca_version = ver_file.readline().strip()
                print >> sys.stderr, 'eucalyptus', euca_version
        except:
            # Those were just more crunchy bits.  If they don't work, oh well!
            pass
        sys.exit()

    def list_config_files(self):
        config_files = []
        if 'EUCA_CONFIG_PATH' in os.environ:
            config_globs = os.getenv('EUCA_CONFIG_PATH').split(':')
        else:
            config_globs = self.CONFIG_PATHS
        for config_glob in config_globs:
            expanded = os.path.expanduser(os.path.expandvars(config_glob))
            config_files.extend(sorted(glob.glob(expanded)))
        return config_files

    def get_user_agent(self):
        if self.__user_agent is None:
            user_agent_bits = ['euca2ools/{0}'.format(__version__)]

            tokens = []
            impl = platform.python_implementation()
            if impl == 'PyPy':
                impl_version = '{0}.{1}.{2}'.format(
                        sys.pypy_version_info.major,
                        sys.pypy_version_info.minor,
                        sys.pypy_version_info.micro)
                if sys.pypy_version_info.releaselevel != 'final':
                    impl_version += sys.pypy_version_info.releaselevel
            else:
                # I'm guessing for non-CPython implementations; feel free to
                # submit patches or the needed implementation-specific API
                # references.
                impl_version = platform.python_version()
            tokens.append('{0} {1}'.format(impl, impl_version))
            plat = []
            try:
                plat.append(platform.system())
                plat.append(platform.release())
            except IOError:
                pass
            if plat:
                tokens.append(' '.join(plat))
            tokens.append(platform.machine())
            user_agent_bits.append('({0})'.format('; '.join(tokens)))

            user_agent_bits.append('requestbuilder/{0}'.format(
                    requestbuilder.__version__))
            user_agent_bits.append('requests/{0}'.format(requests.__version__))
            self.__user_agent = ' '.join(user_agent_bits)
        return self.__user_agent
<|endoftext|>


<commit_before>from django.contrib.auth.models import User
from django.db import models

from events.models import Event

class Invitation(models.Model):
    ACCEPTED = 'A'
    REJECTED = 'R'
    PENDING = 'P'

    STATUS_CHOICES = (
        (ACCEPTED, 'Accepted'),
        (REJECTED, 'Rejected'),
        (PENDING, 'Pending')
    )

    inviter = models.ForeignKey(User, related_name='%(class)s_sent')
    to_user = models.ForeignKey(User, related_name='%(class)s_received')
    status = models.CharField(choices=STATUS_CHOICES, max_length=1, default=PENDING)

    class Meta:
        abstract = True

    def __str__(self):
        return f'{self.to_user.username} invited by {self.inviter.username}'

class EventInvitation(Invitation):
    event = models.ForeignKey(Event, related_name='invitations')

    class Meta:
        unique_together = (('to_user', 'event'),)

class FriendInvitation(Invitation):
    class Meta:
        unique_together = (('inviter', 'to_user'),)
<commit_msg>added FriendInvitation manager, added new choice - DUPLICATED<commit_after>from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db import models

from events.models import Event

class Invitation(models.Model):
    ACCEPTED = 'A'
    REJECTED = 'R'
    PENDING = 'P'
    DUPLICATED = 'D'

    STATUS_CHOICES = (
        (ACCEPTED, 'Accepted'),
        (REJECTED, 'Rejected'),
        (PENDING, 'Pending'),
        (DUPLICATED, 'Duplicated'),
    )

    from_user = models.ForeignKey(User, related_name='%(app_label)s_%(class)s_sent')
    to_user = models.ForeignKey(User, related_name='%(app_label)s_%(class)s_received')
    status = models.CharField(choices=STATUS_CHOICES, max_length=1, default=PENDING)

    class Meta:
        abstract = True

    def __str__(self):
        return f'{self.to_user_id} invited by {self.from_user_id}'

class EventInvitation(Invitation):
    event = models.ForeignKey(Event, related_name='invitations')

    class Meta:
        unique_together = ('to_user', 'event')

class FriendInvivationManager(models.Manager):
    def send_invitation(self, from_user, to_user):
        if from_user == to_user:
            raise ValidationError('from_user and to_user cannot be identical')

        obj, created = FriendInvitation.objects.get_or_create(from_user=from_user, to_user=to_user)

        if created:
            FriendInvitation.objects.get_or_create(from_user=to_user, to_user=from_user,
                                                   status=FriendInvitation.DUPLICATED)
            return True
        return False

class FriendInvitation(Invitation):
    objects = FriendInvivationManager()

    class Meta:
        unique_together = ('from_user', 'to_user')
<|endoftext|>


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

import json
import subprocess

results = {}

def is_encrypted(device):
    try:
        subprocess.check_output(['cryptsetup', 'status', device])
        return True
    except:
        pass
    # I hope it's a logical volume!
    vg = subprocess.check_output(
        ('lvs', '--noheadings', '-o', 'vg_name',
         device), close_fds=True).decode('ascii').strip()
    pv_output = subprocess.check_output(
        ('vgs', '--noheadings', '-o', 'pv_name', vg),
        close_fds=True).decode('ascii').strip()
    pvs = pv_output.split('\n')
    return all(is_encrypted(p) for p in pvs)

for mount in open('/proc/mounts'):
    mount = mount.strip()
    device, mountpoint, type, options, freq, passno = mount.split(' ')
    if type in ('autofs', 'binfmt_misc', 'cgroup', 'debugfs', 'devpts',
                'devtmpfs', 'hugetlbfs', 'mqueue', 'nfs', 'proc', 'pstore',
                'rpc_pipefs', 'securityfs', 'sysfs', 'tmpfs', 'tracefs',
                'cgroup2', 'configfs', 'vboxsf', 'efivarfs'):
        continue
    if type.startswith('fuse'):
        continue
    if mountpoint == '/boot':
        continue
    if device.find(':') > -1:
        # Remote device
        continue
    results[mountpoint] = {'mountpoint': mountpoint,
                           'device': device,
                           'encrypted': is_encrypted(device)}

print(json.dumps(list(results.values())))
<commit_msg>Be more resilient when encountering non-encryption<commit_after>#!/usr/bin/env python3

import json
import subprocess

from qlmdm.client import get_logger

results = {}
log = get_logger('plugins/hd_encryption')

def is_encrypted(device):
    try:
        subprocess.check_output(['cryptsetup', 'status', device])
        return True
    except:
        pass
    try:
        # I hope it's a logical volume!
        vg = subprocess.check_output(
            ('lvs', '--noheadings', '-o', 'vg_name',
             device), close_fds=True).decode('ascii').strip()
    except:
        log.info('Cryptsetup and lvs on {} failed, assuming not encrypted',
                 device)
        return False
    pv_output = subprocess.check_output(
        ('vgs', '--noheadings', '-o', 'pv_name', vg),
        close_fds=True).decode('ascii').strip()
    pvs = pv_output.split('\n')
    return all(is_encrypted(p) for p in pvs)

for mount in open('/proc/mounts'):
    mount = mount.strip()
    device, mountpoint, type, options, freq, passno = mount.split(' ')
    if type in ('autofs', 'binfmt_misc', 'cgroup', 'debugfs', 'devpts',
                'devtmpfs', 'hugetlbfs', 'mqueue', 'nfs', 'proc', 'pstore',
                'rpc_pipefs', 'securityfs', 'sysfs', 'tmpfs', 'tracefs',
                'cgroup2', 'configfs', 'vboxsf', 'efivarfs'):
        continue
    if type.startswith('fuse'):
        continue
    if mountpoint == '/boot':
        continue
    if device.find(':') > -1:
        # Remote device
        continue
    results[mountpoint] = {'mountpoint': mountpoint,
                           'device': device,
                           'encrypted': is_encrypted(device)}

print(json.dumps(list(results.values())))
<|endoftext|>


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

# a simple code to backup critical directories on your machine to a
# separate local disk mounted on that machine.  Several copies are
# kept and an e-mail is sent at the completion.
#
# (use at your own risk...)

import sys
import os
import datetime
import shutil
import smtplib
import ConfigParser
import argparse
from email.mime.text import MIMEText

class Backup:
    """ a simple container class to hold the main information about
        the backup """
    def __init__(self, root, prefix, nstore,
                 email_sender, email_receiver):

        self.root = root
        self.prefix = prefix

        self.nstore = int(nstore)

        self.sender = email_sender
        self.receiver = email_receiver

        dt = datetime.datetime.now()
        self.date = str(dt.replace(second=0, microsecond=0)).replace(" ", "_")

class Log:
    """ a simple logging facility """
    def __init__(self, str=""):
        self.str = str

    def log(self, str):
        print str,
        sys.stdout.flush()
        self.str += str

def report(body, subject, sender, receiver):
    """ send an email """
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = receiver

    try:
        smtpObj = smtplib.SMTP('localhost')
        smtpObj.sendmail(sender, receiver, msg.as_string())
    except SMTPException:
        sys.exit("ERROR sending mail")

def do_backup(infile, simulate=False):

    # parse the input file
    cp = ConfigParser.ConfigParser()
    cp.optionxform = str
    cp.read(infile)

    # store the list of files and directories we will backup

    # in each dictionary, the key is the root directory to copy from and the
    # list it indexes is the list of files/directories under that root to copy
    dirs = {}
    files = {}

    for sec in cp.sections():

        if sec == "main":

            # defaults
            root = "/backup"
            prefix = "my-backup-"
            nstore = 3
            email_sender = "root"
            email_receiver = "root"

            for opt in cp.options("main"):
                if opt == "root":
                    root = cp.get(sec, opt)
                elif opt == "prefix":
                    prefix = cp.get(sec, opt)
                elif opt == "nstore":
                    nstore = cp.get(sec, opt)
                elif opt == "email_sender":
                    email_sender = cp.get(sec, opt)
                elif opt == "email_receiver":
                    email_receiver = cp.get(sec, opt)
                else:
                    sys.exit("invalid option in [main]")

                bo = Backup(root, prefix, nstore,
                            email_sender, email_receiver)
        else:

            for opt in cp.options(sec):
                value = cp.get(sec, opt)

                if opt == "files":
                    flist = [f.strip() for f in value.split(',')]
                    files[sec] = flist

                if opt == "dirs":
                    dlist = [d.strip() for d in value.split(',')]
                    dirs[sec] = dlist

    # log the output
    outMsg = "Output from backup-machine.py, inputs file: {}\n".format(infile)

    blog = Log(outMsg)

    # make sure that the output directory exists and if so, get all the
    # subdirectories in it
    try: old_dirs = os.listdir(bo.root)
    except:
        blog.log("destination directory is not readable/doesn't exist\n")
        report(blog.str, subjectFail, bo.sender, bo.receiver)
        sys.exit("directory not readable")

    # how many existing backups are in that directory?
    backup_dirs = []
    for dir in old_dirs:
        if (dir.startswith(bo.prefix) and
            os.path.isdir(bo.root + '/' + dir)):
            backup_dirs.append(dir)

    backup_dirs.sort()
    backup_dirs.reverse()

    # backup_dirs now contains a list of all the currently stored backups.
    # The most recent backups are at the start of the list.
    print "currently stored backups: "
    for n in range(len(backup_dirs)):
        print backup_dirs[n]

    # get ready for the new backups
    backup_dest = os.path.normpath(bo.root) + '/' + bo.prefix + bo.date

    if not simulate:
        try: os.mkdir(backup_dest)
        except:
            blog.log("error making directory\n")
            report(blog.str, subjectFail, bo.sender, bo.receiver)
            sys.exit("Error making dir")
    else:
        blog.log("mkdir {}\n".format(backup_dest))

    blog.log("writing to: %s\n\n" % (backup_dest) )

    failure = 0

    # backup all the directories
    for root_dir in dirs.keys():
        for d in dirs[root_dir]:

            mydir = os.path.normpath(root_dir) + '/' + d
            if not os.path.isdir(mydir):
                blog.log("WARNING: directory {} does not exist... skipping.\n".format(mydir))
                continue
            else:
                blog.log("copying {}/{} ...\n".format(root_dir, d))

            if not simulate:
                 try: shutil.copytree(mydir,
                                      os.path.normpath(backup_dest) + '/' + d,
                                      symlinks=True)
                 except:
                     blog.log("ERROR copying\n")
                     blog.log("aborting\n")
                     failure = 1
                     break

    blog.log("done with directories\n\n")

    # backup all the files
    for root_dir in files.keys():
        for f in files[root_dir]:

            myfile = os.path.normpath(root_dir) + '/' + f
            if not os.path.isfile(myfile):
                blog.log("WARNING: file {} does not exist... skipping.\n".format(myfile))
                continue
            else:
                blog.log("copying {}/{} ...\n".format(root_dir, f))

            if not simulate:
                try: shutil.copy(myfile,
                                 os.path.normpath(backup_dest) + '/' + f)
                except:
                    blog.log("ERROR copying\n")
                    blog.log("aborting\n")
                    failure = 1
                    break

    blog.log("done with individual files\n\n")

    # if we were successful, then remove any old backups, as necessary
    if not failure:

        # keep in mind that we just stored another backup
        if len(backup_dirs) > bo.nstore-1:
            n = bo.nstore-1

            while n < len(backup_dirs):
                rmDir = bo.root + '/' + backup_dirs[n]

                blog.log("removing old backup: %s\n" % (rmDir) )

                if not simulate:
                    try: shutil.rmtree(rmDir)
                    except:
                        blog.log("ERROR removing %s\n" % (rmDir) )

                n += 1

        subject = "summary from backup-machine.py, infile: {}".format(infile)
        if simulate:
            subject = "[simulate] " + subject
    else:
        subject = "ERROR from backup-machine.py, infile: {}".format(infile)

    report(blog.str, subject, bo.sender, bo.receiver)

if __name__ == "__main__":

    # parse any runtime options
    parser = argparse.ArgumentParser()
    parser.add_argument("-s",
                        help="don't do any copies, just output the steps that would be done",
                        action="store_true")
    parser.add_argument("inputfile", metavar="inputfile", type=str, nargs=1,
                        help="the input file specifying the backup configuration")

    args = parser.parse_args()

    do_backup(args.inputfile[0], simulate=args.s)
<commit_msg>be a little more specific with errors<commit_after>#!/usr/bin/env python

# a simple code to backup critical directories on your machine to a
# separate local disk mounted on that machine.  Several copies are
# kept and an e-mail is sent at the completion.
#
# (use at your own risk...)

import sys
import os
import datetime
import shutil
import smtplib
import ConfigParser
import argparse
from email.mime.text import MIMEText

class Backup:
    """ a simple container class to hold the main information about
        the backup """
    def __init__(self, root, prefix, nstore,
                 email_sender, email_receiver):

        self.root = root
        self.prefix = prefix

        self.nstore = int(nstore)

        self.sender = email_sender
        self.receiver = email_receiver

        dt = datetime.datetime.now()
        self.date = str(dt.replace(second=0, microsecond=0)).replace(" ", "_")

class Log:
    """ a simple logging facility """
    def __init__(self, str=""):
        self.str = str

    def log(self, str):
        print str,
        sys.stdout.flush()
        self.str += str

def report(body, subject, sender, receiver):
    """ send an email """
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = receiver

    try:
        smtpObj = smtplib.SMTP('localhost')
        smtpObj.sendmail(sender, receiver, msg.as_string())
    except SMTPException:
        sys.exit("ERROR sending mail")

def do_backup(infile, simulate=False):

    # parse the input file
    cp = ConfigParser.ConfigParser()
    cp.optionxform = str
    cp.read(infile)

    # store the list of files and directories we will backup

    # in each dictionary, the key is the root directory to copy from and the
    # list it indexes is the list of files/directories under that root to copy
    dirs = {}
    files = {}

    for sec in cp.sections():

        if sec == "main":

            # defaults
            root = "/backup"
            prefix = "my-backup-"
            nstore = 3
            email_sender = "root"
            email_receiver = "root"

            for opt in cp.options("main"):
                if opt == "root":
                    root = cp.get(sec, opt)
                elif opt == "prefix":
                    prefix = cp.get(sec, opt)
                elif opt == "nstore":
                    nstore = cp.get(sec, opt)
                elif opt == "email_sender":
                    email_sender = cp.get(sec, opt)
                elif opt == "email_receiver":
                    email_receiver = cp.get(sec, opt)
                else:
                    sys.exit("invalid option in [main]")

                bo = Backup(root, prefix, nstore,
                            email_sender, email_receiver)
        else:

            for opt in cp.options(sec):
                value = cp.get(sec, opt)

                if opt == "files":
                    flist = [f.strip() for f in value.split(',')]
                    files[sec] = flist

                if opt == "dirs":
                    dlist = [d.strip() for d in value.split(',')]
                    dirs[sec] = dlist

    # log the output
    outMsg = "Output from backup-machine.py, inputs file: {}\n".format(infile)

    blog = Log(outMsg)

    # make sure that the output directory exists and if so, get all the
    # subdirectories in it
    try: old_dirs = os.listdir(bo.root)
    except:
        blog.log("destination directory is not readable/doesn't exist\n")
        report(blog.str, subjectFail, bo.sender, bo.receiver)
        sys.exit("directory not readable")

    # how many existing backups are in that directory?
    backup_dirs = []
    for dir in old_dirs:
        if (dir.startswith(bo.prefix) and
            os.path.isdir(bo.root + '/' + dir)):
            backup_dirs.append(dir)

    backup_dirs.sort()
    backup_dirs.reverse()

    # backup_dirs now contains a list of all the currently stored backups.
    # The most recent backups are at the start of the list.
    print "currently stored backups: "
    for n in range(len(backup_dirs)):
        print backup_dirs[n]

    # get ready for the new backups
    backup_dest = os.path.normpath(bo.root) + '/' + bo.prefix + bo.date

    if not simulate:
        try: os.mkdir(backup_dest)
        except:
            blog.log("error making directory\n")
            report(blog.str, subjectFail, bo.sender, bo.receiver)
            sys.exit("Error making dir")
    else:
        blog.log("mkdir {}\n".format(backup_dest))

    blog.log("writing to: %s\n\n" % (backup_dest) )

    failure = 0

    # backup all the directories
    for root_dir in dirs.keys():
        for d in dirs[root_dir]:

            mydir = os.path.normpath(root_dir) + '/' + d
            if not os.path.isdir(mydir):
                blog.log("WARNING: directory {} does not exist... skipping.\n".format(mydir))
                continue
            else:
                blog.log("copying {}/{} ...\n".format(root_dir, d))

            if not simulate:
                 try: shutil.copytree(mydir,
                                      os.path.normpath(backup_dest) + '/' + d,
                                      symlinks=True)
                 except:
                     blog.log("ERROR copying {}\n".format(mydir))
                     blog.log("aborting\n")
                     failure = 1
                     break

    blog.log("done with directories\n\n")

    # backup all the files
    for root_dir in files.keys():
        for f in files[root_dir]:

            myfile = os.path.normpath(root_dir) + '/' + f
            if not os.path.isfile(myfile):
                blog.log("WARNING: file {} does not exist... skipping.\n".format(myfile))
                continue
            else:
                blog.log("copying {}/{} ...\n".format(root_dir, f))

            if not simulate:
                try: shutil.copy(myfile,
                                 os.path.normpath(backup_dest) + '/' + f)
                except:
                    blog.log("ERROR copying\n")
                    blog.log("aborting\n")
                    failure = 1
                    break

    blog.log("done with individual files\n\n")

    # if we were successful, then remove any old backups, as necessary
    if not failure:

        # keep in mind that we just stored another backup
        if len(backup_dirs) > bo.nstore-1:
            n = bo.nstore-1

            while n < len(backup_dirs):
                rmDir = bo.root + '/' + backup_dirs[n]

                blog.log("removing old backup: %s\n" % (rmDir) )

                if not simulate:
                    try: shutil.rmtree(rmDir)
                    except:
                        blog.log("ERROR removing %s\n" % (rmDir) )

                n += 1

        subject = "summary from backup-machine.py, infile: {}".format(infile)
        if simulate:
            subject = "[simulate] " + subject
    else:
        subject = "ERROR from backup-machine.py, infile: {}".format(infile)

    report(blog.str, subject, bo.sender, bo.receiver)

if __name__ == "__main__":

    # parse any runtime options
    parser = argparse.ArgumentParser()
    parser.add_argument("-s",
                        help="don't do any copies, just output the steps that would be done",
                        action="store_true")
    parser.add_argument("inputfile", metavar="inputfile", type=str, nargs=1,
                        help="the input file specifying the backup configuration")

    args = parser.parse_args()

    do_backup(args.inputfile[0], simulate=args.s)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Django settings for blog project.

For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""
from __future__ import absolute_import, unicode_literals

import environ

ROOT_DIR = environ.Path(__file__) - 3  # (/a/b/myfile.py - 3 = /)
APPS_DIR = ROOT_DIR.path('blog-wagtail')

env = environ.Env()

# APP CONFIGURATION
# ------------------------------------------------------------------------------
DJANGO_APPS = (
    # Default Django apps:
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Useful template tags:
    # 'django.contrib.humanize',

    # Admin
    'django.contrib.admin',
)
THIRD_PARTY_APPS = (
    'crispy_forms',  # Form layouts
    'allauth',  # registration
    'allauth.account',  # registration
    'allauth.socialaccount',  # registration
    'taggit',  # models tagging
    'compressor',  # static compressor
    'modelcluster',  # add possibility to use a foreign key field without
                     # instantiating the object

)
# wagtail core apps
WAGTAIL = (
    'wagtail.wagtailcore',
    'wagtail.wagtailadmin',
    'wagtail.wagtailsearch',
    'wagtail.wagtailimages',
    'wagtail.wagtaildocs',
    'wagtail.wagtailsnippets',
    'wagtail.wagtailusers',
    'wagtail.wagtailsites',
    'wagtail.wagtailembeds',
    'wagtail.wagtailredirects',
    'wagtail.wagtailforms',
    'wagtail.contrib.wagtailapi',
)
# Apps specific for this project go here.
LOCAL_APPS = (
    'blog-wagtail.users',  # custom users app
    'home',  # front page
    'blog',
    'about',
    'portofolio',
    'django_seo_js',
)

# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + WAGTAIL + LOCAL_APPS

# MIDDLEWARE CONFIGURATION
# ------------------------------------------------------------------------------
MIDDLEWARE_CLASSES = (
    # Make sure djangosecure.middleware.SecurityMiddleware is listed first
    'sslify.middleware.SSLifyMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    'wagtail.wagtailcore.middleware.SiteMiddleware',
    'wagtail.wagtailredirects.middleware.RedirectMiddleware',
)

# MIGRATIONS CONFIGURATION
# ------------------------------------------------------------------------------
# MIGRATION_MODULES = {
#     'sites': 'blog-wagtail.contrib.sites.migrations'
# }

# DEBUG
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
DEBUG = env.bool("DJANGO_DEBUG", False)

# FIXTURE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS
FIXTURE_DIRS = (
    str(APPS_DIR.path('fixtures')),
)

# DATABASE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES = {
    # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
    'default': env.db("DATABASE_URL", default="postgres://localhost/blog-wagtail"),
}
DATABASES['default']['ATOMIC_REQUESTS'] = True

# GENERAL CONFIGURATION
# ------------------------------------------------------------------------------
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# In a Windows environment this must be set to your system time zone.
TIME_ZONE = 'GMT'

# See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code
LANGUAGE_CODE = 'en-us'

# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
SITE_ID = 1

# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
USE_I18N = True

# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n
USE_L10N = True

# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
USE_TZ = True

# TEMPLATE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#templates
TEMPLATES = [
    {
        # See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
        'DIRS': [
            str(APPS_DIR.path('templates')),
        ],
        'OPTIONS': {
            # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
            'debug': DEBUG,
            # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
            # https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
            'loaders': [
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
            ],
            # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.template.context_processors.i18n',
                'django.template.context_processors.media',
                'django.template.context_processors.static',
                'django.template.context_processors.tz',
                'django.contrib.messages.context_processors.messages',
                # Your stuff: custom template context processors go here
            ],
        },
    },
]

# See: http://django-crispy-forms.readthedocs.org/en/latest/install.html#template-packs
CRISPY_TEMPLATE_PACK = 'bootstrap3'

# STATIC FILE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = str(ROOT_DIR('staticfiles'))

# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = '/static/'

# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
STATICFILES_DIRS = (
    str(APPS_DIR.path('static')),
)

# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'compressor.finders.CompressorFinder',
)

# MEDIA CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
MEDIA_ROOT = str(APPS_DIR('media'))

# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
MEDIA_URL = '/media/'

# URL Configuration
# ------------------------------------------------------------------------------
ROOT_URLCONF = 'config.urls'

# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
# remoed in PAW
# WSGI_APPLICATION = 'config.wsgi.application'

# AUTHENTICATION CONFIGURATION
# ------------------------------------------------------------------------------
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
)

# Custom user app defaults
# Select the correct user model
AUTH_USER_MODEL = 'users.User'
LOGIN_REDIRECT_URL = 'users:redirect'
LOGIN_URL = 'account_login'

# SLUGLIFIER
AUTOSLUG_SLUGIFY_FUNCTION = 'slugify.slugify'

# Your common stuff: Below this line define 3rd party library settings

# Wagtail
# -----------------------------------------------------------------------------
WAGTAIL_SITE_NAME = "abiraf"

# Wagtail API
# -----------------------------------------------------------------------------
WAGTAILAPI_LIMIT_MAX = 1000

# Django Compressor
# -----------------------------------------------------------------------------
COMPRESS_ENABLED = True
COMPRESS_ROOT = str(ROOT_DIR('staticfiles'))
COMPRESS_CSS_FILTERS = ['compressor.filters.cssmin.rCSSMinFilter',
                        'compressor.filters.css_default.CssAbsoluteFilter',
                        ]
COMPRESS_JS_FILTERS = ['compressor.filters.jsmin.JSMinFilter']
<commit_msg>fixed not including new seo middleware<commit_after># -*- coding: utf-8 -*-
"""
Django settings for blog project.

For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""
from __future__ import absolute_import, unicode_literals

import environ

ROOT_DIR = environ.Path(__file__) - 3  # (/a/b/myfile.py - 3 = /)
APPS_DIR = ROOT_DIR.path('blog-wagtail')

env = environ.Env()

# APP CONFIGURATION
# ------------------------------------------------------------------------------
DJANGO_APPS = (
    # Default Django apps:
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Useful template tags:
    # 'django.contrib.humanize',

    # Admin
    'django.contrib.admin',
)
THIRD_PARTY_APPS = (
    'crispy_forms',  # Form layouts
    'allauth',  # registration
    'allauth.account',  # registration
    'allauth.socialaccount',  # registration
    'taggit',  # models tagging
    'compressor',  # static compressor
    'modelcluster',  # add possibility to use a foreign key field without
                     # instantiating the object

)
# wagtail core apps
WAGTAIL = (
    'wagtail.wagtailcore',
    'wagtail.wagtailadmin',
    'wagtail.wagtailsearch',
    'wagtail.wagtailimages',
    'wagtail.wagtaildocs',
    'wagtail.wagtailsnippets',
    'wagtail.wagtailusers',
    'wagtail.wagtailsites',
    'wagtail.wagtailembeds',
    'wagtail.wagtailredirects',
    'wagtail.wagtailforms',
    'wagtail.contrib.wagtailapi',
)
# Apps specific for this project go here.
LOCAL_APPS = (
    'blog-wagtail.users',  # custom users app
    'home',  # front page
    'blog',
    'about',
    'portofolio',
    'django_seo_js',
)

# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + WAGTAIL + LOCAL_APPS

# MIDDLEWARE CONFIGURATION
# ------------------------------------------------------------------------------
MIDDLEWARE_CLASSES = (
    # Make sure djangosecure.middleware.SecurityMiddleware is listed first
    'sslify.middleware.SSLifyMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    'wagtail.wagtailcore.middleware.SiteMiddleware',
    'wagtail.wagtailredirects.middleware.RedirectMiddleware',

    'django_seo_js.middleware.EscapedFragmentMiddleware',
    'django_seo_js.middleware.UserAgentMiddleware',
)

# MIGRATIONS CONFIGURATION
# ------------------------------------------------------------------------------
# MIGRATION_MODULES = {
#     'sites': 'blog-wagtail.contrib.sites.migrations'
# }

# DEBUG
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
DEBUG = env.bool("DJANGO_DEBUG", False)

# FIXTURE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS
FIXTURE_DIRS = (
    str(APPS_DIR.path('fixtures')),
)

# DATABASE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES = {
    # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
    'default': env.db("DATABASE_URL", default="postgres://localhost/blog-wagtail"),
}
DATABASES['default']['ATOMIC_REQUESTS'] = True

# GENERAL CONFIGURATION
# ------------------------------------------------------------------------------
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# In a Windows environment this must be set to your system time zone.
TIME_ZONE = 'GMT'

# See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code
LANGUAGE_CODE = 'en-us'

# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
SITE_ID = 1

# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
USE_I18N = True

# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n
USE_L10N = True

# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
USE_TZ = True

# TEMPLATE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#templates
TEMPLATES = [
    {
        # See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
        'DIRS': [
            str(APPS_DIR.path('templates')),
        ],
        'OPTIONS': {
            # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
            'debug': DEBUG,
            # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
            # https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
            'loaders': [
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
            ],
            # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.template.context_processors.i18n',
                'django.template.context_processors.media',
                'django.template.context_processors.static',
                'django.template.context_processors.tz',
                'django.contrib.messages.context_processors.messages',
                # Your stuff: custom template context processors go here
            ],
        },
    },
]

# See: http://django-crispy-forms.readthedocs.org/en/latest/install.html#template-packs
CRISPY_TEMPLATE_PACK = 'bootstrap3'

# STATIC FILE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = str(ROOT_DIR('staticfiles'))

# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = '/static/'

# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
STATICFILES_DIRS = (
    str(APPS_DIR.path('static')),
)

# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'compressor.finders.CompressorFinder',
)

# MEDIA CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
MEDIA_ROOT = str(APPS_DIR('media'))

# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
MEDIA_URL = '/media/'

# URL Configuration
# ------------------------------------------------------------------------------
ROOT_URLCONF = 'config.urls'

# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
# remoed in PAW
# WSGI_APPLICATION = 'config.wsgi.application'

# AUTHENTICATION CONFIGURATION
# ------------------------------------------------------------------------------
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
)

# Custom user app defaults
# Select the correct user model
AUTH_USER_MODEL = 'users.User'
LOGIN_REDIRECT_URL = 'users:redirect'
LOGIN_URL = 'account_login'

# SLUGLIFIER
AUTOSLUG_SLUGIFY_FUNCTION = 'slugify.slugify'

# Your common stuff: Below this line define 3rd party library settings

# Wagtail
# -----------------------------------------------------------------------------
WAGTAIL_SITE_NAME = "abiraf"

# Wagtail API
# -----------------------------------------------------------------------------
WAGTAILAPI_LIMIT_MAX = 1000

# Django Compressor
# -----------------------------------------------------------------------------
COMPRESS_ENABLED = True
COMPRESS_ROOT = str(ROOT_DIR('staticfiles'))
COMPRESS_CSS_FILTERS = ['compressor.filters.cssmin.rCSSMinFilter',
                        'compressor.filters.css_default.CssAbsoluteFilter',
                        ]
COMPRESS_JS_FILTERS = ['compressor.filters.jsmin.JSMinFilter']

# SEO JS prerender backend
# -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>import unittest
from datetime import datetime, timedelta

from django.conf import settings
from django.test import TestCase

import balancer
from balancer.routers import RandomRouter, RoundRobinRouter, \
                             WeightedRandomRouter, \
                             WeightedMasterSlaveRouter, \
                             RoundRobinMasterSlaveRouter, \
                             PinningWMSRouter, PinningRRMSRouter
from balancer.mixins import PinningMixin
from balancer.middleware import PINNING_KEY, PINNING_SECONDS, \
                                PinningSessionMiddleware, \
                                PinningCookieMiddleware

class BalancerTestCase(TestCase):

    def setUp(self):
        self.original_databases = settings.DATABASES
        settings.DATABASES = balancer.TEST_DATABASES

        self.original_master = getattr(settings, 'MASTER_DATABASE', None)
        settings.MASTER_DATABASE = balancer.TEST_MASTER_DATABASE

        self.original_pool = getattr(settings, 'DATABASE_POOL', None)
        settings.DATABASE_POOL = balancer.TEST_DATABASE_POOL

        class MockObj(object):
            class _state:
                db = None

        self.obj1 = MockObj()
        self.obj2 = MockObj()

    def tearDown(self):
        settings.DATABASES = self.original_databases
        settings.MASTER_DATABASE = self.original_master
        settings.DATABASE_POOL = self.original_pool

class RandomRouterTestCase(BalancerTestCase):

    def setUp(self):
        super(RandomRouterTestCase, self).setUp()
        self.router = RandomRouter()

    def test_random_db_selection(self):
        """Simple test to make sure that random database selection works."""
        for i in range(10):
            self.assertIn(self.router.get_random_db(),
                          settings.DATABASE_POOL.keys())

    def test_relations(self):
        """Relations should only be allowed for databases in the pool."""
        self.obj1._state.db = 'default'
        self.obj2._state.db = 'other'
        self.assertTrue(self.router.allow_relation(self.obj1, self.obj2))

        self.obj1._state.db = 'other'
        self.obj2._state.db = 'utility'
        self.assertFalse(self.router.allow_relation(self.obj1, self.obj2))

class RoundRobinRouterTestCase(BalancerTestCase):

    def setUp(self):
        super(RoundRobinRouterTestCase, self).setUp()
        settings.DATABASE_POOL = ['default', 'other', 'utility']
        self.router = RoundRobinRouter()

    def test_sequential_db_selection(self):
        """Databases should cycle in order."""
        for i in range(10):
            self.assertEqual(self.router.get_next_db(), self.router.pool[0])
            self.assertEqual(self.router.get_next_db(), self.router.pool[1])
            self.assertEqual(self.router.get_next_db(), self.router.pool[2])

class WeightedRandomRouterTestCase(BalancerTestCase):

    def setUp(self):
        super(WeightedRandomRouterTestCase, self).setUp()
        self.router = WeightedRandomRouter()

    def test_weighted_db_selection(self):
        """
        Make sure that the weights are being applied correctly by checking to
        see if the rate that 'default' is selected is within 0.15 of the target
        rate.
        """
        def check_rate(target):
            hits = {'default': 0, 'other': 0}
            for i in range(1000):
                hits[self.router.get_random_db()] += 1
            rate = round(float(hits['default']) / float(hits['other']), 2)

            self.assertTrue((target - 0.15) <= rate <= (target + 0.15),
                            "The 'default' rate of %s was not close enough to "
                            "the target rate." % rate)

        # The initial target rate is 0.5, because 'default' has a weight of 1
        # and 'other' has a rate of 2 - 'default' should be selected roughly
        # half as much as 'other'.
        check_rate(target=0.5)

        settings.DATABASE_POOL = {
            'default': 1,
            'other': 4,
        }
        # Reinitialize the router with new weights
        self.router = WeightedRandomRouter()
        check_rate(target=0.25)

class MasterSlaveTestMixin(object):
    """A mixin for testing routers that use the MasterSlaveMixin."""

    def test_writes(self):
        """Writes should always go to master."""
        self.assertEqual(self.router.db_for_write(self.obj1), 'default')

    def test_relations(self):
        """
        Relations should be allowed for databases in the pool and the master.
        """
        settings.DATABASE_POOL = {
            'other': 1,
            'utility': 1,
        }
        self.router = WeightedRandomRouter()

        # Even though default isn't in the database pool, it is the master so
        # the relation should be allowed.
        self.obj1._state.db = 'default'
        self.obj2._state.db = 'other'
        self.assertTrue(self.router.allow_relation(self.obj1, self.obj2))

    @unittest.skipIf(not 'test_project' in settings.INSTALLED_APPS,
                     'This test only works when test_project is in installed.')
    def test_subqueries(self):
        """
        Regression test for issue #2 on Github - "Can't do subqueries with
        queries on different DBs."
        """
        from test_project.models import Test, Related

        t = Test.objects.using('utility').create(name="Test 1")
        Test.objects.create(name="Test 2")
        r = Related.objects.create(test=t)

        tests = Test.objects.using('utility')
        obj = Related.objects.using('default').get(test__in=tests)
        self.assertEqual(obj, r)

class WMSRouterTestCase(MasterSlaveTestMixin, BalancerTestCase):
    """Tests for the WeightedMasterSlaveRouter."""

    def setUp(self):
        super(WMSRouterTestCase, self).setUp()
        self.router = WeightedMasterSlaveRouter()

class RRMSRouterTestCase(MasterSlaveTestMixin, BalancerTestCase):
    """Tests for the RoundRobinMasterSlaveRouter."""

    def setUp(self):
        super(RRMSRouterTestCase, self).setUp()
        self.router = RoundRobinMasterSlaveRouter()

class PinningRouterTestMixin(object):
    """A mixin for testing routers that use the pinning mixin."""

    def setUp(self):
        super(PinningRouterTestMixin, self).setUp()

        class MockRequest(object):
            session = {}
            COOKIES = []

        self.mock_request = MockRequest()

        class MockResponse(object):
            cookie = None

            def set_cookie(self, key, value, max_age):
                self.cookie = key

        self.mock_response = MockResponse()

    def test_pinning(self):
        # Check to make sure the 'other' database shows in in reads first
        success = False
        for i in range(100):
            db = self.router.db_for_read(self.obj1)
            if db == 'other':
                success = True
                break
        self.assertTrue(success, "The 'other' database was not offered.")

        # Simulate a write
        self.router.db_for_write(self.obj1)

        # Check to make sure that only the master database shows up in reads,
        # since the thread should now be pinned
        success = True
        for i in range(100):
            db = self.router.db_for_read(self.obj1)
            if db == 'other':
                success = False
                break
        self.assertTrue(success, "The 'other' database was offered in error.")

        PinningMixin.unpin_thread()
        PinningMixin.clear_db_write()

    def test_middleware(self):
        for middleware, vehicle in [(PinningSessionMiddleware(), 'session'),
                                    (PinningCookieMiddleware(), 'cookie')]:
            # The first request shouldn't pin the database
            middleware.process_request(self.mock_request)
            self.assertFalse(PinningMixin.is_pinned())

            # A simulated write should, however
            PinningMixin.set_db_write()

            # The response should set the session variable and clear the locals
            response = middleware.process_response(self.mock_request,
                                                   self.mock_response)
            self.assertFalse(PinningMixin.is_pinned())
            self.assertFalse(PinningMixin.db_was_written())
            if vehicle == 'session':
                self.assertTrue(
                    self.mock_request.session.get(PINNING_KEY, False)
                )
            else:
                self.assertEqual(response.cookie, PINNING_KEY)
                self.mock_request.COOKIES = [response.cookie]

            # The subsequent request should then pin the database
            middleware.process_request(self.mock_request)
            self.assertTrue(PinningMixin.is_pinned())

            PinningMixin.unpin_thread()

            if vehicle == 'session':
                # After the pinning period has expired, the request should no
                # longer pin the thread
                exp = timedelta(seconds=PINNING_SECONDS - 5)
                self.mock_request.session[PINNING_KEY] = datetime.now() - exp
                middleware.process_request(self.mock_request)
                self.assertFalse(PinningMixin.is_pinned())

                PinningMixin.unpin_thread()

class PinningWMSRouterTestCase(PinningRouterTestMixin, BalancerTestCase):

    def setUp(self):
        super(PinningWMSRouterTestCase, self).setUp()
        self.router = PinningWMSRouter()

class PinningRRMSRouterTestCase(PinningRouterTestMixin, BalancerTestCase):

    def setUp(self):
        super(PinningRRMSRouterTestCase, self).setUp()
        self.router = PinningRRMSRouter()
<commit_msg>Removed the TestCase, because the issue turned out to be invalid<commit_after>import unittest
from datetime import datetime, timedelta

from django.conf import settings
from django.test import TestCase

import balancer
from balancer.routers import RandomRouter, RoundRobinRouter, \
                             WeightedRandomRouter, \
                             WeightedMasterSlaveRouter, \
                             RoundRobinMasterSlaveRouter, \
                             PinningWMSRouter, PinningRRMSRouter
from balancer.mixins import PinningMixin
from balancer.middleware import PINNING_KEY, PINNING_SECONDS, \
                                PinningSessionMiddleware, \
                                PinningCookieMiddleware

class BalancerTestCase(TestCase):

    def setUp(self):
        self.original_databases = settings.DATABASES
        settings.DATABASES = balancer.TEST_DATABASES

        self.original_master = getattr(settings, 'MASTER_DATABASE', None)
        settings.MASTER_DATABASE = balancer.TEST_MASTER_DATABASE

        self.original_pool = getattr(settings, 'DATABASE_POOL', None)
        settings.DATABASE_POOL = balancer.TEST_DATABASE_POOL

        class MockObj(object):
            class _state:
                db = None

        self.obj1 = MockObj()
        self.obj2 = MockObj()

    def tearDown(self):
        settings.DATABASES = self.original_databases
        settings.MASTER_DATABASE = self.original_master
        settings.DATABASE_POOL = self.original_pool

class RandomRouterTestCase(BalancerTestCase):

    def setUp(self):
        super(RandomRouterTestCase, self).setUp()
        self.router = RandomRouter()

    def test_random_db_selection(self):
        """Simple test to make sure that random database selection works."""
        for i in range(10):
            self.assertIn(self.router.get_random_db(),
                          settings.DATABASE_POOL.keys())

    def test_relations(self):
        """Relations should only be allowed for databases in the pool."""
        self.obj1._state.db = 'default'
        self.obj2._state.db = 'other'
        self.assertTrue(self.router.allow_relation(self.obj1, self.obj2))

        self.obj1._state.db = 'other'
        self.obj2._state.db = 'utility'
        self.assertFalse(self.router.allow_relation(self.obj1, self.obj2))

class RoundRobinRouterTestCase(BalancerTestCase):

    def setUp(self):
        super(RoundRobinRouterTestCase, self).setUp()
        settings.DATABASE_POOL = ['default', 'other', 'utility']
        self.router = RoundRobinRouter()

    def test_sequential_db_selection(self):
        """Databases should cycle in order."""
        for i in range(10):
            self.assertEqual(self.router.get_next_db(), self.router.pool[0])
            self.assertEqual(self.router.get_next_db(), self.router.pool[1])
            self.assertEqual(self.router.get_next_db(), self.router.pool[2])

class WeightedRandomRouterTestCase(BalancerTestCase):

    def setUp(self):
        super(WeightedRandomRouterTestCase, self).setUp()
        self.router = WeightedRandomRouter()

    def test_weighted_db_selection(self):
        """
        Make sure that the weights are being applied correctly by checking to
        see if the rate that 'default' is selected is within 0.15 of the target
        rate.
        """
        def check_rate(target):
            hits = {'default': 0, 'other': 0}
            for i in range(1000):
                hits[self.router.get_random_db()] += 1
            rate = round(float(hits['default']) / float(hits['other']), 2)

            self.assertTrue((target - 0.15) <= rate <= (target + 0.15),
                            "The 'default' rate of %s was not close enough to "
                            "the target rate." % rate)

        # The initial target rate is 0.5, because 'default' has a weight of 1
        # and 'other' has a rate of 2 - 'default' should be selected roughly
        # half as much as 'other'.
        check_rate(target=0.5)

        settings.DATABASE_POOL = {
            'default': 1,
            'other': 4,
        }
        # Reinitialize the router with new weights
        self.router = WeightedRandomRouter()
        check_rate(target=0.25)

class MasterSlaveTestMixin(object):
    """A mixin for testing routers that use the MasterSlaveMixin."""

    def test_writes(self):
        """Writes should always go to master."""
        self.assertEqual(self.router.db_for_write(self.obj1), 'default')

    def test_relations(self):
        """
        Relations should be allowed for databases in the pool and the master.
        """
        settings.DATABASE_POOL = {
            'other': 1,
            'utility': 1,
        }
        self.router = WeightedRandomRouter()

        # Even though default isn't in the database pool, it is the master so
        # the relation should be allowed.
        self.obj1._state.db = 'default'
        self.obj2._state.db = 'other'
        self.assertTrue(self.router.allow_relation(self.obj1, self.obj2))

class WMSRouterTestCase(MasterSlaveTestMixin, BalancerTestCase):
    """Tests for the WeightedMasterSlaveRouter."""

    def setUp(self):
        super(WMSRouterTestCase, self).setUp()
        self.router = WeightedMasterSlaveRouter()

class RRMSRouterTestCase(MasterSlaveTestMixin, BalancerTestCase):
    """Tests for the RoundRobinMasterSlaveRouter."""

    def setUp(self):
        super(RRMSRouterTestCase, self).setUp()
        self.router = RoundRobinMasterSlaveRouter()

class PinningRouterTestMixin(object):
    """A mixin for testing routers that use the pinning mixin."""

    def setUp(self):
        super(PinningRouterTestMixin, self).setUp()

        class MockRequest(object):
            session = {}
            COOKIES = []

        self.mock_request = MockRequest()

        class MockResponse(object):
            cookie = None

            def set_cookie(self, key, value, max_age):
                self.cookie = key

        self.mock_response = MockResponse()

    def test_pinning(self):
        # Check to make sure the 'other' database shows in in reads first
        success = False
        for i in range(100):
            db = self.router.db_for_read(self.obj1)
            if db == 'other':
                success = True
                break
        self.assertTrue(success, "The 'other' database was not offered.")

        # Simulate a write
        self.router.db_for_write(self.obj1)

        # Check to make sure that only the master database shows up in reads,
        # since the thread should now be pinned
        success = True
        for i in range(100):
            db = self.router.db_for_read(self.obj1)
            if db == 'other':
                success = False
                break
        self.assertTrue(success, "The 'other' database was offered in error.")

        PinningMixin.unpin_thread()
        PinningMixin.clear_db_write()

    def test_middleware(self):
        for middleware, vehicle in [(PinningSessionMiddleware(), 'session'),
                                    (PinningCookieMiddleware(), 'cookie')]:
            # The first request shouldn't pin the database
            middleware.process_request(self.mock_request)
            self.assertFalse(PinningMixin.is_pinned())

            # A simulated write should, however
            PinningMixin.set_db_write()

            # The response should set the session variable and clear the locals
            response = middleware.process_response(self.mock_request,
                                                   self.mock_response)
            self.assertFalse(PinningMixin.is_pinned())
            self.assertFalse(PinningMixin.db_was_written())
            if vehicle == 'session':
                self.assertTrue(
                    self.mock_request.session.get(PINNING_KEY, False)
                )
            else:
                self.assertEqual(response.cookie, PINNING_KEY)
                self.mock_request.COOKIES = [response.cookie]

            # The subsequent request should then pin the database
            middleware.process_request(self.mock_request)
            self.assertTrue(PinningMixin.is_pinned())

            PinningMixin.unpin_thread()

            if vehicle == 'session':
                # After the pinning period has expired, the request should no
                # longer pin the thread
                exp = timedelta(seconds=PINNING_SECONDS - 5)
                self.mock_request.session[PINNING_KEY] = datetime.now() - exp
                middleware.process_request(self.mock_request)
                self.assertFalse(PinningMixin.is_pinned())

                PinningMixin.unpin_thread()

class PinningWMSRouterTestCase(PinningRouterTestMixin, BalancerTestCase):

    def setUp(self):
        super(PinningWMSRouterTestCase, self).setUp()
        self.router = PinningWMSRouter()

class PinningRRMSRouterTestCase(PinningRouterTestMixin, BalancerTestCase):

    def setUp(self):
        super(PinningRRMSRouterTestCase, self).setUp()
        self.router = PinningRRMSRouter()
<|endoftext|>