<commit_before>#
# Copyright 2011-2015 Jeff Bush
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import subprocess
import os
import sys
import re
import traceback

COMPILER_DIR = '/usr/local/llvm-nyuzi/bin/'
BASE_DIR = os.path.normpath(os.path.dirname(os.path.abspath(__file__)) + '/../')
LIB_DIR = BASE_DIR + '/software/libs/'
BIN_DIR = BASE_DIR + '/bin/'
OBJ_DIR = 'obj/'
ELF_FILE = OBJ_DIR + 'test.elf'
HEX_FILE = OBJ_DIR + 'test.hex'

class TestException:
	def __init__(self, output):
		self.output = output

def compile_test(source_file, optlevel='3'):
	if not os.path.exists(OBJ_DIR):
		os.makedirs(OBJ_DIR)

	compiler_args = [COMPILER_DIR + 'clang', '-o', ELF_FILE,
		'-w',
		'-O' + optlevel,
		'-I' + LIB_DIR + 'libc/include',
		'-I' + LIB_DIR + 'libos']

	if isinstance(source_file, list):
		compiler_args += source_file		# List of files
	else:
		compiler_args += [source_file]	# Single file

	compiler_args += [LIB_DIR + 'libc/crt0.o',
		LIB_DIR + 'libc/libc.a',
		LIB_DIR + 'libos/libos.a']

	try:
		subprocess.check_output(compiler_args, stderr=subprocess.STDOUT)
		subprocess.check_output([COMPILER_DIR + 'elf2hex', '-o', HEX_FILE, ELF_FILE],
			stderr=subprocess.STDOUT)
	except subprocess.CalledProcessError as exc:
		raise TestException('Compilation failed:\n' + exc.output)

	return HEX_FILE

def assemble_test(source_file):
	if not os.path.exists(OBJ_DIR):
		os.makedirs(OBJ_DIR)

	try:
		subprocess.check_output([COMPILER_DIR + 'clang', '-o', ELF_FILE, source_file])
		subprocess.check_output([COMPILER_DIR + 'elf2hex', '-o', HEX_FILE, ELF_FILE])
	except subprocess.CalledProcessError as exc:
		raise TestException('Assembly failed:\n' + exc.output)

	return HEX_FILE

def run_emulator(block_device=None, dump_file=None, dump_base=None, dump_length=None):
	args = [BIN_DIR + 'emulator']
	if block_device:
		args += ['-b', block_device]

	if dump_file:
		args += ['-d', dump_file + ',' + hex(dump_base) + ',' + hex(dump_length)]

	args += [HEX_FILE]

	try:
		output = subprocess.check_output(args)
	except subprocess.CalledProcessError as exc:
		raise TestException('Emulator returned error: ' + exc.output)

	return output

def run_verilator(block_device=None, dump_file=None, dump_base=None, dump_length=None, extra_args=None):
	args = [BIN_DIR + 'verilator_model']
	if block_device:
		args += ['+block=' + block_device]

	if dump_file:
		args += ['+memdumpfile=' + dump_file, '+memdumpbase=' + hex(dump_base)[2:],
			'+memdumplen=' + hex(dump_length)[2:]]

	if extra_args:
		args += extra_args

	args += ['+bin=' + HEX_FILE]
	try:
		output = subprocess.check_output(args)
	except subprocess.CalledProcessError as exc:
		raise TestException('Verilator returned error: ' + exc.output)

	if output.find('***HALTED***') == -1:
		raise TestException(output + '\nProgram did not halt normally')

	return output

def assert_files_equal(file1, file2, error_msg=''):
	len1 = os.stat(file1).st_size
	len2 = os.stat(file2).st_size
	if len1 != len2:
		raise TestException('file mismatch: different lengths')

	BUFSIZE = 0x1000
	block_offset = 0
	with open(file1, 'rb') as fp1, open(file2, 'rb') as fp2:
		while True:
			block1 = fp1.read(BUFSIZE)
			block2 = fp2.read(BUFSIZE)
			if block1 != block2:
				for i in range(len(block1)):
					if block1[i] != block2[i]:
						# Show the difference
						exception_text = error_msg + ':\n'
						rounded_offset = i & ~15
						exception_text += '%08x' % (block_offset + rounded_offset),
						for x in range(16):
							exception_text += '%02x' % ord(block1[rounded_offset + x]),

						exception_text += '\n%08x' % (block_offset + rounded_offset),
						for x in range(16):
							exception_text += '%02x' % ord(block2[rounded_offset + x]),

						exception_text += '\n        ',
						for x in range(16):
							if block1[rounded_offset + x] != block2[rounded_offset + x]:
								exception_text += '^^',
							else:
								exception_text += '  ',

						raise TestException(exception_text)

			if not block1:
				return

			block_offset += BUFSIZE

registered_tests = []

def register_tests(func, params):
	global registered_tests
	registered_tests += [(func, param) for param in params]

def find_files(extensions):
	return [fname for fname in os.listdir('.') if fname.endswith(extensions)]

def execute_tests():
	global registered_tests

	if len(sys.argv) > 1:
		# Filter test list based on command line requests
		new_test_list = []
		for requested in sys.argv[1:]:
			for func, param in registered_tests:
				if param == requested:
					new_test_list += [(func, param)]
					break
			else:
				print 'Unknown test', requested
				sys.exit(1)

		registered_tests = new_test_list

	ALIGN = 30
	failing_tests = []
	for func, param in registered_tests:
		print param + (' ' * (ALIGN - len(param))),
		try:
			func(param)
			print '[\x1b[32mPASS\x1b[0m]'
		except KeyboardInterrupt:
			sys.exit(1)
		except TestException as exc:
			print '[\x1b[31mFAIL\x1b[0m]'
			failing_tests += [(param, exc.output)]
		except Exception as exc:
			print '[\x1b[31mFAIL\x1b[0m]'
			failing_tests += [(param, 'Caught exception ' + traceback.format_exc())]

	if failing_tests:
		print 'Failing tests:'
		for name, output in failing_tests:
			print name
			print output

	print str(len(failing_tests)) + '/' + str(len(registered_tests)) + ' tests failed'
	if failing_tests != []:
		sys.exit(1)

#
# This reads the results of a program from stdin and a source file specified
# on the command line.  For each line in the source file prefixed with
# 'CHECK:', it searches to see if that string occurs in the program output.
# The strings must occur in order.  It ignores any other output between the
# strings.
#
def check_result(source_file, result):
	PREFIX = 'CHECK: '

	# Read expected results
	resultOffset = 0
	lineNo = 1
	foundCheckLines = False
	with open(source_file, 'r') as f:
		for line in f:
			chkoffs = line.find(PREFIX)
			if chkoffs != -1:
				foundCheckLines = True
				expected = line[chkoffs + len(PREFIX):].strip()
				regexp = re.compile(expected)
				got = regexp.search(result, resultOffset)
				if got:
					resultOffset = got.end()
				else:
					error = 'FAIL: line ' + str(lineNo) + ' expected string ' + expected + ' was not found\n'
					error += 'searching here:' + result[resultOffset:]
					raise TestException(error)

			lineNo += 1

	if not foundCheckLines:
		raise TestException('FAIL: no lines with CHECK: were found')

	return True
<commit_msg>test_harness.py: minor cleanup<commit_after>#
# Copyright 2011-2015 Jeff Bush
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

#
# Utility functions for unit tests
#

import subprocess
import os
import sys
import re
import traceback

COMPILER_DIR = '/usr/local/llvm-nyuzi/bin/'
PROJECT_TOP = os.path.normpath(os.path.dirname(os.path.abspath(__file__)) + '/../')
LIB_DIR = PROJECT_TOP + '/software/libs/'
BIN_DIR = PROJECT_TOP + '/bin/'
OBJ_DIR = 'obj/'
ELF_FILE = OBJ_DIR + 'test.elf'
HEX_FILE = OBJ_DIR + 'test.hex'

class TestException:
	def __init__(self, output):
		self.output = output

def compile_test(source_file, optlevel='3'):
	if not os.path.exists(OBJ_DIR):
		os.makedirs(OBJ_DIR)

	compiler_args = [COMPILER_DIR + 'clang',
		'-o', ELF_FILE,
		'-w',
		'-O' + optlevel,
		'-I' + LIB_DIR + 'libc/include',
		'-I' + LIB_DIR + 'libos']

	if isinstance(source_file, list):
		compiler_args += source_file		# List of files
	else:
		compiler_args += [source_file]	# Single file

	compiler_args += [LIB_DIR + 'libc/crt0.o',
		LIB_DIR + 'libc/libc.a',
		LIB_DIR + 'libos/libos.a']

	try:
		subprocess.check_output(compiler_args, stderr=subprocess.STDOUT)
		subprocess.check_output([COMPILER_DIR + 'elf2hex', '-o', HEX_FILE, ELF_FILE],
			stderr=subprocess.STDOUT)
	except subprocess.CalledProcessError as exc:
		raise TestException('Compilation failed:\n' + exc.output)

	return HEX_FILE

def assemble_test(source_file):
	if not os.path.exists(OBJ_DIR):
		os.makedirs(OBJ_DIR)

	try:
		subprocess.check_output([COMPILER_DIR + 'clang', '-o', ELF_FILE, source_file])
		subprocess.check_output([COMPILER_DIR + 'elf2hex', '-o', HEX_FILE, ELF_FILE])
	except subprocess.CalledProcessError as exc:
		raise TestException('Assembly failed:\n' + exc.output)

	return HEX_FILE

def run_emulator(block_device=None, dump_file=None, dump_base=None, dump_length=None):
	args = [BIN_DIR + 'emulator']
	if block_device:
		args += ['-b', block_device]

	if dump_file:
		args += ['-d', dump_file + ',' + hex(dump_base) + ',' + hex(dump_length)]

	args += [HEX_FILE]

	try:
		output = subprocess.check_output(args)
	except subprocess.CalledProcessError as exc:
		raise TestException('Emulator returned error: ' + exc.output)

	return output

def run_verilator(block_device=None, dump_file=None, dump_base=None, dump_length=None, extra_args=None):
	args = [BIN_DIR + 'verilator_model']
	if block_device:
		args += ['+block=' + block_device]

	if dump_file:
		args += ['+memdumpfile=' + dump_file, '+memdumpbase=' + hex(dump_base)[2:],
			'+memdumplen=' + hex(dump_length)[2:]]

	if extra_args:
		args += extra_args

	args += ['+bin=' + HEX_FILE]
	try:
		output = subprocess.check_output(args)
	except subprocess.CalledProcessError as exc:
		raise TestException('Verilator returned error: ' + exc.output)

	if output.find('***HALTED***') == -1:
		raise TestException(output + '\nProgram did not halt normally')

	return output

def assert_files_equal(file1, file2, error_msg=''):
	len1 = os.stat(file1).st_size
	len2 = os.stat(file2).st_size
	if len1 != len2:
		raise TestException('file mismatch: different lengths')

	BUFSIZE = 0x1000
	block_offset = 0
	with open(file1, 'rb') as fp1, open(file2, 'rb') as fp2:
		while True:
			block1 = fp1.read(BUFSIZE)
			block2 = fp2.read(BUFSIZE)
			if block1 != block2:
				for i in range(len(block1)):
					if block1[i] != block2[i]:
						# Show the difference
						exception_text = error_msg + ':\n'
						rounded_offset = i & ~15
						exception_text += '%08x' % (block_offset + rounded_offset),
						for x in range(16):
							exception_text += '%02x' % ord(block1[rounded_offset + x]),

						exception_text += '\n%08x' % (block_offset + rounded_offset),
						for x in range(16):
							exception_text += '%02x' % ord(block2[rounded_offset + x]),

						exception_text += '\n        ',
						for x in range(16):
							if block1[rounded_offset + x] != block2[rounded_offset + x]:
								exception_text += '^^',
							else:
								exception_text += '  ',

						raise TestException(exception_text)

			if not block1:
				return

			block_offset += BUFSIZE

registered_tests = []

def register_tests(func, params):
	global registered_tests
	registered_tests += [(func, param) for param in params]

def find_files(extensions):
	return [fname for fname in os.listdir('.') if fname.endswith(extensions)]

def execute_tests():
	global registered_tests

	if len(sys.argv) > 1:
		# Filter test list based on command line requests
		new_test_list = []
		for requested in sys.argv[1:]:
			for func, param in registered_tests:
				if param == requested:
					new_test_list += [(func, param)]
					break
			else:
				print 'Unknown test', requested
				sys.exit(1)

		registered_tests = new_test_list

	ALIGN = 30
	failing_tests = []
	for func, param in registered_tests:
		print param + (' ' * (ALIGN - len(param))),
		try:
			func(param)
			print '[\x1b[32mPASS\x1b[0m]'
		except KeyboardInterrupt:
			sys.exit(1)
		except TestException as exc:
			print '[\x1b[31mFAIL\x1b[0m]'
			failing_tests += [(param, exc.output)]
		except Exception as exc:
			print '[\x1b[31mFAIL\x1b[0m]'
			failing_tests += [(param, 'Caught exception ' + traceback.format_exc())]

	if failing_tests:
		print 'Failing tests:'
		for name, output in failing_tests:
			print name
			print output

	print str(len(failing_tests)) + '/' + str(len(registered_tests)) + ' tests failed'
	if failing_tests != []:
		sys.exit(1)

#
# For each pattern in source_file that begins with 'CHECK:', this searches
# to see if the regular expression that follows it occurs in program_output.
# The strings must occur in order, but this ignores any other output between
# them.
#
def check_result(source_file, program_output):
	PREFIX = 'CHECK: '

	output_offset = 0
	lineNo = 1
	foundCheckLines = False
	with open(source_file, 'r') as f:
		for line in f:
			chkoffs = line.find(PREFIX)
			if chkoffs != -1:
				foundCheckLines = True
				expected = line[chkoffs + len(PREFIX):].strip()
				regexp = re.compile(expected)
				got = regexp.search(program_output, output_offset)
				if got:
					output_offset = got.end()
				else:
					error = 'FAIL: line ' + str(lineNo) + ' expected string ' + expected + ' was not found\n'
					error += 'searching here:' + output_offset[output_offset:]
					raise TestException(error)

			lineNo += 1

	if not foundCheckLines:
		raise TestException('FAIL: no lines with CHECK: were found')

	return True
<|endoftext|>


<commit_before># -*- encoding: utf-8 -*-
#
# Copyright 2013 Jay Pipes
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import testtools

from talons import helpers

from tests import base

class TestHelpers(base.TestCase):

    def test_bad_import(self):
        with testtools.ExpectedException(ImportError):
            helpers.import_function('not.exist.function')

    def test_no_function_in_module(self):
        with testtools.ExpectedException(ImportError):
            helpers.import_function('sys.noexisting')

    def test_not_callable(self):
        with testtools.ExpectedException(TypeError):
            helpers.import_function('sys.stdout')
<commit_msg>Add test to ensure talons.helpers.import_function returns a callable<commit_after># -*- encoding: utf-8 -*-
#
# Copyright 2013 Jay Pipes
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import testtools

from talons import helpers

from tests import base

class TestHelpers(base.TestCase):

    def test_bad_import(self):
        with testtools.ExpectedException(ImportError):
            helpers.import_function('not.exist.function')

    def test_no_function_in_module(self):
        with testtools.ExpectedException(ImportError):
            helpers.import_function('sys.noexisting')

    def test_not_callable(self):
        with testtools.ExpectedException(TypeError):
            helpers.import_function('sys.stdout')

    def test_return_function(self):
        fn = helpers.import_function('os.path.join')
        self.assertEqual(callable(fn), True)
<|endoftext|>


<commit_before>import os
from pathlib import Path
import pytest

from regolith.main import main

helper_map = [
    (["helper", "hello", "--person", "Simon"], "hello Simon\n"),
    (["helper", "a_proprev", "A. Einstein", "nsf", "2020-04-08", "-q",
      "Tess Guebre","-s", "downloaded", "-t", "A flat world theory"],
      "A. Einstein proposal has been added/updated in proposal reviews\n"),
    (["helper", "a_grppub_readlist", "test the lister",
      "A list to test the lister", "pdf", "--purpose", "Test the lister"],
     "test_the_lister has been added in reading_lists\n"),
    (["helper", "a_projectum", "New projectum", "lyang",
      "--date", "2020-04-29", "-c", "afriend", "-d", "more work",
      "-m", "ascopatz", "-g", "SymPy-1.1", "-u", "2021-01-01"],
     "20ly_newprojectum has been added in projecta\n"),
    (["helper", "l_milestones", "--verbose"],
     "2021-01-01: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: \n    Title: deliverable\n    log url: \n    Purpose: deliver\n    Audience: beginning grad in chemistry\n2020-05-20: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: meeting\n    Title: Project lead presentation\n    log url: \n    Purpose: to act as an example milestone.  The date is the date it was finished.  delete the field until it is finished.  In this case, the lead will present what they think is the project after their reading. Add more milestones as needed.\n    Audience: lyang, scopatz, ascopatz\n2020-05-06: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: meeting\n    Title: Kick off meeting\n    log url: \n    Purpose: introduce project to the lead\n    Audience: lyang, scopatz, ascopatz\n"
     ),
    (["helper", "l_milestones", "--verbose", "-l", "lyang"],
     "2021-01-01: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: \n    Title: deliverable\n    log url: \n    Purpose: deliver\n    Audience: beginning grad in chemistry\n2020-05-20: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: meeting\n    Title: Project lead presentation\n    log url: \n    Purpose: to act as an example milestone.  The date is the date it was finished.  delete the field until it is finished.  In this case, the lead will present what they think is the project after their reading. Add more milestones as needed.\n    Audience: lyang, scopatz, ascopatz\n2020-05-06: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: meeting\n    Title: Kick off meeting\n    log url: \n    Purpose: introduce project to the lead\n    Audience: lyang, scopatz, ascopatz\n"
     ),
    (["helper", "l_projecta", "--verbose"],
     "20ly_newprojectum\n20sb_firstprojectum\n"
     ),
    (["helper", "l_projecta", "--verbose", "-l", "ascopatz"],
     "20sb_firstprojectum\n"
     ),
    (["helper", "l_projecta", "--verbose", "-p", "ascopatz"],
     "20ly_newprojectum\n20sb_firstprojectum\n"
     ),
    (["helper", "l_grants", "-c", "-d", "2020-05-25"],
     "sym2.0, awardnr: , acctn: , 2019-06-01 to 2030-12-31\n, awardnr: , acctn: GG012345, 2015-10-01 to 2025-09-30\n"
     ),
    (["helper", "l_members", "-v"],
     "Anthony Scopatz, professor | group_id: scopatz | orcid: 0000-0002-9432-4248 | github_id: ascopatz\n"
     ),
     (["helper", "l_contacts", "-n", "ny", "-i", "col", "-o", "coffee", "-d", "2020-01-15", "-r", "2"],
      "name: Anthony B Friend, institution: columbiau, email: friend@deed.com\n"
     ),
]

@pytest.mark.parametrize("hm", helper_map)
def test_helper_python(hm, make_db, capsys):
    repo = Path(make_db)
    testfile = Path(__file__)
    os.chdir(repo)

    main(args=hm[0])
    out, err = capsys.readouterr()
    assert out == hm[1]

    builddir = repo / "_build" / hm[0][1]
    expecteddir = testfile.parent / "outputs" / hm[0][1]
    are_outfiles = any(builddir.iterdir())
    if are_outfiles and not expecteddir.is_dir():
        print("WARNING: there are built outputs that are not being tested")
    if are_outfiles and expecteddir.is_dir():
        assert_outputs(builddir,expecteddir)

    builddir = repo / "db"
    if expecteddir.is_dir():
        assert_outputs(builddir,expecteddir)

def assert_outputs(builddir,expecteddir):
    """

    Parameters
    ----------
    builddir pathlib.Path object
      the directory where the helper has built the output
    expecteddir pathlib.Path object
      the directory where the expected output is found
    """
    os.chdir(builddir)
    for root, dirs, files in os.walk("."):
        for file in files:
            if file in os.listdir(expecteddir / root):
                fn1 = builddir / root / file
                with fn1.open(mode="r") as f:
                    actual = f.read()
                fn2 = expecteddir / root / file
                with fn2.open(mode="r") as f:
                    expected = f.read()

                # Skip because of a date time in
                if file != "rss.xml":
                    # Fixme proper fix for testing hard coded filepaths on windows
                    if os.name == "nt":
                        if "tmp" not in expected:
                            if "../.." not in expected:
                                assert expected == actual
                    else:
                        assert expected == actual

<commit_msg>improved pep8 formatting<commit_after>import os
from pathlib import Path
import pytest

from regolith.main import main

helper_map = [
    (["helper", "hello", "--person", "Simon"], "hello Simon\n"),
    (["helper", "a_proprev", "A. Einstein", "nsf", "2020-04-08", "-q",
      "Tess Guebre", "-s", "downloaded", "-t", "A flat world theory"],
     "A. Einstein proposal has been added/updated in proposal reviews\n"),
    (["helper", "a_grppub_readlist", "test the lister",
      "A list to test the lister", "pdf", "--purpose", "Test the lister"],
     "test_the_lister has been added in reading_lists\n"),
    (["helper", "a_projectum", "New projectum", "lyang",
      "--date", "2020-04-29", "-c", "afriend", "-d", "more work",
      "-m", "ascopatz", "-g", "SymPy-1.1", "-u", "2021-01-01"],
     "20ly_newprojectum has been added in projecta\n"),
    (["helper", "l_milestones", "--verbose"],
     "2021-01-01: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: \n    Title: deliverable\n    log url: \n    Purpose: deliver\n    Audience: beginning grad in chemistry\n2020-05-20: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: meeting\n    Title: Project lead presentation\n    log url: \n    Purpose: to act as an example milestone.  The date is the date it was finished.  delete the field until it is finished.  In this case, the lead will present what they think is the project after their reading. Add more milestones as needed.\n    Audience: lyang, scopatz, ascopatz\n2020-05-06: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: meeting\n    Title: Kick off meeting\n    log url: \n    Purpose: introduce project to the lead\n    Audience: lyang, scopatz, ascopatz\n"
     ),
    (["helper", "l_milestones", "--verbose", "-l", "lyang"],
     "2021-01-01: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: \n    Title: deliverable\n    log url: \n    Purpose: deliver\n    Audience: beginning grad in chemistry\n2020-05-20: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: meeting\n    Title: Project lead presentation\n    log url: \n    Purpose: to act as an example milestone.  The date is the date it was finished.  delete the field until it is finished.  In this case, the lead will present what they think is the project after their reading. Add more milestones as needed.\n    Audience: lyang, scopatz, ascopatz\n2020-05-06: lead: lyang, 20ly_newprojectum, status: proposed\n    Type: meeting\n    Title: Kick off meeting\n    log url: \n    Purpose: introduce project to the lead\n    Audience: lyang, scopatz, ascopatz\n"
     ),
    (["helper", "l_projecta", "--verbose"],
     "20ly_newprojectum\n20sb_firstprojectum\n"
     ),
    (["helper", "l_projecta", "--verbose", "-l", "ascopatz"],
     "20sb_firstprojectum\n"
     ),
    (["helper", "l_projecta", "--verbose", "-p", "ascopatz"],
     "20ly_newprojectum\n20sb_firstprojectum\n"
     ),
    (["helper", "l_grants", "-c", "-d", "2020-05-25"],
     "sym2.0, awardnr: , acctn: , 2019-06-01 to 2030-12-31\n, awardnr: , acctn: GG012345, 2015-10-01 to 2025-09-30\n"
     ),
    (["helper", "l_members", "-v"],
     "Anthony Scopatz, professor | group_id: scopatz | orcid: 0000-0002-9432-4248 | github_id: ascopatz\n"
     ),
    (["helper", "l_contacts", "-n", "ny", "-i", "col", "-o", "coffee", "-d", "2020-01-15", "-r", "2"],
     "name: Anthony B Friend, institution: columbiau, email: friend@deed.com\n"
     ),
]

@pytest.mark.parametrize("hm", helper_map)
def test_helper_python(hm, make_db, capsys):
    repo = Path(make_db)
    testfile = Path(__file__)
    os.chdir(repo)

    main(args=hm[0])
    out, err = capsys.readouterr()
    assert out == hm[1]

    builddir = repo / "_build" / hm[0][1]
    expecteddir = testfile.parent / "outputs" / hm[0][1]
    are_outfiles = any(builddir.iterdir())
    if are_outfiles and not expecteddir.is_dir():
        print("WARNING: there are built outputs that are not being tested")
    if are_outfiles and expecteddir.is_dir():
        assert_outputs(builddir, expecteddir)

    builddir = repo / "db"
    if expecteddir.is_dir():
        assert_outputs(builddir, expecteddir)

def assert_outputs(builddir, expecteddir):
    """

    Parameters
    ----------
    builddir pathlib.Path object
      the directory where the helper has built the output
    expecteddir pathlib.Path object
      the directory where the expected output is found
    """
    os.chdir(builddir)
    for root, dirs, files in os.walk("."):
        for file in files:
            if file in os.listdir(expecteddir / root):
                fn1 = builddir / root / file
                with fn1.open(mode="r") as f:
                    actual = f.read()
                fn2 = expecteddir / root / file
                with fn2.open(mode="r") as f:
                    expected = f.read()

                # Skip because of a date time in
                if file != "rss.xml":
                    # Fixme proper fix for testing hard coded filepaths on
                    # windows
                    if os.name == "nt":
                        if "tmp" not in expected:
                            if "../.." not in expected:
                                assert expected == actual
                    else:
                        assert expected == actual
<|endoftext|>


<commit_before>"""
    Tests for the NURBS-Python package
    Released under The MIT License. See LICENSE file for details.
    Copyright (c) 2018 Onur Rauf Bingol

    Tests geomdl.helpers module.
"""

from geomdl import helpers

GEOMDL_DELTA = 10e-8

def test_find_span_binsearch():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	num_ctrlpts = len(knot_vector) - degree - 1
	knot = 5.0 / 2.0

	to_check = helpers.find_span_binsearch(degree, knot_vector, num_ctrlpts, knot)
	result = 4  # Value from The Nurbs Book p.68

	assert to_check == result

def test_basis_function():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0

	to_check = helpers.basis_function(degree, knot_vector, span, knot)
	result = [1.0 / 8.0, 6.0 / 8.0, 1.0 / 8.0]  # Values from The Nurbs Book p.69

	assert to_check == result

def test_basis_functions():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	spans = [3, 4, 5]
	knots = [5.0 / 2.0 for _ in range(len(spans))]

	to_check = helpers.basis_functions(degree, knot_vector, spans, knots)
	result = [helpers.basis_function(degree, knot_vector, spans[_], knots[_]) for _ in range(len(spans))]  # Values from The Nurbs Book p.55

	assert to_check == result

def test_basis_function_all():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0

	to_check = helpers.basis_function_all(degree, knot_vector, span, knot)
	interm = [helpers.basis_function(_, knot_vector, span, knot) + [None] * (degree - _) for _ in range(0, degree + 1)]
	result = [list(_) for _ in zip(*interm)]  # Tranposing to the same format as to_check

	assert to_check == result

def test_basis_function_ders():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0
	order = 2

	to_check = helpers.basis_function_ders(degree, knot_vector, span, knot, order)
	result = [[0.125, 0.75, 0.125], [-0.5, 0.0, 0.5], [1.0, -2.0, 1.0]] # Values and formulas from The Nurbs Book p.69 & p.72

	assert to_check == result

def test_find_multiplicity():
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	knots = [0.5, 2, 4, 5]

	to_check = [helpers.find_multiplicity(_, knot_vector) for _ in knots]
	result = [0, 1, 2, 3]

	assert to_check == result

def test_basis_function_one():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0

	# Values from basis_function
	to_check = [helpers.basis_function_one(degree, knot_vector, span - _, knot) for _ in range(degree, -1, -1)]
	result = helpers.basis_function(degree, knot_vector, span, knot)

	assert to_check == result

def test_basis_function_ders_one():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0
	order = 2

	to_check = [helpers.basis_function_ders_one(degree, knot_vector, span - _, knot, order) for _ in range(degree, -1, -1)]
	interm = helpers.basis_function_ders(degree, knot_vector, span, knot, order)
	result = [list(_) for _ in zip(*interm)]

	assert to_check == result
<commit_msg>Added tolerance in tests from test_helpers.py<commit_after>"""
    Tests for the NURBS-Python package
    Released under The MIT License. See LICENSE file for details.
    Copyright (c) 2018 Onur Rauf Bingol

    Tests geomdl.helpers module.
"""

from geomdl import helpers

GEOMDL_DELTA = 10e-8

def test_find_span_binsearch():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	num_ctrlpts = len(knot_vector) - degree - 1
	knot = 5.0 / 2.0

	to_check = helpers.find_span_binsearch(degree, knot_vector, num_ctrlpts, knot)
	result = 4  # Value from The Nurbs Book p.68

	assert to_check == result

def test_basis_function():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0

	to_check = helpers.basis_function(degree, knot_vector, span, knot)
	result = [1.0 / 8.0, 6.0 / 8.0, 1.0 / 8.0]  # Values from The Nurbs Book p.69

	assert abs(to_check[0] - result[0]) < GEOMDL_DELTA
	assert abs(to_check[1] - result[1]) < GEOMDL_DELTA
	assert abs(to_check[2] - result[2]) < GEOMDL_DELTA

def test_basis_functions():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	spans = [3, 4, 5]
	knots = [5.0 / 2.0 for _ in range(len(spans))]

	to_check = helpers.basis_functions(degree, knot_vector, spans, knots)
	result = [helpers.basis_function(degree, knot_vector, spans[_], knots[_]) for _ in range(len(spans))]  # Values from The Nurbs Book p.55

	assert abs(to_check[0][0] - result[0][0]) < GEOMDL_DELTA
	assert abs(to_check[0][1] - result[0][1]) < GEOMDL_DELTA
	assert abs(to_check[0][2] - result[0][2]) < GEOMDL_DELTA

	assert abs(to_check[1][0] - result[1][0]) < GEOMDL_DELTA
	assert abs(to_check[1][1] - result[1][1]) < GEOMDL_DELTA
	assert abs(to_check[1][2] - result[1][2]) < GEOMDL_DELTA

	assert abs(to_check[2][0] - result[2][0]) < GEOMDL_DELTA
	assert abs(to_check[2][1] - result[2][1]) < GEOMDL_DELTA
	assert abs(to_check[2][2] - result[2][2]) < GEOMDL_DELTA

def test_basis_function_all():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0

	to_check = helpers.basis_function_all(degree, knot_vector, span, knot)
	interm = [helpers.basis_function(_, knot_vector, span, knot) + [None] * (degree - _) for _ in range(0, degree + 1)]
	result = [list(_) for _ in zip(*interm)]  # Tranposing to the same format as to_check

	assert abs(to_check[0][0] - result[0][0]) < GEOMDL_DELTA
	assert abs(to_check[0][1] - result[0][1]) < GEOMDL_DELTA
	assert abs(to_check[0][2] - result[0][2]) < GEOMDL_DELTA

	assert to_check[1][0] == result[1][0]  # NoneType can't be substracted
	assert abs(to_check[1][1] - result[1][1]) < GEOMDL_DELTA
	assert abs(to_check[1][2] - result[1][2]) < GEOMDL_DELTA

	assert to_check[2][0] == result[2][0]  # None
	assert to_check[2][1] == result[2][1]  # None
	assert abs(to_check[2][2] - result[2][2]) < GEOMDL_DELTA

def test_basis_function_ders():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0
	order = 2

	to_check = helpers.basis_function_ders(degree, knot_vector, span, knot, order)
	result = [[0.125, 0.75, 0.125], [-0.5, 0.0, 0.5], [1.0, -2.0, 1.0]] # Values and formulas from The Nurbs Book p.69 & p.72

	assert abs(to_check[0][0] - result[0][0]) < GEOMDL_DELTA
	assert abs(to_check[0][1] - result[0][1]) < GEOMDL_DELTA
	assert abs(to_check[0][2] - result[0][2]) < GEOMDL_DELTA

	assert abs(to_check[1][0] - result[1][0]) < GEOMDL_DELTA
	assert abs(to_check[1][1] - result[1][1]) < GEOMDL_DELTA
	assert abs(to_check[1][2] - result[1][2]) < GEOMDL_DELTA

	assert abs(to_check[2][0] - result[2][0]) < GEOMDL_DELTA
	assert abs(to_check[2][1] - result[2][1]) < GEOMDL_DELTA
	assert abs(to_check[2][2] - result[2][2]) < GEOMDL_DELTA

def test_find_multiplicity():
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	knots = [0.5, 2, 4, 5]

	to_check = [helpers.find_multiplicity(_, knot_vector) for _ in knots]
	result = [0, 1, 2, 3]

	assert to_check == result

def test_basis_function_one():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0

	# Values from basis_function
	to_check = [helpers.basis_function_one(degree, knot_vector, span - _, knot) for _ in range(degree, -1, -1)]
	result = helpers.basis_function(degree, knot_vector, span, knot)

	assert abs(to_check[0] - result[0]) < GEOMDL_DELTA
	assert abs(to_check[1] - result[1]) < GEOMDL_DELTA
	assert abs(to_check[2] - result[2]) < GEOMDL_DELTA

def test_basis_function_ders_one():
	degree = 2
	knot_vector = [0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]
	span = 4
	knot = 5.0 / 2.0
	order = 2

	to_check = [helpers.basis_function_ders_one(degree, knot_vector, span - _, knot, order) for _ in range(degree, -1, -1)]
	interm = helpers.basis_function_ders(degree, knot_vector, span, knot, order)
	result = [list(_) for _ in zip(*interm)]

	assert abs(to_check[0][0] - result[0][0]) < GEOMDL_DELTA
	assert abs(to_check[0][1] - result[0][1]) < GEOMDL_DELTA
	assert abs(to_check[0][2] - result[0][2]) < GEOMDL_DELTA

	assert abs(to_check[1][0] - result[1][0]) < GEOMDL_DELTA
	assert abs(to_check[1][1] - result[1][1]) < GEOMDL_DELTA
	assert abs(to_check[1][2] - result[1][2]) < GEOMDL_DELTA

	assert abs(to_check[2][0] - result[2][0]) < GEOMDL_DELTA
	assert abs(to_check[2][1] - result[2][1]) < GEOMDL_DELTA
	assert abs(to_check[2][2] - result[2][2]) < GEOMDL_DELTA
<|endoftext|>


<commit_before># Copyright (C) 2012 Peter Teichman

import operator
import os
import shutil
import sqlite3
import unittest2 as unittest

import cobe.kvstore

class KVStoreBase(object):
    """Base tests for KV Stores"""

    def test_get_default(self):
        self.assertIsNone(self.store.get("missing"))

    def test_put_get(self):
        key, value = "test_key", "test_value"

        self.assertIsNone(self.store.get(key, None))
        self.store.put(key, value)
        self.assertEqual(value, self.store.get(key))

    def test_null_key(self):
        key, value = "\x00", "test_value"

        self.assertIsNone(self.store.get(key, None))
        self.store.put(key, value)

        self.assertEqual(value, self.store.get(key))

        self.assertEqual([key], list(self.store.keys()))
        self.assertEqual([(key, value)], list(self.store.items()))

    def test_null_value(self):
        key, value = "test_key", "\x00"

        self.assertIsNone(self.store.get(key, None))
        self.store.put(key, value)

        self.assertEqual(value, self.store.get(key))

        self.assertEqual([key], list(self.store.keys()))
        self.assertEqual([(key, value)], list(self.store.items()))

    def test_replace(self):
        key = "foo"
        self.assertIsNone(self.store.get(key, None))

        self.store.put(key, "bar")
        self.assertEqual("bar", self.store.get(key))

        self.store.put(key, "baz")
        self.assertEqual("baz", self.store.get(key))

    def test_put_many(self):
        items = [
            ("one", "value1"),
            ("two", "value2"),
            ("three", "value3"),
            ("four", "value4"),
            ("five", "value5"),
            ("six", "value6"),
            ("seven", "value7"),
            ("eight", "value8"),
            ("nine", "value9")
            ]

        self.store.put_many(items)

        for key, value in items:
            self.assertEqual(value, self.store.get(key))

    def test_no_keys(self):
        self.assertEqual([], list(self.store.keys()))

        self.assertEqual([], list(self.store.keys(key_from="foo")))
        self.assertEqual([], list(self.store.keys(key_to="bar")))

        self.assertEqual([], list(self.store.keys(key_from="foo",
                                                  key_to="bar")))

    def test_no_items(self):
        self.assertEqual([], list(self.store.items()))

        self.assertEqual([], list(self.store.items(key_from="foo")))
        self.assertEqual([], list(self.store.items(key_to="bar")))

        self.assertEqual([], list(self.store.items(key_from="foo",
                                                   key_to="bar")))

    def test_keys(self):
        items = [
            ("one", "value1"),
            ("two", "value2"),
            ("three", "value3"),
            ("four", "value4"),
            ("five", "value5"),
            ("six", "value6"),
            ("seven", "value7"),
            ("eight", "value8"),
            ("nine", "value9")
            ]

        for key, value in items:
            self.store.put(key, value)

        # Sorted order is: eight five four nine one seven six three two
        keys = list(self.store.keys())
        expected = "eight five four nine one seven six three two".split()
        self.assertEqual(expected, keys)

        # Test key_from on keys that are present and missing in the db
        keys = list(self.store.keys(key_from="four"))
        expected = "four nine one seven six three two".split()
        self.assertEqual(expected, keys)

        keys = list(self.store.keys(key_from="fo"))
        expected = "four nine one seven six three two".split()
        self.assertEqual(expected, keys)

        # Test key_to
        keys = list(self.store.keys(key_to="six"))
        expected = "eight five four nine one seven six".split()
        self.assertEqual(expected, keys)

        keys = list(self.store.keys(key_to="si"))
        expected = "eight five four nine one seven".split()
        self.assertEqual(expected, keys)

        # And test them both together
        keys = list(self.store.keys(key_from="five", key_to="three"))
        expected = "five four nine one seven six three".split()
        self.assertEqual(expected, keys)

    def test_items(self):
        put_items = dict([
            ("one", "value1"),
            ("two", "value2"),
            ("three", "value3"),
            ("four", "value4"),
            ("five", "value5"),
            ("six", "value6"),
            ("seven", "value7"),
            ("eight", "value8"),
            ("nine", "value9")
            ])

        for key, value in put_items.items():
            self.store.put(key, value)

        # Sorted order is: eight five four nine one seven six three two
        keys = list(self.store.items())
        expected = sorted(put_items.items(), key=operator.itemgetter(0))
        self.assertEqual(expected, keys)

        # Test key_from on keys that are present and missing in the db
        keys = list(self.store.items(key_from="four"))
        self.assertEqual(expected[2:], keys)

        keys = list(self.store.items(key_from="fo"))
        self.assertEqual(expected[2:], keys)

        # Test key_to
        keys = list(self.store.items(key_to="six"))
        self.assertEqual(expected[:7], keys)

        keys = list(self.store.items(key_to="si"))
        self.assertEqual(expected[:6], keys)

        # And test them both together
        keys = list(self.store.items(key_from="five", key_to="three"))
        self.assertEqual(expected[1:8], keys)

class TestBsddbStore(unittest.TestCase, KVStoreBase):
    DB = "tests.test_bsddb_store"

    def setUp(self):
        self.store = cobe.kvstore.BsddbStore(self.DB)

        def cleanup():
            if os.path.exists(self.DB):
                os.unlink(self.DB)

        self.addCleanup(cleanup)

class TestSqliteStore(unittest.TestCase, KVStoreBase):
    DB = "tests.test_sqlite_store"

    def setUp(self):
        self.store = cobe.kvstore.SqliteStore(self.DB)

        def cleanup():
            if os.path.exists(self.DB):
                os.unlink(self.DB)

        self.addCleanup(cleanup)

class TestLevelDBStore(unittest.TestCase, KVStoreBase):
    DBDIR = "tests.test_leveldb_store"

    @classmethod
    def setUpClass(cls):
        try:
            import leveldb
        except ImportError:
            raise unittest.SkipTest("py-leveldb not installed")

    def setUp(self):
        self.store = cobe.kvstore.LevelDBStore(self.DBDIR)

        def cleanup():
            if os.path.exists(self.DBDIR):
                shutil.rmtree(self.DBDIR)

        self.addCleanup(cleanup)

if __name__ == '__main__':
    unittest.main()
<commit_msg>Skip BsddbStore tests if bsddb is missing or broken (as on OSX)<commit_after># Copyright (C) 2012 Peter Teichman

import operator
import os
import shutil
import sqlite3
import unittest2 as unittest

import cobe.kvstore

class KVStoreBase(object):
    """Base tests for KV Stores"""

    def test_get_default(self):
        self.assertIsNone(self.store.get("missing"))

    def test_put_get(self):
        key, value = "test_key", "test_value"

        self.assertIsNone(self.store.get(key, None))
        self.store.put(key, value)
        self.assertEqual(value, self.store.get(key))

    def test_null_key(self):
        key, value = "\x00", "test_value"

        self.assertIsNone(self.store.get(key, None))
        self.store.put(key, value)

        self.assertEqual(value, self.store.get(key))

        self.assertEqual([key], list(self.store.keys()))
        self.assertEqual([(key, value)], list(self.store.items()))

    def test_null_value(self):
        key, value = "test_key", "\x00"

        self.assertIsNone(self.store.get(key, None))
        self.store.put(key, value)

        self.assertEqual(value, self.store.get(key))

        self.assertEqual([key], list(self.store.keys()))
        self.assertEqual([(key, value)], list(self.store.items()))

    def test_replace(self):
        key = "foo"
        self.assertIsNone(self.store.get(key, None))

        self.store.put(key, "bar")
        self.assertEqual("bar", self.store.get(key))

        self.store.put(key, "baz")
        self.assertEqual("baz", self.store.get(key))

    def test_put_many(self):
        items = [
            ("one", "value1"),
            ("two", "value2"),
            ("three", "value3"),
            ("four", "value4"),
            ("five", "value5"),
            ("six", "value6"),
            ("seven", "value7"),
            ("eight", "value8"),
            ("nine", "value9")
            ]

        self.store.put_many(items)

        for key, value in items:
            self.assertEqual(value, self.store.get(key))

    def test_no_keys(self):
        self.assertEqual([], list(self.store.keys()))

        self.assertEqual([], list(self.store.keys(key_from="foo")))
        self.assertEqual([], list(self.store.keys(key_to="bar")))

        self.assertEqual([], list(self.store.keys(key_from="foo",
                                                  key_to="bar")))

    def test_no_items(self):
        self.assertEqual([], list(self.store.items()))

        self.assertEqual([], list(self.store.items(key_from="foo")))
        self.assertEqual([], list(self.store.items(key_to="bar")))

        self.assertEqual([], list(self.store.items(key_from="foo",
                                                   key_to="bar")))

    def test_keys(self):
        items = [
            ("one", "value1"),
            ("two", "value2"),
            ("three", "value3"),
            ("four", "value4"),
            ("five", "value5"),
            ("six", "value6"),
            ("seven", "value7"),
            ("eight", "value8"),
            ("nine", "value9")
            ]

        for key, value in items:
            self.store.put(key, value)

        # Sorted order is: eight five four nine one seven six three two
        keys = list(self.store.keys())
        expected = "eight five four nine one seven six three two".split()
        self.assertEqual(expected, keys)

        # Test key_from on keys that are present and missing in the db
        keys = list(self.store.keys(key_from="four"))
        expected = "four nine one seven six three two".split()
        self.assertEqual(expected, keys)

        keys = list(self.store.keys(key_from="fo"))
        expected = "four nine one seven six three two".split()
        self.assertEqual(expected, keys)

        # Test key_to
        keys = list(self.store.keys(key_to="six"))
        expected = "eight five four nine one seven six".split()
        self.assertEqual(expected, keys)

        keys = list(self.store.keys(key_to="si"))
        expected = "eight five four nine one seven".split()
        self.assertEqual(expected, keys)

        # And test them both together
        keys = list(self.store.keys(key_from="five", key_to="three"))
        expected = "five four nine one seven six three".split()
        self.assertEqual(expected, keys)

    def test_items(self):
        put_items = dict([
            ("one", "value1"),
            ("two", "value2"),
            ("three", "value3"),
            ("four", "value4"),
            ("five", "value5"),
            ("six", "value6"),
            ("seven", "value7"),
            ("eight", "value8"),
            ("nine", "value9")
            ])

        for key, value in put_items.items():
            self.store.put(key, value)

        # Sorted order is: eight five four nine one seven six three two
        keys = list(self.store.items())
        expected = sorted(put_items.items(), key=operator.itemgetter(0))
        self.assertEqual(expected, keys)

        # Test key_from on keys that are present and missing in the db
        keys = list(self.store.items(key_from="four"))
        self.assertEqual(expected[2:], keys)

        keys = list(self.store.items(key_from="fo"))
        self.assertEqual(expected[2:], keys)

        # Test key_to
        keys = list(self.store.items(key_to="six"))
        self.assertEqual(expected[:7], keys)

        keys = list(self.store.items(key_to="si"))
        self.assertEqual(expected[:6], keys)

        # And test them both together
        keys = list(self.store.items(key_from="five", key_to="three"))
        self.assertEqual(expected[1:8], keys)

class TestBsddbStore(unittest.TestCase, KVStoreBase):
    DB = "tests.test_bsddb_store"

    @classmethod
    def setUpClass(cls):
        try:
            import bsddb
        except ImportError:
            raise unittest.SkipTest("bsddb not installed")

    def setUp(self):
        self.store = cobe.kvstore.BsddbStore(self.DB)

        def cleanup():
            if os.path.exists(self.DB):
                os.unlink(self.DB)

        self.addCleanup(cleanup)

class TestSqliteStore(unittest.TestCase, KVStoreBase):
    DB = "tests.test_sqlite_store"

    def setUp(self):
        self.store = cobe.kvstore.SqliteStore(self.DB)

        def cleanup():
            if os.path.exists(self.DB):
                os.unlink(self.DB)

        self.addCleanup(cleanup)

class TestLevelDBStore(unittest.TestCase, KVStoreBase):
    DBDIR = "tests.test_leveldb_store"

    @classmethod
    def setUpClass(cls):
        try:
            import leveldb
        except ImportError:
            raise unittest.SkipTest("py-leveldb not installed")

    def setUp(self):
        self.store = cobe.kvstore.LevelDBStore(self.DBDIR)

        def cleanup():
            if os.path.exists(self.DBDIR):
                shutil.rmtree(self.DBDIR)

        self.addCleanup(cleanup)

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


<commit_before>'''Unstamp Mail Transfer Agent Server

This server receives mail from the outside and sends it to the Mail Delivery
Agent (mail_delivery.py) for delivery.
'''

from gevent import socket
from gevent.server import StreamServer
from email.parser import FeedParser

from .error import error
from .util import writeline
from .database import Address

_server = None
_hostname = ''

class _Envelope:
    def __init__(self):
        self.FROM = ''
        self.RECIPIENTS = []
        self.MESSAGE = None
        self._FEEDER = None
    def start_feed(self):
        self._FEEDER = FeedParser()
    def feed(self, lines):
        self._FEEDER.feed(lines)
        if lines.strip() == '.':
            return False
        return True
    def end_feed(self):
        self.MESSAGE = self._FEEDER.close()

def _parse_request(request):
    request = request.strip()

def parse_address(encoded):
    address = []
    encoded = encoded.strip()
    if not encoded or encoded[0] != '<':
        return
    inside_quotes = False
    i = 1
    if encoded[i] == '@':
        while encoded[i] != ':':
            i += 1
        i += 1
    while True:
        if i >= len(encoded):
            return  # Address is not properly terminated with '>'
        char = encoded[i]
        if char == '\\':
            i += 1
            address.append(encoded[i])
        elif char == '"':
            inside_quotes = not inside_quotes
        elif char == '>' and not inside_quotes:
            return ''.join(address)
        else:
            address.append(char)
        i += 1

def _accept(fp, host, port):

    writeline(fp, '220 {0} ESMTP'.format(_hostname))
    verb, parameter = _parse_request(fp.readline())

    if verb == 'HELO':
        client_name = parameter
        envelope = _Envelope()
        writeline(fp, '250 OK')

    elif verb == 'EHLO':
        pass  # TODO

    else:
        writeline(fp, '500 Unrecognized Response')
        return

    while True:
        verb, parameter = _parse_request(fp.readline())

        if verb == 'MAIL':
            parameter = parameter.lower()
            if parameter[:5] != 'from:':
                writeline(fp, '500 No Address Given')
                continue
            mailfrom = parse_address(parameter[5:])
            if not mailfrom:
                writeline(fp, '501 Malformatted Address')
                continue
            envelope.FROM = mailfrom
            envelope.RECIPIENTS = []
            writeline(fp, '250 OK')

        elif verb == 'RCPT':
            if not envelope.FROM:
                writeline(fp, '503 Need MAIL Before RCPT')
                continue
            if len(envelope.RECIPIENTS) >= 100:
                writeline(fp, '452 Too Many Recipients')
                continue
            parameter = parameter.lower()
            if parameter[:3] != 'to:':
                writeline(fp, '500 No Address Given')
                continue
            rcptto = parse_address(parameter[3:])
            if rcptto is None:
                writeline(fp, '501 Malformatted Address')
                continue
            account = Address.select().where(Address.email == rcptto)
            if not account.exists():
                writeline(fp, '550 Not A Valid Address')
                continue
            envelope.RECIPIENTS.append(account.get().forward_to)
            writeline(fp, '250 OK')

        elif verb == 'DATA':
            if not envelope.RECIPIENTS:
                writeline(fp, '503 Need RCPT Before Data')
                continue
            writeline(fp, '354 OK')
            envelope.start_feed()
            while envelope.feed(fp.readline()):
                pass
            envelope.end_feed()
            # TODO

        elif verb == 'QUIT':
            writeline(fp, '221 Farewell')
            break

        else:
            writeline(fp, '500 Unrecognized Response')

def _handler(s, address):
    sf = s.makefile('r+', newline='')
    _accept(sf, *address)
    s.shutdown(socket.SHUT_RDWR)
    s.close()

def start(hostname, host, port):
    global _server, _hostname
    _hostname = hostname
    try:
        _server = StreamServer((host, port), _handler)
        _server.start()
    except PermissionError:
        raise error('Permission to access port {1} on {0} denied!'.format(host, port))

def stop():
    if _server is None:
        raise error('stop() called, but Mail Transfer Agent server is not running!')
    _server.stop()
<commit_msg>Envelope recipients is now a set<commit_after>'''Unstamp Mail Transfer Agent Server

This server receives mail from the outside and sends it to the Mail Delivery
Agent (mail_delivery.py) for delivery.
'''

from gevent import socket
from gevent.server import StreamServer
from email.parser import FeedParser

from .error import error
from .util import writeline
from .database import Address

_server = None
_hostname = ''

class _Envelope:
    def __init__(self):
        self.FROM = ''
        self.RECIPIENTS = set()
        self.MESSAGE = None
        self._FEEDER = None
    def start_feed(self):
        self._FEEDER = FeedParser()
    def feed(self, lines):
        self._FEEDER.feed(lines)
        if lines.strip() == '.':
            return False
        return True
    def end_feed(self):
        self.MESSAGE = self._FEEDER.close()

def _parse_request(request):
    request = request.strip()

def parse_address(encoded):
    address = []
    encoded = encoded.strip()
    if not encoded or encoded[0] != '<':
        return
    inside_quotes = False
    i = 1
    if encoded[i] == '@':
        while encoded[i] != ':':
            i += 1
        i += 1
    while True:
        if i >= len(encoded):
            return  # Address is not properly terminated with '>'
        char = encoded[i]
        if char == '\\':
            i += 1
            address.append(encoded[i])
        elif char == '"':
            inside_quotes = not inside_quotes
        elif char == '>' and not inside_quotes:
            return ''.join(address)
        else:
            address.append(char)
        i += 1

def _accept(fp, host, port):

    writeline(fp, '220 {0} ESMTP'.format(_hostname))
    verb, parameter = _parse_request(fp.readline())

    if verb == 'HELO':
        client_name = parameter
        envelope = _Envelope()
        writeline(fp, '250 OK')

    elif verb == 'EHLO':
        pass  # TODO

    else:
        writeline(fp, '500 Unrecognized Response')
        return

    while True:
        verb, parameter = _parse_request(fp.readline())

        if verb == 'MAIL':
            parameter = parameter.lower()
            if parameter[:5] != 'from:':
                writeline(fp, '500 No Address Given')
                continue
            mailfrom = parse_address(parameter[5:])
            if not mailfrom:
                writeline(fp, '501 Malformatted Address')
                continue
            envelope.FROM = mailfrom
            envelope.RECIPIENTS = set()
            writeline(fp, '250 OK')

        elif verb == 'RCPT':
            if not envelope.FROM:
                writeline(fp, '503 Need MAIL Before RCPT')
                continue
            if len(envelope.RECIPIENTS) >= 100:
                writeline(fp, '452 Too Many Recipients')
                continue
            parameter = parameter.lower()
            if parameter[:3] != 'to:':
                writeline(fp, '500 No Address Given')
                continue
            rcptto = parse_address(parameter[3:])
            if rcptto is None:
                writeline(fp, '501 Malformatted Address')
                continue
            account = Address.select().where(Address.email == rcptto)
            if not account.exists():
                writeline(fp, '550 Not A Valid Address')
                continue
            envelope.RECIPIENTS.add(rcptto)
            writeline(fp, '250 OK')

        elif verb == 'DATA':
            if not envelope.RECIPIENTS:
                writeline(fp, '503 Need RCPT Before Data')
                continue
            writeline(fp, '354 OK')
            envelope.start_feed()
            while envelope.feed(fp.readline()):
                pass
            envelope.end_feed()
            # TODO

        elif verb == 'QUIT':
            writeline(fp, '221 Farewell')
            break

        else:
            writeline(fp, '500 Unrecognized Response')

def _handler(s, address):
    sf = s.makefile('r+', newline='')
    _accept(sf, *address)
    s.shutdown(socket.SHUT_RDWR)
    s.close()

def start(hostname, host, port):
    global _server, _hostname
    _hostname = hostname
    try:
        _server = StreamServer((host, port), _handler)
        _server.start()
    except PermissionError:
        raise error('Permission to access port {1} on {0} denied!'.format(host, port))

def stop():
    if _server is None:
        raise error('stop() called, but Mail Transfer Agent server is not running!')
    _server.stop()
<|endoftext|>


<commit_before>from __future__ import division

import logging
import threading

import av.logging
import av.utils
from av import AVError

from .common import TestCase

def do_log(message):
    av.logging.log(av.logging.INFO, 'test', message)

class TestLogging(TestCase):

    def test_adapt_level(self):
        self.assertEqual(
            av.logging.adapt_level(av.logging.ERROR),
            logging.ERROR
        )
        self.assertEqual(
            av.logging.adapt_level(av.logging.WARNING),
            logging.WARNING
        )
        self.assertEqual(
            av.logging.adapt_level((av.logging.WARNING + av.logging.ERROR) // 2),
            logging.WARNING
        )

    def test_threaded_captures(self):

        with av.logging.Capture(local=True) as logs:
            do_log('main')
            thread = threading.Thread(target=do_log, args=('thread', ))
            thread.start()
            thread.join()

        self.assertEqual(logs, [
            (av.logging.INFO, 'test', 'main'),
        ])

    def test_global_captures(self):

        with av.logging.Capture(local=False) as logs:
            do_log('main')
            thread = threading.Thread(target=do_log, args=('thread', ))
            thread.start()
            thread.join()

        self.assertEqual(logs, [
            (av.logging.INFO, 'test', 'main'),
            (av.logging.INFO, 'test', 'thread'),
        ])

    def test_repeats(self):

        with av.logging.Capture() as logs:
            do_log('foo')
            do_log('foo')
            do_log('bar')
            do_log('bar')
            do_log('bar')
            do_log('baz')

        logs = [l for l in logs if l[1] == 'test']

        self.assertEqual(logs, [
            (av.logging.INFO, 'test', 'foo'),
            (av.logging.INFO, 'test', 'foo'),
            (av.logging.INFO, 'test', 'bar'),
            (av.logging.INFO, 'test', 'bar (repeated 2 more times)'),
            (av.logging.INFO, 'test', 'baz'),

        ])

    def test_error(self):

        log = (av.logging.ERROR, 'test', 'This is a test.')
        av.logging.log(*log)
        try:
            av.utils.err_check(-1)
        except AVError as e:
            self.assertEqual(e.log, log)
        else:
            self.fail()
<commit_msg>Make logging test more specific.<commit_after>from __future__ import division

import logging
import threading

import av.logging
import av.utils
from av import AVError

from .common import TestCase

def do_log(message):
    av.logging.log(av.logging.INFO, 'test', message)

class TestLogging(TestCase):

    def test_adapt_level(self):
        self.assertEqual(
            av.logging.adapt_level(av.logging.ERROR),
            logging.ERROR
        )
        self.assertEqual(
            av.logging.adapt_level(av.logging.WARNING),
            logging.WARNING
        )
        self.assertEqual(
            av.logging.adapt_level((av.logging.WARNING + av.logging.ERROR) // 2),
            logging.WARNING
        )

    def test_threaded_captures(self):

        with av.logging.Capture(local=True) as logs:
            do_log('main')
            thread = threading.Thread(target=do_log, args=('thread', ))
            thread.start()
            thread.join()

        self.assertIn((av.logging.INFO, 'test', 'main'), logs)

    def test_global_captures(self):

        with av.logging.Capture(local=False) as logs:
            do_log('main')
            thread = threading.Thread(target=do_log, args=('thread', ))
            thread.start()
            thread.join()

        self.assertIn((av.logging.INFO, 'test', 'main'), logs)
        self.assertIn((av.logging.INFO, 'test', 'thread'), logs)

    def test_repeats(self):

        with av.logging.Capture() as logs:
            do_log('foo')
            do_log('foo')
            do_log('bar')
            do_log('bar')
            do_log('bar')
            do_log('baz')

        logs = [l for l in logs if l[1] == 'test']

        self.assertEqual(logs, [
            (av.logging.INFO, 'test', 'foo'),
            (av.logging.INFO, 'test', 'foo'),
            (av.logging.INFO, 'test', 'bar'),
            (av.logging.INFO, 'test', 'bar (repeated 2 more times)'),
            (av.logging.INFO, 'test', 'baz'),

        ])

    def test_error(self):

        log = (av.logging.ERROR, 'test', 'This is a test.')
        av.logging.log(*log)
        try:
            av.utils.err_check(-1)
        except AVError as e:
            self.assertEqual(e.log, log)
        else:
            self.fail()
<|endoftext|>


<commit_before># Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A wrapper for the wrapper.

It interacts with the datastore, where the wrapper it wraps does not.
"""

__author__ = [
    'nretallack@google.com (Nick Retallack)',
]

import json

from google.appengine.ext import db

from models import models
from modules.drive import drive_api_client
from modules.drive import drive_models
from modules.drive import drive_settings
from modules.drive import errors

class _DriveManager(object):
    def __init__(self, client):
        self.client = client

    @classmethod
    def from_app_context(cls, app_context):
        # raises errors.NotConfigured
        # pylint: disable=protected-access
        secrets = drive_settings.get_secrets(app_context)
        client = (
            drive_api_client._APIClientWrapper
            .from_service_account_secrets(
                secrets['client_email'], secrets['private_key']))

        return cls(client)

    @classmethod
    def from_code(cls, app_context, code):
        # pylint: disable=protected-access
        client_id = drive_settings.get_google_client_id(app_context)
        client_secret = drive_settings.get_google_client_secret(app_context)
        if not client_id and client_secret:
            raise errors.NotConfigured

        client = drive_api_client._APIClientWrapper.\
            from_client_secrets_and_code(code, client_id, client_secret)

        return cls(client)

    def list_file_meta(self, **kwargs):
        # add caching here if needed
        return self.client.list_file_meta(**kwargs)

    def get_file_meta(self, file_id):
        # add caching here if needed
        return self.client.get_file_meta(file_id)

    def download_file(self, dto):
        """Downloads a representation of the file into the datastore.

        For docs, it uses HTML.
        For sheets, it uses JSON.

        This method does not check for other concurrent actors.  Races can occur
        between the job and the manual sync handler.  However, documents are
        stored atomically in a single record, so the only consequences of a race
        are spending slightly more time and possibly temporarily regressing
        to a previous version if the document is being actively modified.
        Nothing another sync won't fix.
        """

        # Determine if the type is supported before messign with the database.
        # This will raise KeyError if you mess up.
        fetch_method = {
            drive_api_client.SHEET_TYPE: self.client.get_sheet_data,
            drive_api_client.DOC_TYPE: self.client.get_doc_as_html,
        }[dto.type]

        self._start_sync(dto.id)

        try:
            meta = self.client.get_file_meta(dto.id)
            if meta.version != dto.version:
                content = fetch_method(dto.id)
                content_chunk = models.ContentChunkDAO.get_one_by_uid(
                    models.ContentChunkDAO.make_uid(dto.type, dto.id))
                content_chunk_id = content_chunk.id if content_chunk else None
                self._save_content(meta, content, content_chunk_id)
            else:
                self._save_content_unchanged(meta)

        except errors.Error as error:
            self._save_failure(dto.id, error)
            raise error

    @db.transactional
    def _start_sync(self, file_id):
        dto = drive_models.DriveSyncDAO.load(file_id)
        dto.sync_started()
        drive_models.DriveSyncDAO.save(dto)

    @db.transactional
    def _save_failure(self, file_id, error):
        dto = drive_models.DriveSyncDAO.load(file_id)
        dto.sync_failed(error)
        drive_models.DriveSyncDAO.save(dto)

    @db.transactional
    def _save_content_unchanged(self, meta):
        dto = drive_models.DriveSyncDAO.load(meta.file_id)
        dto.dict['title'] = meta.title
        dto.sync_succeeded()
        drive_models.DriveSyncDAO.save(dto)

    @db.transactional(xg=True)
    def _save_content(self, meta, content, content_chunk_id):
        # load both
        dto = drive_models.DriveSyncDAO.load(meta.file_id)
        content_chunk = models.ContentChunkDAO.get(content_chunk_id)

        # update sync entity
        dto.dict['title'] = meta.title
        dto.version = meta.version
        dto.sync_succeeded()

        # instantiate new content chunk if necessary
        if not content_chunk:
            content_chunk = models.ContentChunkDTO({
                'type_id': meta.type,
                'resource_id': meta.file_id,
            })

        # populate content
        {
            drive_api_client.SHEET_TYPE: self._save_sheet_content,
            drive_api_client.DOC_TYPE: self._save_doc_content,
        }[dto.type](content_chunk, content)

        # Save both
        models.ContentChunkDAO.save(content_chunk)
        drive_models.DriveSyncDAO.save(dto)

    def _save_sheet_content(self, content_chunk, content):
        content_chunk.contents = json.dumps(content.to_json())
        content_chunk.content_type = 'application/json'

    def _save_doc_content(self, content_chunk, content):
        content_chunk.contents = content
        content_chunk.content_type = 'text/html'

    def share_file(self, file_id, email):
        self.client.share_file(file_id, email)
<commit_msg>Don't check version when syncing Drive documents.<commit_after># Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A wrapper for the wrapper.

It interacts with the datastore, where the wrapper it wraps does not.
"""

__author__ = [
    'nretallack@google.com (Nick Retallack)',
]

import json

from google.appengine.ext import db

from models import models
from modules.drive import drive_api_client
from modules.drive import drive_models
from modules.drive import drive_settings
from modules.drive import errors

class _DriveManager(object):
    def __init__(self, client):
        self.client = client

    @classmethod
    def from_app_context(cls, app_context):
        # raises errors.NotConfigured
        # pylint: disable=protected-access
        secrets = drive_settings.get_secrets(app_context)
        client = (
            drive_api_client._APIClientWrapper
            .from_service_account_secrets(
                secrets['client_email'], secrets['private_key']))

        return cls(client)

    @classmethod
    def from_code(cls, app_context, code):
        # pylint: disable=protected-access
        client_id = drive_settings.get_google_client_id(app_context)
        client_secret = drive_settings.get_google_client_secret(app_context)
        if not client_id and client_secret:
            raise errors.NotConfigured

        client = drive_api_client._APIClientWrapper.\
            from_client_secrets_and_code(code, client_id, client_secret)

        return cls(client)

    def list_file_meta(self, **kwargs):
        # add caching here if needed
        return self.client.list_file_meta(**kwargs)

    def get_file_meta(self, file_id):
        # add caching here if needed
        return self.client.get_file_meta(file_id)

    def download_file(self, dto):
        """Downloads a representation of the file into the datastore.

        For docs, it uses HTML.
        For sheets, it uses JSON.

        This method does not check for other concurrent actors.  Races can occur
        between the job and the manual sync handler.  However, documents are
        stored atomically in a single record, so the only consequences of a race
        are spending slightly more time and possibly temporarily regressing
        to a previous version if the document is being actively modified.
        Nothing another sync won't fix.
        """

        # Determine if the type is supported before messign with the database.
        # This will raise KeyError if you mess up.
        fetch_method = {
            drive_api_client.SHEET_TYPE: self.client.get_sheet_data,
            drive_api_client.DOC_TYPE: self.client.get_doc_as_html,
        }[dto.type]

        self._start_sync(dto.id)

        try:
            meta = self.client.get_file_meta(dto.id)
            content = fetch_method(dto.id)
            content_chunk = models.ContentChunkDAO.get_one_by_uid(
                models.ContentChunkDAO.make_uid(dto.type, dto.id))
            content_chunk_id = content_chunk.id if content_chunk else None
            self._save_content(meta, content, content_chunk_id)

        except errors.Error as error:
            self._save_failure(dto.id, error)
            raise error

    @db.transactional
    def _start_sync(self, file_id):
        dto = drive_models.DriveSyncDAO.load(file_id)
        dto.sync_started()
        drive_models.DriveSyncDAO.save(dto)

    @db.transactional
    def _save_failure(self, file_id, error):
        dto = drive_models.DriveSyncDAO.load(file_id)
        dto.sync_failed(error)
        drive_models.DriveSyncDAO.save(dto)

    @db.transactional(xg=True)
    def _save_content(self, meta, content, content_chunk_id):
        # load both
        dto = drive_models.DriveSyncDAO.load(meta.file_id)
        content_chunk = models.ContentChunkDAO.get(content_chunk_id)

        # update sync entity
        dto.dict['title'] = meta.title
        dto.version = meta.version
        dto.sync_succeeded()

        # instantiate new content chunk if necessary
        if not content_chunk:
            content_chunk = models.ContentChunkDTO({
                'type_id': meta.type,
                'resource_id': meta.file_id,
            })

        # populate content
        {
            drive_api_client.SHEET_TYPE: self._save_sheet_content,
            drive_api_client.DOC_TYPE: self._save_doc_content,
        }[dto.type](content_chunk, content)

        # Save both
        models.ContentChunkDAO.save(content_chunk)
        drive_models.DriveSyncDAO.save(dto)

    def _save_sheet_content(self, content_chunk, content):
        content_chunk.contents = json.dumps(content.to_json())
        content_chunk.content_type = 'application/json'

    def _save_doc_content(self, content_chunk, content):
        content_chunk.contents = content
        content_chunk.content_type = 'text/html'

    def share_file(self, file_id, email):
        self.client.share_file(file_id, email)
<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
import os
import sys
import zephyr
import random

if __name__ == '__main__':
    cur_file = os.path.abspath(__file__)
    django_dir = os.path.abspath(os.path.join(os.path.dirname(cur_file), '..'))
    sys.path.append(django_dir)
    os.environ['DJANGO_SETTINGS_MODULE'] = 'zscore.settings'

import django.contrib.auth.models
from django.core.exceptions import ValidationError

import sleep.models

def setup():
    zephyr.init()
    subs = zephyr.Subscriptions()
    subs.add(('message', '*', '%me%'))

def fetch_user_from_zgram(zgram):
    if not zgram.auth:
        print "  -> Rejecting: unauthenticated"
        raise LookupError("You aren't authenticated.")
    user, at, domain = zgram.sender.partition('@')
    if domain == 'ATHENA.MIT.EDU':
        email = "%s@mit.edu" % (user, )
        try:
            user = django.contrib.auth.models.User.objects.get(email=email)
            return user
        except django.contrib.auth.models.User.DoesNotExist:
            raise LookupError("No user with email %s" % (email, ))
    else:
        raise LookupError("Don't know about the domain %s" % (domain, ))

def build_reply(zgram):
    z = zephyr.ZNotice()
    z.cls = zgram.cls
    z.instance = zgram.instance
    z.recipient = zgram.sender
    z.opcode = 'auto'
    z.fields = ['zscore bot: http://zscore.mit.edu/', '']
    return z

def handle_zgram(zgram):
    reply = build_reply(zgram)
    try:
        user = fetch_user_from_zgram(zgram)
        if 'gnight' in zgram.message or 'goodnight' in zgram.message:
            success = sleep.models.PartialSleep.create_new_for_user(user)
            if success:
                msg = 'Sleep well!'
            else:
                msg = "Hmm, I can't seem to record you as asleep."
        elif 'awake' in zgram.message or "mornin'" in zgram.message:
            try:
                s = sleep.models.PartialSleep.finish_for_user(user)
                tmpl = "Good morning!\nYou slept from %s to %s.\n(That's %s.)"
                msg = tmpl % (s.start_time, s.end_time, s.length())
            except sleep.models.PartialSleep.DoesNotExist:
                msg = "Sorry, you don't seem to have been asleep."
            except ValidationError as e:
                msg = e.messages[0]
        elif 'meow' in zgram.message.lower():
            msg = random.choice(['meow!', "purrrr", "*barks*"])
        else:
            msg = "I'm sorry -- I don't understand."
    except LookupError as e:
        msg = "I'm sorry -- I can't find an account for you: %s" % (e.message, )
    reply.fields[1] = msg
    reply.send()

def main():
    setup()
    print "Waiting..."
    while True:
        zgram = zephyr.receive(True)
        if not zgram or zgram.opcode == 'PING':
            continue
        if zgram.opcode.lower() == 'kill':
            sys.exit(0)

        print '%s: [%s] -c %s -i "%s": %s -> %s' % (
            datetime.datetime.now(),
            zgram.opcode,
            zgram.cls, zgram.instance,
            zgram.sender, zgram.recipient,
        )
        if zgram.opcode.lower() == 'auto':
            print "  -> auto; ignoring"
            continue

        handle_zgram(zgram)

if __name__ == '__main__':
    main()
<commit_msg>Adds help text to zephyrbot<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
import os
import sys
import zephyr
import random

if __name__ == '__main__':
    cur_file = os.path.abspath(__file__)
    django_dir = os.path.abspath(os.path.join(os.path.dirname(cur_file), '..'))
    sys.path.append(django_dir)
    os.environ['DJANGO_SETTINGS_MODULE'] = 'zscore.settings'

import django.contrib.auth.models
from django.core.exceptions import ValidationError

import sleep.models

def setup():
    zephyr.init()
    subs = zephyr.Subscriptions()
    subs.add(('message', '*', '%me%'))

def fetch_user_from_zgram(zgram):
    if not zgram.auth:
        print "  -> Rejecting: unauthenticated"
        raise LookupError("You aren't authenticated.")
    user, at, domain = zgram.sender.partition('@')
    if domain == 'ATHENA.MIT.EDU':
        email = "%s@mit.edu" % (user, )
        try:
            user = django.contrib.auth.models.User.objects.get(email=email)
            return user
        except django.contrib.auth.models.User.DoesNotExist:
            raise LookupError("No user with email %s" % (email, ))
    else:
        raise LookupError("Don't know about the domain %s" % (domain, ))

def build_reply(zgram):
    z = zephyr.ZNotice()
    z.cls = zgram.cls
    z.instance = zgram.instance
    z.recipient = zgram.sender
    z.opcode = 'auto'
    z.fields = ['zscore bot: http://zscore.mit.edu/', '']
    return z

def handle_zgram(zgram):
    reply = build_reply(zgram)
    try:
        user = fetch_user_from_zgram(zgram)
        if 'gnight' in zgram.message or 'goodnight' in zgram.message:
            success = sleep.models.PartialSleep.create_new_for_user(user)
            if success:
                msg = 'Sleep well!'
            else:
                msg = "Hmm, I can't seem to record you as asleep."
        elif 'awake' in zgram.message or "mornin'" in zgram.message:
            try:
                s = sleep.models.PartialSleep.finish_for_user(user)
                tmpl = "Good morning!\nYou slept from %s to %s.\n(That's %s.)"
                msg = tmpl % (s.start_time, s.end_time, s.length())
            except sleep.models.PartialSleep.DoesNotExist:
                msg = "Sorry, you don't seem to have been asleep."
            except ValidationError as e:
                msg = e.messages[0]
        elif 'help' in zgram.message:
            msg = "Hi! I'm the zscore zephyrbot.\n\nMessage me 'gnight' when you want to sleep\nand 'awake' when you wake up in the morning"
        elif 'meow' in zgram.message.lower():
            msg = random.choice(['meow!', "purrrr", "*barks*"])
        else:
            msg = "I'm sorry -- I don't understand."
    except LookupError as e:
        msg = "I'm sorry -- I can't find an account for you: %s" % (e.message, )
    reply.fields[1] = msg
    reply.send()

def main():
    setup()
    print "Waiting..."
    while True:
        zgram = zephyr.receive(True)
        if not zgram or zgram.opcode == 'PING':
            continue
        if zgram.opcode.lower() == 'kill':
            sys.exit(0)

        print '%s: [%s] -c %s -i "%s": %s -> %s' % (
            datetime.datetime.now(),
            zgram.opcode,
            zgram.cls, zgram.instance,
            zgram.sender, zgram.recipient,
        )
        if zgram.opcode.lower() == 'auto':
            print "  -> auto; ignoring"
            continue

        handle_zgram(zgram)

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