<commit_before># This file is part of Rubber and thus covered by the GPL
# (c) Emmanuel Beffara, 2002--2006
# Modified by Olivier Verdier <olivier.verdier@gmail.com>

import re
import string

# The function `_' is defined here to prepare for internationalization.
def _ (txt): return txt

re_loghead = re.compile("This is [0-9a-zA-Z-]*(TeX|Omega)")
re_rerun = re.compile("LaTeX Warning:.*Rerun")
re_file = re.compile("(\\((?P<file>[^ \n\t(){}]*)|\\))")
re_badbox = re.compile(r"(Ov|Und)erfull \\[hv]box ")
re_line = re.compile(r"(l\.(?P<line>[0-9]+)( (?P<code>.*))?$|<\*>)")
re_cseq = re.compile(r".*(?P<seq>\\[^ ]*) ?$")
re_page = re.compile("\[(?P<num>[0-9]+)\]")
re_atline = re.compile(
"( detected| in paragraph)? at lines? (?P<line>[0-9]*)(--(?P<last>[0-9]*))?")
re_reference = re.compile("LaTeX Warning: Reference `(?P<ref>.*)' \
on page (?P<page>[0-9]*) undefined on input line (?P<line>[0-9]*)\\.$")
re_label = re.compile("LaTeX Warning: (?P<text>Label .*)$")
re_warning = re.compile(
"(LaTeX|Package)( (?P<pkg>.*))? Warning: (?P<text>.*)$")
re_online = re.compile("(; reported)? on input line (?P<line>[0-9]*)")
re_ignored = re.compile("; all text was ignored after line (?P<line>[0-9]*).$")

class LogCheck (object):
	"""
	This class performs all the extraction of information from the log file.
	For efficiency, the instances contain the whole file as a list of strings
	so that it can be read several times with no disk access.
	"""
	#-- Initialization {{{2

	def __init__ (self):
		self.lines = None

	def read (self, name):
		"""
		Read the specified log file, checking that it was produced by the
		right compiler. Returns true if the log file is invalid or does not
		exist.
		"""
		self.lines = None
		file = open(name)
		line = file.readline()
		if not line:
			file.close()
			raise ValueError("Empty file")
		if not re_loghead.match(line):
			file.close()
			raise ValueError("This doesn't seem to be a tex log file")
		self.lines = file.readlines()
		file.close()

	#-- Process information {{{2

	def errors (self):
		"""
		Returns true if there was an error during the compilation.
		"""
		skipping = 0
		for line in self.lines:
			if line.strip() == "":
				skipping = 0
				continue
			if skipping:
				continue
			m = re_badbox.match(line)
			if m:
				skipping = 1
				continue
			if line[0] == "!":
				# We check for the substring "pdfTeX warning" because pdfTeX
				# sometimes issues warnings (like undefined references) in the
				# form of errors...

				if string.find(line, "pdfTeX warning") == -1:
					return True
		return False

	def run_needed (self):
		"""
		Returns true if LaTeX indicated that another compilation is needed.
		"""
		for line in self.lines:
			if re_rerun.match(line):
				return True
		return False

	#-- Information extraction {{{2

	def continued (self, line):
		"""
		Check if a line in the log is continued on the next line. This is
		needed because TeX breaks messages at 79 characters per line. We make
		this into a method because the test is slightly different in Metapost.
		"""
		return len(line) == 79 and line[-3:] != '...'

	def parse (self, errors=False, boxes=False, refs=False, warnings=False):
		"""
		Parse the log file for relevant information. The named arguments are
		booleans that indicate which information should be extracted:
		- errors: all errors
		- boxes: bad boxes
		- refs: warnings about references
		- warnings: all other warnings
		The function returns a generator. Each generated item is a dictionary
		that contains (some of) the following entries:
		- kind: the kind of information ("error", "box", "ref", "warning")
		- text: the text of the error or warning
		- code: the piece of code that caused an error
		- file, line, last, pkg: as used by Message.format_pos.
		"""
		if not self.lines:
			return
		last_file = None
		pos = [last_file]
		page = 1
		parsing = False   # True if we are parsing an error's text
		skipping = False  # True if we are skipping text until an empty line
		something = False # True if some error was found
		prefix = None  # the prefix for warning messages from packages
		accu = ""      # accumulated text from the previous line
		for line in self.lines:
			line = line[:-1]  # remove the line feed

			# TeX breaks messages at 79 characters, just to make parsing
			# trickier...

			if self.continued(line):
				accu += line
				continue
			line = accu + line
			accu = ""

			# Text that should be skipped (from bad box messages)

			if prefix is None and line == "":
				skipping = False
				continue

			if skipping:
				continue

			# Errors (including aborted compilation)

			if parsing:
				if error == "Undefined control sequence.":
					# This is a special case in order to report which control
					# sequence is undefined.
					m = re_cseq.match(line)
					if m:
						error = "Undefined control sequence %s." % m.group("seq")
				m = re_line.match(line)
				if m:
					parsing = False
					skipping = True
					pdfTeX = string.find(line, "pdfTeX warning") != -1
					if (pdfTeX and warnings) or (errors and not pdfTeX):
						if pdfTeX:
							d = {
								"kind": "warning",
								"pkg": "pdfTeX",
								"text": error[error.find(":")+2:]
							}
						else:
							d =	{
								"kind": "error",
								"text": error
							}
						d.update( m.groupdict() )
						m = re_ignored.search(error)
						if m:
							d["file"] = last_file
							if d.has_key("code"):
								del d["code"]
							d.update( m.groupdict() )
						elif pos[-1] is None:
							d["file"] = last_file
						else:
							d["file"] = pos[-1]
						yield d
				elif line[0] == "!":
					error = line[2:]
				elif line[0:3] == "***":
					parsing = False
					skipping = True
					if errors:
						yield	{
							"kind": "abort",
							"text": error,
							"why" : line[4:],
							"file": last_file
							}
				elif line[0:15] == "Type X to quit ":
					parsing = False
					skipping = False
					if errors:
						yield	{
							"kind": "error",
							"text": error,
							"file": pos[-1]
							}
				continue

			if len(line) > 0 and line[0] == "!":
				error = line[2:]
				parsing = True
				continue

			if line == "Runaway argument?":
				error = line
				parsing = True
				continue

			# Long warnings

			if prefix is not None:
				if line[:len(prefix)] == prefix:
					text.append(string.strip(line[len(prefix):]))
				else:
					text = " ".join(text)
					m = re_online.search(text)
					if m:
						info["line"] = m.group("line")
						text = text[:m.start()] + text[m.end():]
					if warnings:
						info["text"] = text
						d = { "kind": "warning" }
						d.update( info )
						yield d
					prefix = None
				continue

			# Undefined references

			m = re_reference.match(line)
			if m:
				if refs:
					d =	{
						"kind": "warning",
						"text": _("Reference `%s' undefined.") % m.group("ref"),
						"file": pos[-1]
						}
					d.update( m.groupdict() )
					yield d
				continue

			m = re_label.match(line)
			if m:
				if refs:
					d =	{
						"kind": "warning",
						"file": pos[-1]
						}
					d.update( m.groupdict() )
					yield d
				continue

			# Other warnings

			if line.find("Warning") != -1:
				m = re_warning.match(line)
				if m:
					info = m.groupdict()
					info["file"] = pos[-1]
					info["page"] = page
					if info["pkg"] is None:
						del info["pkg"]
						prefix = ""
					else:
						prefix = ("(%s)" % info["pkg"])
					prefix = prefix.ljust(m.start("text"))
					text = [info["text"]]
				continue

			# Bad box messages

			m = re_badbox.match(line)
			if m:
				if boxes:
					mpos = { "file": pos[-1], "page": page }
					m = re_atline.search(line)
					if m:
						md = m.groupdict()
						for key in "line", "last":
							if md[key]: mpos[key] = md[key]
						line = line[:m.start()]
					d =	{
						"kind": "warning",
						"text": line
						}
					d.update( mpos )
					yield d
				skipping = True
				continue

			# If there is no message, track source names and page numbers.

			last_file = self.update_file(line, pos, last_file)
			page = self.update_page(line, page)

	def get_errors (self):
		return self.parse(errors=1)
	def get_boxes (self):
		return self.parse(boxes=1)
	def get_references (self):
		return self.parse(refs=1)
	def get_warnings (self):
		return self.parse(warnings=1)

	def update_file (self, line, stack, last):
		"""
		Parse the given line of log file for file openings and closings and
		update the list `stack'. Newly opened files are at the end, therefore
		stack[1] is the main source while stack[-1] is the current one. The
		first element, stack[0], contains the value None for errors that may
		happen outside the source. Return the last file from which text was
		read (the new stack top, or the one before the last closing
		parenthesis).
		"""
		m = re_file.search(line)
		while m:
			if line[m.start()] == '(':
				last = m.group("file")
				stack.append(last)
			else:
				last = stack[-1]
				del stack[-1]
			line = line[m.end():]
			m = re_file.search(line)
		return last

	def update_page (self, line, before):
		"""
		Parse the given line and return the number of the page that is being
		built after that line, assuming the current page before the line was
		`before'.
		"""
		ms = re_page.findall(line)
		if ms == []:
			return before
		return int(ms[-1]) + 1

if __name__ == '__main__':
	parser = LogCheck()
	parser.read('short.log')
	errs = list(parser.get_errors())<commit_msg>some ints converted to bools<commit_after># This file is part of Rubber and thus covered by the GPL
# (c) Emmanuel Beffara, 2002--2006
# Modified by Olivier Verdier <olivier.verdier@gmail.com>

import re
import string

# The function `_' is defined here to prepare for internationalization.
def _ (txt): return txt

re_loghead = re.compile("This is [0-9a-zA-Z-]*(TeX|Omega)")
re_rerun = re.compile("LaTeX Warning:.*Rerun")
re_file = re.compile("(\\((?P<file>[^ \n\t(){}]*)|\\))")
re_badbox = re.compile(r"(Ov|Und)erfull \\[hv]box ")
re_line = re.compile(r"(l\.(?P<line>[0-9]+)( (?P<code>.*))?$|<\*>)")
re_cseq = re.compile(r".*(?P<seq>\\[^ ]*) ?$")
re_page = re.compile("\[(?P<num>[0-9]+)\]")
re_atline = re.compile(
"( detected| in paragraph)? at lines? (?P<line>[0-9]*)(--(?P<last>[0-9]*))?")
re_reference = re.compile("LaTeX Warning: Reference `(?P<ref>.*)' \
on page (?P<page>[0-9]*) undefined on input line (?P<line>[0-9]*)\\.$")
re_label = re.compile("LaTeX Warning: (?P<text>Label .*)$")
re_warning = re.compile(
"(LaTeX|Package)( (?P<pkg>.*))? Warning: (?P<text>.*)$")
re_online = re.compile("(; reported)? on input line (?P<line>[0-9]*)")
re_ignored = re.compile("; all text was ignored after line (?P<line>[0-9]*).$")

class LogCheck (object):
	"""
	This class performs all the extraction of information from the log file.
	For efficiency, the instances contain the whole file as a list of strings
	so that it can be read several times with no disk access.
	"""
	#-- Initialization {{{2

	def __init__ (self):
		self.lines = None

	def read (self, name):
		"""
		Read the specified log file, checking that it was produced by the
		right compiler. Returns true if the log file is invalid or does not
		exist.
		"""
		self.lines = None
		file = open(name)
		line = file.readline()
		if not line:
			file.close()
			raise ValueError("Empty file")
		if not re_loghead.match(line):
			file.close()
			raise ValueError("This doesn't seem to be a tex log file")
		self.lines = file.readlines()
		file.close()

	#-- Process information {{{2

	def errors (self):
		"""
		Returns true if there was an error during the compilation.
		"""
		skipping = 0
		for line in self.lines:
			if line.strip() == "":
				skipping = 0
				continue
			if skipping:
				continue
			m = re_badbox.match(line)
			if m:
				skipping = 1
				continue
			if line[0] == "!":
				# We check for the substring "pdfTeX warning" because pdfTeX
				# sometimes issues warnings (like undefined references) in the
				# form of errors...

				if string.find(line, "pdfTeX warning") == -1:
					return True
		return False

	def run_needed (self):
		"""
		Returns true if LaTeX indicated that another compilation is needed.
		"""
		for line in self.lines:
			if re_rerun.match(line):
				return True
		return False

	#-- Information extraction {{{2

	def continued (self, line):
		"""
		Check if a line in the log is continued on the next line. This is
		needed because TeX breaks messages at 79 characters per line. We make
		this into a method because the test is slightly different in Metapost.
		"""
		return len(line) == 79 and line[-3:] != '...'

	def parse (self, errors=False, boxes=False, refs=False, warnings=False):
		"""
		Parse the log file for relevant information. The named arguments are
		booleans that indicate which information should be extracted:
		- errors: all errors
		- boxes: bad boxes
		- refs: warnings about references
		- warnings: all other warnings
		The function returns a generator. Each generated item is a dictionary
		that contains (some of) the following entries:
		- kind: the kind of information ("error", "box", "ref", "warning")
		- text: the text of the error or warning
		- code: the piece of code that caused an error
		- file, line, last, pkg: as used by Message.format_pos.
		"""
		if not self.lines:
			return
		last_file = None
		pos = [last_file]
		page = 1
		parsing = False   # True if we are parsing an error's text
		skipping = False  # True if we are skipping text until an empty line
		something = False # True if some error was found
		prefix = None  # the prefix for warning messages from packages
		accu = ""      # accumulated text from the previous line
		for line in self.lines:
			line = line[:-1]  # remove the line feed

			# TeX breaks messages at 79 characters, just to make parsing
			# trickier...

			if self.continued(line):
				accu += line
				continue
			line = accu + line
			accu = ""

			# Text that should be skipped (from bad box messages)

			if prefix is None and line == "":
				skipping = False
				continue

			if skipping:
				continue

			# Errors (including aborted compilation)

			if parsing:
				if error == "Undefined control sequence.":
					# This is a special case in order to report which control
					# sequence is undefined.
					m = re_cseq.match(line)
					if m:
						error = "Undefined control sequence %s." % m.group("seq")
				m = re_line.match(line)
				if m:
					parsing = False
					skipping = True
					pdfTeX = string.find(line, "pdfTeX warning") != -1
					if (pdfTeX and warnings) or (errors and not pdfTeX):
						if pdfTeX:
							d = {
								"kind": "warning",
								"pkg": "pdfTeX",
								"text": error[error.find(":")+2:]
							}
						else:
							d =	{
								"kind": "error",
								"text": error
							}
						d.update( m.groupdict() )
						m = re_ignored.search(error)
						if m:
							d["file"] = last_file
							if d.has_key("code"):
								del d["code"]
							d.update( m.groupdict() )
						elif pos[-1] is None:
							d["file"] = last_file
						else:
							d["file"] = pos[-1]
						yield d
				elif line[0] == "!":
					error = line[2:]
				elif line[0:3] == "***":
					parsing = False
					skipping = True
					if errors:
						yield	{
							"kind": "abort",
							"text": error,
							"why" : line[4:],
							"file": last_file
							}
				elif line[0:15] == "Type X to quit ":
					parsing = False
					skipping = False
					if errors:
						yield	{
							"kind": "error",
							"text": error,
							"file": pos[-1]
							}
				continue

			if len(line) > 0 and line[0] == "!":
				error = line[2:]
				parsing = True
				continue

			if line == "Runaway argument?":
				error = line
				parsing = True
				continue

			# Long warnings

			if prefix is not None:
				if line[:len(prefix)] == prefix:
					text.append(string.strip(line[len(prefix):]))
				else:
					text = " ".join(text)
					m = re_online.search(text)
					if m:
						info["line"] = m.group("line")
						text = text[:m.start()] + text[m.end():]
					if warnings:
						info["text"] = text
						d = { "kind": "warning" }
						d.update( info )
						yield d
					prefix = None
				continue

			# Undefined references

			m = re_reference.match(line)
			if m:
				if refs:
					d =	{
						"kind": "warning",
						"text": _("Reference `%s' undefined.") % m.group("ref"),
						"file": pos[-1]
						}
					d.update( m.groupdict() )
					yield d
				continue

			m = re_label.match(line)
			if m:
				if refs:
					d =	{
						"kind": "warning",
						"file": pos[-1]
						}
					d.update( m.groupdict() )
					yield d
				continue

			# Other warnings

			if line.find("Warning") != -1:
				m = re_warning.match(line)
				if m:
					info = m.groupdict()
					info["file"] = pos[-1]
					info["page"] = page
					if info["pkg"] is None:
						del info["pkg"]
						prefix = ""
					else:
						prefix = ("(%s)" % info["pkg"])
					prefix = prefix.ljust(m.start("text"))
					text = [info["text"]]
				continue

			# Bad box messages

			m = re_badbox.match(line)
			if m:
				if boxes:
					mpos = { "file": pos[-1], "page": page }
					m = re_atline.search(line)
					if m:
						md = m.groupdict()
						for key in "line", "last":
							if md[key]: mpos[key] = md[key]
						line = line[:m.start()]
					d =	{
						"kind": "warning",
						"text": line
						}
					d.update( mpos )
					yield d
				skipping = True
				continue

			# If there is no message, track source names and page numbers.

			last_file = self.update_file(line, pos, last_file)
			page = self.update_page(line, page)

	def get_errors (self):
		return self.parse(errors=True)
	def get_boxes (self):
		return self.parse(boxes=True)
	def get_references (self):
		return self.parse(refs=True)
	def get_warnings (self):
		return self.parse(warnings=True)

	def update_file (self, line, stack, last):
		"""
		Parse the given line of log file for file openings and closings and
		update the list `stack'. Newly opened files are at the end, therefore
		stack[1] is the main source while stack[-1] is the current one. The
		first element, stack[0], contains the value None for errors that may
		happen outside the source. Return the last file from which text was
		read (the new stack top, or the one before the last closing
		parenthesis).
		"""
		m = re_file.search(line)
		while m:
			if line[m.start()] == '(':
				last = m.group("file")
				stack.append(last)
			else:
				last = stack[-1]
				del stack[-1]
			line = line[m.end():]
			m = re_file.search(line)
		return last

	def update_page (self, line, before):
		"""
		Parse the given line and return the number of the page that is being
		built after that line, assuming the current page before the line was
		`before'.
		"""
		ms = re_page.findall(line)
		if ms == []:
			return before
		return int(ms[-1]) + 1

if __name__ == '__main__':
	parser = LogCheck()
	parser.read('short.log')
	errs = list(parser.get_errors())<|endoftext|>


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

from itertools import combinations

puzzle_input = [43, 3, 4, 10, 21, 44, 4, 6, 47, 41, 34,
                17, 17, 44, 36, 31, 46, 9, 27, 38]
puzzle_input.sort()

def brute_force(containers, amount):
    eggnog_combos = [
        c
        for i in range(len(containers))
        for c in combinations(containers, i)
        if sum(c) == amount]
    number_combos = len(eggnog_combos)
    eggnog_combos.sort(key=len)
    min_containers = len(eggnog_combos[0])
    min_containers_ways = len(
        [c for c in eggnog_combos if len(c) == min_containers])
    return (number_combos, min_containers_ways)

# I got completely stuck on the recursion (it'd been a while!)
# and was helped along by this blog post:
# https://blog.jverkamp.com/2015/12/17/advent-of-code-day-17/
def find_containers(containers, amount):
    if not amount:
        yield []
    elif containers and min(containers) > amount:
        # This is just an early return for lists of containers that
        # can’t possibly work.
        return
    else:
        for idx, container in enumerate(containers):
            if container <= amount:
                for others in find_containers(
                        containers[idx+1:], amount - container):
                    yield [container] + others

# This is much faster than brute forcing, about 3 times
def recursive(containers, amount):
    containers.sort()
    container_lengths = [len(c) for c in find_containers(containers, amount)]

    # Part one
    number_combos = len(container_lengths)
    # Part two
    min_ways = container_lengths.count(min(container_lengths))
    return (number_combos, min_ways)

# print(brute_force(puzzle_input, 150))
print(recursive(puzzle_input, 150))
<commit_msg>Day 17: tidy brute force logic & whitespace<commit_after>#!/usr/bin/env python3

from itertools import combinations

puzzle_input = [43, 3, 4, 10, 21, 44, 4, 6, 47, 41, 34,
                17, 17, 44, 36, 31, 46, 9, 27, 38]
puzzle_input.sort()

def brute_force(containers, amount):
    combo_lengths = [
        len(c)
        for i in range(len(containers))
        for c in combinations(containers, i)
        if sum(c) == amount]
    number_combos = len(combo_lengths)
    min_ways = combo_lengths.count(min(combo_lengths))
    return (number_combos, min_ways)

# I got completely stuck on the recursion (it'd been a while!)
# and was helped along by this blog post:
# https://blog.jverkamp.com/2015/12/17/advent-of-code-day-17/
def find_containers(containers, amount):
    if not amount:
        yield []
    elif containers and min(containers) > amount:
        # This is just an early return for lists of containers that
        # can’t possibly work.
        return
    else:
        for idx, container in enumerate(containers):
            if container <= amount:
                for others in find_containers(
                        containers[idx+1:], amount - container):
                    yield [container] + others

# This is much faster than brute forcing, about 3 times
def recursive(containers, amount):
    containers.sort()
    container_lengths = [len(c) for c in find_containers(containers, amount)]

    # Part one
    number_combos = len(container_lengths)
    # Part two
    min_ways = container_lengths.count(min(container_lengths))
    return (number_combos, min_ways)

# print(brute_force(puzzle_input, 150))
print(recursive(puzzle_input, 150))
<|endoftext|>


<commit_before># 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.

from __future__ import absolute_import, division, print_function

import cffi

from cryptography.hazmat.bindings.utils import binding_available
from cryptography.hazmat.bindings.openssl.binding import Binding

def dummy_initializer():
    raise cffi.VerificationError

def test_binding_available():
    assert binding_available(Binding._ensure_ffi_initialized) is True

def test_binding_unavailable():
    assert binding_available(dummy_initializer) is False
<commit_msg>make the dummy_initializer fail with an actual verify call<commit_after># 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.

from __future__ import absolute_import, division, print_function

import cffi

from cryptography.hazmat.bindings.utils import binding_available
from cryptography.hazmat.bindings.openssl.binding import Binding

def dummy_initializer():
    ffi = cffi.FFI()
    ffi.verify(source="include <fake_header.h>")

def test_binding_available():
    assert binding_available(Binding._ensure_ffi_initialized) is True

def test_binding_unavailable():
    assert binding_available(dummy_initializer) is False
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""Module containing the DOV data type for screens (Filter), including
subtypes."""
import numpy as np
from .abstract import (
    AbstractDovType,
    AbstractDovSubType,
)

class Korrelverdeling(AbstractDovSubType):

    _name = 'korrelverdeling'
    _rootpath = './/grondmonster/observatieReeksData/' \
                'korrelverdeling_reeks/korrelverdeling'

    _fields = [{
        'name': 'diameter',
        'source': 'xml',
        'sourcefield': '/diameter',
        'definition': '.',
        'type': 'float',
        'notnull': False
    }, {
        'name': 'fractie',
        'source': 'xml',
        'sourcefield': '/fractie',
        'definition': '.',
        'type': 'float',
        'notnull': False
    }, {
        'name': 'methode',
        'source': 'xml',
        'sourcefield': '/methode',
        'definition': '.',
        'type': 'string',
        'notnull': False
    }, ]

class Grondmonster(AbstractDovType):
    """Class representing the DOV data type for ground samples."""

    _subtypes = [Korrelverdeling]

    _xsd_schemas = [
        'https://www.dov.vlaanderen.be/xdov/schema/latest/xsd/kern/'
        'grondmonster/GrondmonsterDataCodes.xsd',
    ]

    _fields = [{
        'name': 'pkey_boring',
        'source': 'wfs',
        'sourcefield': 'boringfiche',
        'type': 'string'
    }, {
        'name': 'pkey_grondmonster',
        'source': 'wfs',
        'sourcefield': 'grondmonsterfiche',
        'type': 'string'
    }, {
        'name': 'naam',
        'source': 'wfs',
        'sourcefield': 'naam',
        'type': 'string'
    }, {
        'name': 'boornummer',
        'source': 'wfs',
        'sourcefield': 'boornummer',
        'type': 'string'
    }, {
        'name': 'x',
        'source': 'wfs',
        'sourcefield': 'X_mL72',
        'type': 'float'
    }, {
        'name': 'y',
        'source': 'wfs',
        'sourcefield': 'Y_mL72',
        'type': 'float'
    }, {
        'name': 'z_mtaw',
        'source': 'wfs',
        'sourcefield': 'Z_mTAW',
        'type': 'float'
    }, {
        'name': 'gemeente',
        'source': 'wfs',
        'sourcefield': 'gemeente',
        'type': 'string'
    }, {
        'name': 'diepte_van_m',
        'source': 'wfs',
        'sourcefield': 'diepte_van_m',
        'type': 'float',
    }, {
        'name': 'diepte_tot_m',
        'source': 'wfs',
        'sourcefield': 'diepte_tot_m',
        'type': 'float',
    }, {
        'name': 'peil_tot_mtaw',
        'source': 'wfs',
        'sourcefield': 'peil_tot_mTAW',
        'type': 'float',
    }, {
        'name': 'monstertype',
        'source': 'xml',
        'sourcefield': '/grondmonster/monstertype',
        'xsd_type': 'MonsterEnumType',
        'definition': 'type monster',
        'type': 'string',
    }, {
        'name': 'astm_naam',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="ASTM_NAAM"]/waarde_text',
        'xsd_type': 'ParameterEnumType',
        'definition': 'ASTM_naam',
        'type': 'string'
    }, {
        'name': 'grondsoort_bggg',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="BGGG"]/waarde_text',
        'xsd_type': 'ParameterEnumType',
        'definition': 'Grondsoort BGGG',
        'type': 'string'
    }]

    def __init__(self, pkey):
        """Initialisation.

        Parameters
        ----------
        pkey : str
            Permanent key of the Filter (screen), being a URI of the form
            `https://www.dov.vlaanderen.be/data/boring/<id>`.

        """
        super(Grondmonster, self).__init__('grondmonster', pkey)

    @classmethod
    def from_wfs_element(cls, feature, namespace):
        """Build `GrondwaterFilter` instance from a WFS feature element.

        Parameters
        ----------
        feature : etree.Element
            XML element representing a single record of the WFS layer.
        namespace : str
            Namespace associated with this WFS featuretype.

        Returns
        -------
        filter : GrondwaterFilter
            An instance of this class populated with the data from the WFS
            element.

        """
        grondmonster = Grondmonster(
            feature.findtext('./{%s}grondmonster' % namespace))

        for field in cls.get_fields(source=('wfs',)).values():
            grondmonster.data[field['name']] = cls._parse(
                func=feature.findtext,
                xpath=field['sourcefield'],
                namespace=namespace,
                returntype=field.get('type', None)
            )

        return grondmonster
<commit_msg>additional fields to grondmonster type<commit_after># -*- coding: utf-8 -*-
"""Module containing the DOV data type for screens (Filter), including
subtypes."""
import numpy as np
from .abstract import (
    AbstractDovType,
    AbstractDovSubType,
)

class Korrelverdeling(AbstractDovSubType):

    _name = 'korrelverdeling'
    _rootpath = './/grondmonster/observatieReeksData/' \
                'korrelverdeling_reeks/korrelverdeling'

    _fields = [{
        'name': 'diameter',
        'source': 'xml',
        'sourcefield': '/diameter',
        'definition': '.',
        'type': 'float',
        'notnull': False
    }, {
        'name': 'fractie',
        'source': 'xml',
        'sourcefield': '/fractie',
        'definition': '.',
        'type': 'float',
        'notnull': False
    }, {
        'name': 'methode',
        'source': 'xml',
        'sourcefield': '/methode',
        'definition': '.',
        'type': 'string',
        'notnull': False
    }, ]

class Grondmonster(AbstractDovType):
    """Class representing the DOV data type for ground samples."""

    _subtypes = [Korrelverdeling]

    _xsd_schemas = [
        'https://www.dov.vlaanderen.be/xdov/schema/latest/xsd/kern/'
        'grondmonster/GrondmonsterDataCodes.xsd',
    ]

    _fields = [{
        'name': 'pkey_boring',
        'source': 'wfs',
        'sourcefield': 'boringfiche',
        'type': 'string'
    }, {
        'name': 'pkey_grondmonster',
        'source': 'wfs',
        'sourcefield': 'grondmonsterfiche',
        'type': 'string'
    }, {
        'name': 'naam',
        'source': 'wfs',
        'sourcefield': 'naam',
        'type': 'string'
    }, {
        'name': 'boornummer',
        'source': 'wfs',
        'sourcefield': 'boornummer',
        'type': 'string'
    }, {
        'name': 'x',
        'source': 'wfs',
        'sourcefield': 'X_mL72',
        'type': 'float'
    }, {
        'name': 'y',
        'source': 'wfs',
        'sourcefield': 'Y_mL72',
        'type': 'float'
    }, {
        'name': 'z_mtaw',
        'source': 'wfs',
        'sourcefield': 'Z_mTAW',
        'type': 'float'
    }, {
        'name': 'gemeente',
        'source': 'wfs',
        'sourcefield': 'gemeente',
        'type': 'string'
    }, {
        'name': 'diepte_van_m',
        'source': 'wfs',
        'sourcefield': 'diepte_van_m',
        'type': 'float',
    }, {
        'name': 'diepte_tot_m',
        'source': 'wfs',
        'sourcefield': 'diepte_tot_m',
        'type': 'float',
    }, {
        'name': 'peil_tot_mtaw',
        'source': 'wfs',
        'sourcefield': 'peil_tot_mTAW',
        'type': 'float',
    }, {
        'name': 'monstertype',
        'source': 'xml',
        'sourcefield': '/grondmonster/monstertype',
        'xsd_type': 'MonsterEnumType',
        'definition': 'type monster',
        'type': 'string',
    }, {
        'name': 'astm_naam',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="ASTM_NAAM"]/waarde_text',
        'xsd_type': 'ParameterEnumType',
        'definition': 'ASTM_naam',
        'type': 'string'
    }, {
        'name': 'grondsoort_bggg',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="BGGG"]/waarde_text',
        'xsd_type': 'ParameterEnumType',
        'definition': 'Grondsoort BGGG',
        'type': 'string'
    }, {
        'name': 'humusgehalte',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="HUMUSGEHALTE"]/waarde_numeriek',
        'xsd_type': 'ParameterEnumType',
        'definition': 'Humusgehalte',
        'type': 'float'
    }, {
        'name': 'kalkgehalte',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="KALKGEHALTE"]/waarde_numeriek',
        'xsd_type': 'ParameterEnumType',
        'definition': 'Kalkgehalte',
        'type': 'float'
    }, {
        'name': 'uitrolgrens',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="UITROLGRENS"]/waarde_numeriek',
        'xsd_type': 'ParameterEnumType',
        'definition': 'Uitrolgrens',
        'type': 'float'
    }, {
        'name': 'vloeigrens',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="VLOEIGRENS"]/waarde_numeriek',
        'xsd_type': 'ParameterEnumType',
        'definition': 'Vloeigrens',
        'type': 'float'
    }, {
        'name': 'glauconiet',
        'source': 'xml',
        'sourcefield': '/grondmonster/observatieData/observatie['
                       'parameter="GLAUCONIET_TOTAAL"]/waarde_numeriek',
        'xsd_type': 'ParameterEnumType',
        'definition': 'Glauconiet totaal',
        'type': 'float'
    }]

    def __init__(self, pkey):
        """Initialisation.

        Parameters
        ----------
        pkey : str
            Permanent key of the Grondmonster, being a URI of the form
            `https://www.dov.vlaanderen.be/data/grondmonster/<id>`.

        """
        super(Grondmonster, self).__init__('grondmonster', pkey)

    @classmethod
    def from_wfs_element(cls, feature, namespace):
        """Build `Grondmonster` instance from a WFS feature element.

        Parameters
        ----------
        feature : etree.Element
            XML element representing a single record of the WFS layer.
        namespace : str
            Namespace associated with this WFS featuretype.

        Returns
        -------
        grondmonster : Grondmonster
            An instance of this class populated with the data from the WFS
            element.

        """
        grondmonster = Grondmonster(
            feature.findtext('./{%s}grondmonster' % namespace))

        for field in cls.get_fields(source=('wfs',)).values():
            grondmonster.data[field['name']] = cls._parse(
                func=feature.findtext,
                xpath=field['sourcefield'],
                namespace=namespace,
                returntype=field.get('type', None)
            )

        return grondmonster
<|endoftext|>


<commit_before>import os
from devp2p.service import BaseService
from gevent.event import Event
#import leveldb
import plyvel
from ethereum import slogging

slogging.set_level('db', 'debug')
log = slogging.get_logger('db')

compress = decompress = lambda x: x

class LevelDB(object):

    def __init__(self, dbfile):
        self.uncommitted = dict()
        log.info('opening LevelDB', path=dbfile)
        self.dbfile = dbfile
        # self.db = leveldb.LevelDB(dbfile)
        self.db = plyvel.DB(dbfile, create_if_missing=True)

    # def reopen(self):
    #     del self.db
    #     self.db = leveldb.LevelDB(self.dbfile)

    def get(self, key):
        log.trace('getting entry', key=key.encode('hex')[:8])
        if key in self.uncommitted:
            if self.uncommitted[key] is None:
                raise KeyError("key not in db")
            log.trace('from uncommitted')
            return self.uncommitted[key]
        log.trace('from db')
        v = self.db.get(key)
        if v is None:
            raise KeyError('hey not in leveldb')
        o = decompress(v)
        self.uncommitted[key] = o
        return o

    def put(self, key, value):
        log.trace('putting entry', key=key.encode('hex')[:8], len=len(value))
        self.uncommitted[key] = value

    # def commit(self):
    #     log.info('committing', db=self, num=len(self.uncommitted))
    #     batch = leveldb.WriteBatch()
    #     for k, v in self.uncommitted.items():
    #         if v is None:
    #             batch.Delete(k)
    #         else:
    #             batch.Put(k, compress(v))
    #     self.db.Write(batch, sync=False)
    #     self.uncommitted.clear()
    #     log.info('committed', db=self, num=len(self.uncommitted))
        # self.reopen()

    def commit(self):
        log.info('committing', db=self, num=len(self.uncommitted))
        with self.db.write_batch(transaction=True, sync=True) as wb:
            for k, v in self.uncommitted.items():
                if v is None:
                    wb.delete(k)
                else:
                    wb.put(k, compress(v))
        self.uncommitted.clear()
        log.info('committed', db=self, num=len(self.uncommitted))
        # self.reopen()

    def delete(self, key):
        log.trace('deleting entry', key=key)
        self.uncommitted[key] = None

    def _has_key(self, key):
        try:
            self.get(key)
            return True
        except KeyError:
            return False

    def __contains__(self, key):
        return self._has_key(key)

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self.db == other.db

    def __repr__(self):
        return '<DB at %d uncommitted=%d>' % (id(self.db), len(self.uncommitted))

class LevelDBService(LevelDB, BaseService):

    """A service providing an interface to a level db."""

    name = 'db'
    default_config = dict(data_dir='')

    def __init__(self, app):
        BaseService.__init__(self, app)
        assert self.app.config['data_dir']
        self.uncommitted = dict()
        self.stop_event = Event()
        dbfile = os.path.join(self.app.config['data_dir'], 'leveldb')
        LevelDB.__init__(self, dbfile)

    def _run(self):
        self.stop_event.wait()

    def stop(self):
        self.stop_event.set()
        # commit?
        log.info('closing db')
<commit_msg>w/ reopen db<commit_after>import os
from devp2p.service import BaseService
from gevent.event import Event
#import leveldb
import plyvel
from ethereum import slogging

slogging.set_level('db', 'debug')
log = slogging.get_logger('db')

compress = decompress = lambda x: x

class LevelDB(object):

    def __init__(self, dbfile):
        self.uncommitted = dict()
        log.info('opening LevelDB', path=dbfile)
        self.dbfile = dbfile
        # self.db = leveldb.LevelDB(dbfile)
        self.db = plyvel.DB(dbfile, create_if_missing=True)

    def reopen(self):
        self.db.close()
        self.db = plyvel.DB(self.dbfile, create_if_missing=True)

    def get(self, key):
        log.trace('getting entry', key=key.encode('hex')[:8])
        if key in self.uncommitted:
            if self.uncommitted[key] is None:
                raise KeyError("key not in db")
            log.trace('from uncommitted')
            return self.uncommitted[key]
        log.trace('from db')
        v = self.db.get(key)
        if v is None:
            raise KeyError('hey not in leveldb')
        o = decompress(v)
        self.uncommitted[key] = o
        return o

    def put(self, key, value):
        log.trace('putting entry', key=key.encode('hex')[:8], len=len(value))
        self.uncommitted[key] = value

    # def commit(self):
    #     log.info('committing', db=self, num=len(self.uncommitted))
    #     batch = leveldb.WriteBatch()
    #     for k, v in self.uncommitted.items():
    #         if v is None:
    #             batch.Delete(k)
    #         else:
    #             batch.Put(k, compress(v))
    #     self.db.Write(batch, sync=False)
    #     self.uncommitted.clear()
    #     log.info('committed', db=self, num=len(self.uncommitted))
        # self.reopen()

    def commit(self):
        log.info('committing', db=self, num=len(self.uncommitted))
        with self.db.write_batch(transaction=True, sync=True) as wb:
            for k, v in self.uncommitted.items():
                if v is None:
                    wb.delete(k)
                else:
                    wb.put(k, compress(v))
        self.uncommitted.clear()
        log.info('committed', db=self, num=len(self.uncommitted))
        self.reopen()

    def delete(self, key):
        log.trace('deleting entry', key=key)
        self.uncommitted[key] = None

    def _has_key(self, key):
        try:
            self.get(key)
            return True
        except KeyError:
            return False

    def __contains__(self, key):
        return self._has_key(key)

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self.db == other.db

    def __repr__(self):
        return '<DB at %d uncommitted=%d>' % (id(self.db), len(self.uncommitted))

class LevelDBService(LevelDB, BaseService):

    """A service providing an interface to a level db."""

    name = 'db'
    default_config = dict(data_dir='')

    def __init__(self, app):
        BaseService.__init__(self, app)
        assert self.app.config['data_dir']
        self.uncommitted = dict()
        self.stop_event = Event()
        dbfile = os.path.join(self.app.config['data_dir'], 'leveldb')
        LevelDB.__init__(self, dbfile)

    def _run(self):
        self.stop_event.wait()

    def stop(self):
        self.stop_event.set()
        # commit?
        log.info('closing db')
<|endoftext|>


<commit_before>import datetime
import pytest

from django.core.exceptions import ValidationError

from components.merchandise.music.models import Album, Edition, Single, Track
from components.merchandise.music.factories import (AlbumFactory,
    EditionFactory, SingleFactory, TrackFactory)
from components.people.factories import GroupFactory

pytestmark = pytest.mark.django_db

class TestAlbums:
    def test_factory(self):
        factory = AlbumFactory()
        assert isinstance(factory, Album)
        assert 'album' in factory.romanized_name
        assert factory.identifier == 'album'

    def test_get_absolute_url(self, client):
        factory = AlbumFactory()
        response = client.get(factory.get_absolute_url())
        assert response.status_code == 200

    def test_regular_edition(self):
        album = AlbumFactory()
        edition = EditionFactory(album=album, kind=Edition.EDITIONS.regular)
        assert album.regular_edition == edition

    def test_regular_edition_failure(self):
        # Test that calling `regular_edition` will not fail loudly if the
        # proper edition is not found.
        album = AlbumFactory()
        edition = EditionFactory(album=album, kind=Edition.EDITIONS.limited)
        assert edition in album.editions.all()
        assert not album.regular_edition

    def test_get_previous_and_next(self):
        album1 = AlbumFactory(romanized_name='album#1', released=datetime.date.today() - datetime.timedelta(days=14), number='1')
        album2 = AlbumFactory(romanized_name='album#2', released=datetime.date.today() - datetime.timedelta(days=7), number='2')
        album3 = AlbumFactory(romanized_name='album#3', released=datetime.date.today())

        group = GroupFactory()
        album1.groups.add(group)
        assert album1.groups.exists()
        album2.groups.add(group)
        assert album2.groups.exists()
        album3.groups.add(group)
        assert album2.groups.exists()

        assert album1.get_next == album2
        assert album2.get_previous == album1
        assert album2.get_next != album3
        assert not album1.get_previous
        assert not album3.get_next

class TestSingles:
    def test_factory(self):
        factory = SingleFactory()
        assert isinstance(factory, Single)
        assert 'single' in factory.romanized_name
        assert factory.identifier == 'single'

    def test_get_absolute_url(self, client):
        factory = SingleFactory()
        response = client.get(factory.get_absolute_url())
        assert response.status_code == 200

    def test_get_previous_and_next(self):
        single1 = SingleFactory(romanized_name='single#1', released=datetime.date.today() - datetime.timedelta(days=14), number='1')
        single2 = SingleFactory(romanized_name='single#2', released=datetime.date.today() - datetime.timedelta(days=7), number='2')
        single3 = SingleFactory(romanized_name='single#3', released=datetime.date.today())

        group = GroupFactory()
        single1.groups.add(group)
        assert single1.groups.exists()
        single2.groups.add(group)
        assert single2.groups.exists()
        single3.groups.add(group)
        assert single2.groups.exists()

        assert single1.get_next == single2
        assert single2.get_previous == single1
        assert single2.get_next != single3
        assert not single1.get_previous
        assert not single3.get_next

class TestEditions:
    def test_factory(self):
        single = SingleFactory()
        factory = EditionFactory(single=single)
        assert isinstance(factory, Edition)
        assert 'edition' in factory.romanized_name

    def test_string_representation(self):
        single = SingleFactory()
        edition = EditionFactory(single=single)
        assert 'single', 'edition' in str(edition)

    def test_get_absolute_url(self, client):
        single = SingleFactory()
        edition = EditionFactory(single=single)
        response = client.get(edition.get_absolute_url())
        assert edition.get_absolute_url() == single.get_absolute_url()
        assert response.status_code == 200

    def test_parent(self):
        single = SingleFactory()
        edition = EditionFactory(single=single)
        assert edition.parent == single

    def test_get_regular_edition(self):
        single = SingleFactory()
        edition1 = EditionFactory(single=single, kind=Edition.EDITIONS.regular)
        edition2 = EditionFactory(single=single, kind=Edition.EDITIONS.limited)
        assert edition2._get_regular_edition() == edition1

class TestTracks:
    def test_factory(self):
        factory = TrackFactory()
        assert isinstance(factory, Track)
        assert 'track' in factory.romanized_name

    def test_get_absolute_url(self, client):
        single = SingleFactory()
        factory = TrackFactory(single=single)
        response = client.get(factory.get_absolute_url())
        assert response.status_code == 200

    def test_original_track_slug_exception(self):
        with pytest.raises(ValidationError):
            original_track = TrackFactory(slug='track')
            track = TrackFactory(original_track=original_track, slug='track')
<commit_msg>Cover another branch. :<<commit_after>import datetime
import pytest

from django.core.exceptions import ValidationError

from components.merchandise.music.models import Album, Edition, Single, Track
from components.merchandise.music.factories import (AlbumFactory,
    EditionFactory, SingleFactory, TrackFactory)
from components.people.factories import GroupFactory

pytestmark = pytest.mark.django_db

class TestAlbums:
    def test_factory(self):
        factory = AlbumFactory()
        assert isinstance(factory, Album)
        assert 'album' in factory.romanized_name
        assert factory.identifier == 'album'

    def test_get_absolute_url(self, client):
        factory = AlbumFactory()
        response = client.get(factory.get_absolute_url())
        assert response.status_code == 200

    def test_regular_edition(self):
        album = AlbumFactory()
        edition = EditionFactory(album=album, kind=Edition.EDITIONS.regular)
        assert album.regular_edition == edition

    def test_regular_edition_failure(self):
        # Test that calling `regular_edition` will not fail loudly if the
        # proper edition is not found.
        album = AlbumFactory()
        edition = EditionFactory(album=album, kind=Edition.EDITIONS.limited)
        assert edition in album.editions.all()
        assert not album.regular_edition

    def test_get_previous_and_next(self):
        album1 = AlbumFactory(romanized_name='album#1', released=datetime.date.today() - datetime.timedelta(days=14), number='1')
        album2 = AlbumFactory(romanized_name='album#2', released=datetime.date.today() - datetime.timedelta(days=7), number='2')
        album3 = AlbumFactory(romanized_name='album#3', released=datetime.date.today())

        group = GroupFactory()
        album1.groups.add(group)
        assert album1.groups.exists()
        album2.groups.add(group)
        assert album2.groups.exists()
        album3.groups.add(group)
        assert album2.groups.exists()

        assert album1.get_next == album2
        assert album2.get_previous == album1
        assert album2.get_next != album3
        assert not album1.get_previous
        assert not album3.get_next

class TestSingles:
    def test_factory(self):
        factory = SingleFactory()
        assert isinstance(factory, Single)
        assert 'single' in factory.romanized_name
        assert factory.identifier == 'single'

    def test_get_absolute_url(self, client):
        factory = SingleFactory()
        response = client.get(factory.get_absolute_url())
        assert response.status_code == 200

    def test_get_previous_and_next(self):
        single1 = SingleFactory(romanized_name='single#1', released=datetime.date.today() - datetime.timedelta(days=14), number='1')
        single2 = SingleFactory(romanized_name='single#2', released=datetime.date.today() - datetime.timedelta(days=7), number='2')
        single3 = SingleFactory(romanized_name='single#3', released=datetime.date.today())

        group = GroupFactory()
        single1.groups.add(group)
        assert single1.groups.exists()
        single2.groups.add(group)
        assert single2.groups.exists()
        single3.groups.add(group)
        assert single2.groups.exists()

        assert single1.get_next == single2
        assert single2.get_previous == single1
        assert single2.get_next != single3
        assert not single1.get_previous
        assert not single3.get_next

class TestEditions:
    def test_factory(self):
        single = SingleFactory()
        factory = EditionFactory(single=single)
        assert isinstance(factory, Edition)
        assert 'edition' in factory.romanized_name

    def test_string_representation(self):
        single = SingleFactory()
        edition = EditionFactory(single=single)
        assert 'single', 'edition' in str(edition)

    def test_get_absolute_url(self, client):
        single = SingleFactory()
        edition = EditionFactory(single=single)
        response = client.get(edition.get_absolute_url())
        assert edition.get_absolute_url() == single.get_absolute_url()
        assert response.status_code == 200

    def test_parent(self):
        single = SingleFactory()
        edition = EditionFactory(single=single)
        assert edition.parent == single

    def test_get_regular_edition(self):
        single = SingleFactory()
        edition1 = EditionFactory(single=single, kind=Edition.EDITIONS.regular)
        edition2 = EditionFactory(single=single, kind=Edition.EDITIONS.limited)
        assert edition2._get_regular_edition() == edition1

class TestTracks:
    def test_factory(self):
        factory = TrackFactory()
        assert isinstance(factory, Track)
        assert 'track' in factory.romanized_name

    def test_get_absolute_url(self, client):
        single = SingleFactory()
        original_track = TrackFactory(single=single)
        response = client.get(original_track.get_absolute_url())
        assert response.status_code == 200

        child_track = TrackFactory(single=single, original_track=original_track)
        response = client.get(child_track.get_absolute_url())
        assert child_track.get_absolute_url() == original_track.get_absolute_url()
        assert response.status_code == 200

    def test_original_track_slug_exception(self):
        with pytest.raises(ValidationError):
            original_track = TrackFactory(slug='track')
            track = TrackFactory(original_track=original_track, slug='track')
<|endoftext|>


<commit_before>#!/usr/bin/env python
# vim:ts=4:sw=4:et:

import os

watchman_src_dir = os.environ.get("CMAKE_CURRENT_SOURCE_DIR")
if watchman_src_dir is None:
    watchman_src_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")

# The python source dir.
# On Windows, this has to be relative to the cwd otherwise something
# in the setuptools machinery does the wrong thing and produces a
# path like `Z:blah` which on windows resolves ambiguously depending
# on the cwd.
py_dir = os.path.join(watchman_src_dir, "python")
if os.name == "nt":
    py_dir = os.path.relpath(py_dir)

def srcs(names):
    """ transform a list of sources to be relative to py_dir """
    return ["%s/%s" % (py_dir, n) for n in names]

try:
    from setuptools import setup, Extension
except:
    from distutils.core import setup, Extension

setup(
    name="pywatchman",
    version="1.4.1",
    package_dir={"": py_dir},
    description="Watchman client for python",
    author="Wez Furlong, Rain",
    author_email="wez@fb.com",
    maintainer="Wez Furlong",
    maintainer_email="wez@fb.com",
    url="https://github.com/facebook/watchman",
    long_description="Connect and query Watchman to discover file changes",
    keywords=("watchman inotify fsevents kevent kqueue portfs filesystem watcher"),
    license="BSD",
    packages=["pywatchman"],
    ext_modules=[Extension("pywatchman.bser", sources=srcs(["pywatchman/bser.c"]))],
    platforms="Platform Independent",
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: Developers",
        "Topic :: System :: Filesystems",
        "License :: OSI Approved :: BSD License",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 2",
        "Programming Language :: Python :: 2.6",
        "Programming Language :: Python :: 2.7",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.5",
        "Programming Language :: Python :: 3.6",
    ],
    zip_safe=True,
    scripts=srcs(
        [
            "bin/watchman-make",
            "bin/watchman-wait",
            "bin/watchman-replicate-subscription",
        ]
    ),
    test_suite="tests",
)
<commit_msg>watchman: just use distutils for python setup<commit_after>#!/usr/bin/env python
# vim:ts=4:sw=4:et:

from __future__ import absolute_import, division, print_function, unicode_literals

import os
from distutils.core import Extension, setup

watchman_src_dir = os.environ.get("CMAKE_CURRENT_SOURCE_DIR")
if watchman_src_dir is None:
    watchman_src_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")

# The python source dir.
# On Windows, this has to be relative to the cwd otherwise something
# in the setuptools machinery does the wrong thing and produces a
# path like `Z:blah` which on windows resolves ambiguously depending
# on the cwd.
py_dir = os.path.join(watchman_src_dir, "python")
if os.name == "nt":
    py_dir = os.path.relpath(py_dir)

def srcs(names):
    """ transform a list of sources to be relative to py_dir """
    return ["%s/%s" % (py_dir, n) for n in names]

setup(
    name="pywatchman",
    version="1.4.1",
    package_dir={"": py_dir},
    description="Watchman client for python",
    author="Wez Furlong, Rain",
    author_email="wez@fb.com",
    maintainer="Wez Furlong",
    maintainer_email="wez@fb.com",
    url="https://github.com/facebook/watchman",
    long_description="Connect and query Watchman to discover file changes",
    keywords=("watchman inotify fsevents kevent kqueue portfs filesystem watcher"),
    license="BSD",
    packages=["pywatchman"],
    ext_modules=[Extension("pywatchman.bser", sources=srcs(["pywatchman/bser.c"]))],
    platforms="Platform Independent",
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: Developers",
        "Topic :: System :: Filesystems",
        "License :: OSI Approved :: BSD License",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 2",
        "Programming Language :: Python :: 2.6",
        "Programming Language :: Python :: 2.7",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.5",
        "Programming Language :: Python :: 3.6",
    ],
    zip_safe=True,
    scripts=srcs(
        [
            "bin/watchman-make",
            "bin/watchman-wait",
            "bin/watchman-replicate-subscription",
        ]
    ),
    test_suite="tests",
)
<|endoftext|>


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

import setuptools
from setuptools import setup, find_packages

import os

# from ambassador.VERSION import Version
Version = "0.0.0-dev"

requirements = open("requirements.txt", "r").read().split("\n")

def collect_data_files(dirpath):
    return [
        (subdirpath,
         [ os.path.join(subdirpath, filename)
           for filename in filenames ])
        for subdirpath, folders, filenames in os.walk(dirpath)
    ]

template_files = collect_data_files("templates")
schema_files = collect_data_files("schemas")
kat_files = [
    (subdirpath,
     [ os.path.join(subdirpath, filename)
       for filename in filenames if filename.endswith("go") ])
    for subdirpath, folders, filenames in os.walk("kat")
]

data_files = template_files + schema_files + kat_files

setup(
    name="ambassador",
    # version=versioneer.get_version(),
    # cmdclass=versioneer.get_cmdclass(),
    version=Version,
    packages=find_packages(exclude=["tests"]),
    # include_package_data=True,
    install_requires=requirements,

    data_files=data_files,

    entry_points={
        'console_scripts': [
            'ambassador=ambassador.cli:main',
            'diagd=ambassador_diag.diagd:main'
      ]
    },

    author="datawire.io",
    author_email="dev@datawire.io",
    url="https://www.getambassador.io",
    download_url="https://github.com/datawire/ambassador",
    keywords=[
        "kubernetes",
        "microservices",
        "api gateway",
        "envoy",
        "ambassador"
    ],
    classifiers=[],
)
<commit_msg>add ambassador.version to data_files<commit_after># Copyright 2018 Datawire. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

import setuptools
from setuptools import setup, find_packages

import os

# from ambassador.VERSION import Version
Version = "0.0.0-dev"

requirements = open("requirements.txt", "r").read().split("\n")

def collect_data_files(dirpath):
    return [
        (subdirpath,
         [ os.path.join(subdirpath, filename)
           for filename in filenames ])
        for subdirpath, folders, filenames in os.walk(dirpath)
    ]

template_files = collect_data_files("templates")
schema_files = collect_data_files("schemas")
kat_files = [
    (subdirpath,
     [ os.path.join(subdirpath, filename)
       for filename in filenames if filename.endswith("go") ])
    for subdirpath, folders, filenames in os.walk("kat")
]

data_files = [("", ["ambassador.version"])] + template_files + schema_files + kat_files

setup(
    name="ambassador",
    # version=versioneer.get_version(),
    # cmdclass=versioneer.get_cmdclass(),
    version=Version,
    packages=find_packages(exclude=["tests"]),
    # include_package_data=True,
    install_requires=requirements,

    data_files=data_files,

    entry_points={
        'console_scripts': [
            'ambassador=ambassador.cli:main',
            'diagd=ambassador_diag.diagd:main'
      ]
    },

    author="datawire.io",
    author_email="dev@datawire.io",
    url="https://www.getambassador.io",
    download_url="https://github.com/datawire/ambassador",
    keywords=[
        "kubernetes",
        "microservices",
        "api gateway",
        "envoy",
        "ambassador"
    ],
    classifiers=[],
)
<|endoftext|>


<commit_before># No shebang line, this module is meant to be imported
#
# Copyright 2013 Oliver Palmer
#
# 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.

"""
Custom Columns and Type Generators
==================================

Special column types used by PyFarm's models.
"""

import re
import uuid
from json import dumps, loads
from textwrap import dedent

try:  # pragma: no cover
    from UserDict import UserDict
    from UserList import UserList
except ImportError:
    from collections import UserDict, UserList

from sqlalchemy.types import (
    TypeDecorator, BigInteger, Integer, UnicodeText, TypeEngine, VARBINARY,
    VARCHAR, BINARY)
from sqlalchemy.dialects.postgresql import UUID as POSTGRES_UUID
from netaddr import AddrFormatError, IPAddress as _IPAddress

from pyfarm.master.application import db
from pyfarm.core.enums import (
    STRING_TYPES, _AgentState, _UseAgentAddress, _WorkState, _OperatingSystem,
    Values)

ID_DOCSTRING = dedent("""Provides an id for the current row.  This value should
                         never be directly relied upon and it's intended for use
                         by relationships.""")
NoneType = type(None)  # from stdlib types module
JSON_NONE = dumps(None)
RESUB_GUID_CHARS = re.compile("[{}-]")

# types which our custom column types will accept via json
try:
    # pylint: disable=undefined-variable
    JSON_CUSTOM_COLUMN_TYPES = (str, unicode, int, long)
except NameError:
    JSON_CUSTOM_COLUMN_TYPES = (str, int)

# global mappings which can be used in relationships by external
# tables
if db.engine.name == "sqlite":
    IDTypeWork = Integer
else:
    IDTypeWork = BigInteger

if db.engine.name == "postgresql":
    import psycopg2.extras
    psycopg2.extras.register_uuid()

IDTypeAgent = Integer
IDTypeTag = Integer

class JSONSerializable(TypeDecorator):
    """
    Base of all custom types which process json data
    to and from the database.

    :var tuple serialize_types:
        the kinds of objects we expect to serialize to
        and from the database

    :var bool serialize_none:
        if True then return None instead of converting it to
        its json value

    :var bool allow_blank:
        if True, do not raise a :class:`ValueError` for empty data

    :var bool allow_empty:
        if True, do not raise :class:`ValueError` if the input data
        itself is empty
    """
    impl = UnicodeText
    serialize_types = None
    serialize_none = False

    # pylint: disable=super-on-old-class
    def __init__(self, *args, **kwargs):
        super(JSONSerializable, self).__init__(*args, **kwargs)

        # make sure the subclass is doing something we expect
        if self.serialize_types is None:
            raise NotImplementedError("`serialize_types` is not defined")

    def dumps(self, value):
        """
        Performs the process of dumping `value` to json.  For classes
        such as :class:`UserDict` or :class:`UserList` this will dump the
        underlying data instead of the object itself.
        """
        if isinstance(value, (UserDict, UserList)):
            value = value.data

        return dumps(value)

    def process_bind_param(self, value, dialect):
        """Converts the value being assigned into a json blob"""
        if NoneType in self.serialize_types and value is None:
            return self.dumps(value) if self.serialize_none else value
        elif NoneType not in self.serialize_types and value is None:
            return
        elif not isinstance(value, self.serialize_types):
            args = (type(value), self.__class__.__name__)
            raise ValueError("unexpected type %s for `%s`" % args)
        else:
            return self.dumps(value)

    def process_result_value(self, value, dialect):
        """Converts data from the database into a Python object"""
        if value is not None:
            value = loads(value)

        return value

class JSONList(JSONSerializable):
    """Column type for storing list objects as json"""
    serialize_types = (list, tuple, UserList)
    json_types = list

class JSONDict(JSONSerializable):
    """Column type for storing dictionary objects as json"""
    serialize_types = (dict, UserDict)
    json_types = dict

class MACAddress(TypeDecorator):
    """
    Column type which can store and retrieve MAC addresses in a more
    efficient manner
    """
    impl = BigInteger
    MAX_INT = 0xFFFFFFFFFFFF
    json_types = JSON_CUSTOM_COLUMN_TYPES

    def process_bind_param(self, value, dialect):
        if isinstance(value, int):
            if value < 0 or value > self.MAX_INT:
                args = (value, self.__class__.__name__)
                raise ValueError("invalid integer '%s' for %s" % args)
            return value

        elif isinstance(value, STRING_TYPES):
            return int("0" + value.replace(":", ""), 16)

        elif value is None:
            return value

        else:
            raise ValueError("unexpected type %s for value" % type(value))

    def process_result_value(self, value, dialect):
        if value is not None:
            out = format((value >> 40) & 0xFF, "02x")
            out += ":"
            out += format((value >> 32) & 0xFF, "02x")
            out += ":"
            out += format((value >> 24) & 0xFF, "02x")
            out += ":"
            out += format((value >> 16) & 0xFF, "02x")
            out += ":"
            out += format((value >> 8) & 0xFF, "02x")
            out += ":"
            out += format(value & 0xFF, "02x")
            return out

class IPAddress(_IPAddress):
    """
    Custom version of :class:`netaddr.IPAddress` which can match itself
    against other instance of the same class, a string, or an integer.
    """
    def __eq__(self, other):  # pylint: disable=super-on-old-class
        if isinstance(other, STRING_TYPES):
            return str(self) == other
        elif isinstance(other, int):
            return int(self) == other
        else:
            return super(IPAddress, self).__eq__(other)

    def __ne__(self, other):  # pylint: disable=super-on-old-class
        if isinstance(other, STRING_TYPES):
            return str(self) != other
        elif isinstance(other, int):
            return int(self) != other
        else:
            return super(IPAddress, self).__ne__(other)

class IPv4Address(TypeDecorator):
    """
    Column type which can store and retrieve IPv4 addresses in a more
    efficient manner
    """
    impl = BigInteger
    MAX_INT = 4294967295
    json_types = JSON_CUSTOM_COLUMN_TYPES

    def checkInteger(self, value):
        if value < 0 or value > self.MAX_INT:
            args = (value, self.__class__.__name__)
            raise ValueError("invalid integer '%s' for %s" % args)

        return value

    def process_bind_param(self, value, dialect):
        if isinstance(value, int):
            return self.checkInteger(value)

        elif isinstance(value, STRING_TYPES):
            try:
                return self.checkInteger(int(IPAddress(value.replace("%", ""))))
            except AddrFormatError:  # pragma: no cover
                # value provided is coming from a form search
                if "%" in value:
                    return None
                raise

        elif isinstance(value, _IPAddress):
            return int(value)

        elif value is None:
            return value

        else:
            raise ValueError("unexpected type %s for value" % type(value))

    def process_result_value(self, value, dialect):
        if value is not None:
            value = IPAddress(value)
            self.checkInteger(int(value))
            return value

class EnumType(TypeDecorator):
    """
    Special column type which handles translation from a human
    readable enum into an integer that the database can use.

    :var enum:
        required class level variable which defines what enum
        this custom column handles

    :raises AssertionError:
        raised if ``enum`` is not set on the class
    """
    impl = Integer
    enum = NotImplemented
    json_types = JSON_CUSTOM_COLUMN_TYPES

    # pylint: disable=super-on-old-class
    def __init__(self, *args, **kwargs):
        super(EnumType, self).__init__(*args, **kwargs)
        assert self.enum is not NotImplemented, "`enum` not set"

    def process_bind_param(self, value, dialect):
        """
        Takes ``value`` and maps it to the internal integer.

        :raises ValueError:
            raised if ``value`` is not part of the class level
            ``enum`` mapping
        """
        if value is None:
            return None

        elif isinstance(value, Values):
            return value.int

        else:
            return self.process_result_value(value, dialect).int

    def process_result_value(self, value, dialect):
        if value is not None:
            for enum_value in self.enum:
                if value == enum_value:
                    return enum_value
            else:
                error_args = (repr(value), repr(self.enum))
                raise ValueError(
                    "failed to map %s to an enum value in %s" % error_args)

        return value

class UUIDType(TypeDecorator):
    """
    Custom column type which handles UUIDs in the appropriate
    manner for various databases.
    """
    impl = TypeEngine

    def load_dialect_impl(self, dialect):
        if dialect.name == "postgresql":
            return dialect.type_descriptor(POSTGRES_UUID())

        if dialect.name == "sqlite":
            return dialect.type_descriptor(VARCHAR(16))

        return dialect.type_descriptor(VARBINARY(16))

    def process_bind_param(self, value, dialect):
        if dialect.name == "postgresql" or value is None:
            return value

        return value.bytes

    def process_result_value(self, value, dialect):
        if dialect.name == "postgresql" or value is None:
            return value

        return uuid.UUID(bytes=value)

class OperatingSystemEnum(EnumType):
    """custom column type for working with :class:`.AgentState`"""
    enum = _OperatingSystem

class UseAgentAddressEnum(EnumType):
    """custom column type for working with :class:`.UseAgentAddress`"""
    enum = _UseAgentAddress

class AgentStateEnum(EnumType):
    """custom column type for working with :class:`.AgentState`"""
    enum = _AgentState

class WorkStateEnum(EnumType):
    """custom column type for working with :class:`.WorkState`"""
    enum = _WorkState

def id_column(column_type=None):
    """
    Produces a column used for `id` on each table.  Typically this is done
    using a class in :mod:`pyfarm.models.mixins` however because of the ORM
    and the table relationships it's cleaner to have a function produce
    the column.
    """
    return db.Column(
        column_type or Integer,
        primary_key=True, autoincrement=True, doc=ID_DOCSTRING, nullable=False)
<commit_msg>remove unused import<commit_after># No shebang line, this module is meant to be imported
#
# Copyright 2013 Oliver Palmer
#
# 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.

"""
Custom Columns and Type Generators
==================================

Special column types used by PyFarm's models.
"""

import re
import uuid
from json import dumps, loads
from textwrap import dedent

try:  # pragma: no cover
    from UserDict import UserDict
    from UserList import UserList
except ImportError:
    from collections import UserDict, UserList

from sqlalchemy.types import (
    TypeDecorator, BigInteger, Integer, UnicodeText, TypeEngine, VARBINARY,
    VARCHAR)
from sqlalchemy.dialects.postgresql import UUID as POSTGRES_UUID
from netaddr import AddrFormatError, IPAddress as _IPAddress

from pyfarm.master.application import db
from pyfarm.core.enums import (
    STRING_TYPES, _AgentState, _UseAgentAddress, _WorkState, _OperatingSystem,
    Values)

ID_DOCSTRING = dedent("""Provides an id for the current row.  This value should
                         never be directly relied upon and it's intended for use
                         by relationships.""")
NoneType = type(None)  # from stdlib types module
JSON_NONE = dumps(None)
RESUB_GUID_CHARS = re.compile("[{}-]")

# types which our custom column types will accept via json
try:
    # pylint: disable=undefined-variable
    JSON_CUSTOM_COLUMN_TYPES = (str, unicode, int, long)
except NameError:
    JSON_CUSTOM_COLUMN_TYPES = (str, int)

# global mappings which can be used in relationships by external
# tables
if db.engine.name == "sqlite":
    IDTypeWork = Integer
else:
    IDTypeWork = BigInteger

if db.engine.name == "postgresql":
    import psycopg2.extras
    psycopg2.extras.register_uuid()

IDTypeAgent = Integer
IDTypeTag = Integer

class JSONSerializable(TypeDecorator):
    """
    Base of all custom types which process json data
    to and from the database.

    :var tuple serialize_types:
        the kinds of objects we expect to serialize to
        and from the database

    :var bool serialize_none:
        if True then return None instead of converting it to
        its json value

    :var bool allow_blank:
        if True, do not raise a :class:`ValueError` for empty data

    :var bool allow_empty:
        if True, do not raise :class:`ValueError` if the input data
        itself is empty
    """
    impl = UnicodeText
    serialize_types = None
    serialize_none = False

    # pylint: disable=super-on-old-class
    def __init__(self, *args, **kwargs):
        super(JSONSerializable, self).__init__(*args, **kwargs)

        # make sure the subclass is doing something we expect
        if self.serialize_types is None:
            raise NotImplementedError("`serialize_types` is not defined")

    def dumps(self, value):
        """
        Performs the process of dumping `value` to json.  For classes
        such as :class:`UserDict` or :class:`UserList` this will dump the
        underlying data instead of the object itself.
        """
        if isinstance(value, (UserDict, UserList)):
            value = value.data

        return dumps(value)

    def process_bind_param(self, value, dialect):
        """Converts the value being assigned into a json blob"""
        if NoneType in self.serialize_types and value is None:
            return self.dumps(value) if self.serialize_none else value
        elif NoneType not in self.serialize_types and value is None:
            return
        elif not isinstance(value, self.serialize_types):
            args = (type(value), self.__class__.__name__)
            raise ValueError("unexpected type %s for `%s`" % args)
        else:
            return self.dumps(value)

    def process_result_value(self, value, dialect):
        """Converts data from the database into a Python object"""
        if value is not None:
            value = loads(value)

        return value

class JSONList(JSONSerializable):
    """Column type for storing list objects as json"""
    serialize_types = (list, tuple, UserList)
    json_types = list

class JSONDict(JSONSerializable):
    """Column type for storing dictionary objects as json"""
    serialize_types = (dict, UserDict)
    json_types = dict

class MACAddress(TypeDecorator):
    """
    Column type which can store and retrieve MAC addresses in a more
    efficient manner
    """
    impl = BigInteger
    MAX_INT = 0xFFFFFFFFFFFF
    json_types = JSON_CUSTOM_COLUMN_TYPES

    def process_bind_param(self, value, dialect):
        if isinstance(value, int):
            if value < 0 or value > self.MAX_INT:
                args = (value, self.__class__.__name__)
                raise ValueError("invalid integer '%s' for %s" % args)
            return value

        elif isinstance(value, STRING_TYPES):
            return int("0" + value.replace(":", ""), 16)

        elif value is None:
            return value

        else:
            raise ValueError("unexpected type %s for value" % type(value))

    def process_result_value(self, value, dialect):
        if value is not None:
            out = format((value >> 40) & 0xFF, "02x")
            out += ":"
            out += format((value >> 32) & 0xFF, "02x")
            out += ":"
            out += format((value >> 24) & 0xFF, "02x")
            out += ":"
            out += format((value >> 16) & 0xFF, "02x")
            out += ":"
            out += format((value >> 8) & 0xFF, "02x")
            out += ":"
            out += format(value & 0xFF, "02x")
            return out

class IPAddress(_IPAddress):
    """
    Custom version of :class:`netaddr.IPAddress` which can match itself
    against other instance of the same class, a string, or an integer.
    """
    def __eq__(self, other):  # pylint: disable=super-on-old-class
        if isinstance(other, STRING_TYPES):
            return str(self) == other
        elif isinstance(other, int):
            return int(self) == other
        else:
            return super(IPAddress, self).__eq__(other)

    def __ne__(self, other):  # pylint: disable=super-on-old-class
        if isinstance(other, STRING_TYPES):
            return str(self) != other
        elif isinstance(other, int):
            return int(self) != other
        else:
            return super(IPAddress, self).__ne__(other)

class IPv4Address(TypeDecorator):
    """
    Column type which can store and retrieve IPv4 addresses in a more
    efficient manner
    """
    impl = BigInteger
    MAX_INT = 4294967295
    json_types = JSON_CUSTOM_COLUMN_TYPES

    def checkInteger(self, value):
        if value < 0 or value > self.MAX_INT:
            args = (value, self.__class__.__name__)
            raise ValueError("invalid integer '%s' for %s" % args)

        return value

    def process_bind_param(self, value, dialect):
        if isinstance(value, int):
            return self.checkInteger(value)

        elif isinstance(value, STRING_TYPES):
            try:
                return self.checkInteger(int(IPAddress(value.replace("%", ""))))
            except AddrFormatError:  # pragma: no cover
                # value provided is coming from a form search
                if "%" in value:
                    return None
                raise

        elif isinstance(value, _IPAddress):
            return int(value)

        elif value is None:
            return value

        else:
            raise ValueError("unexpected type %s for value" % type(value))

    def process_result_value(self, value, dialect):
        if value is not None:
            value = IPAddress(value)
            self.checkInteger(int(value))
            return value

class EnumType(TypeDecorator):
    """
    Special column type which handles translation from a human
    readable enum into an integer that the database can use.

    :var enum:
        required class level variable which defines what enum
        this custom column handles

    :raises AssertionError:
        raised if ``enum`` is not set on the class
    """
    impl = Integer
    enum = NotImplemented
    json_types = JSON_CUSTOM_COLUMN_TYPES

    # pylint: disable=super-on-old-class
    def __init__(self, *args, **kwargs):
        super(EnumType, self).__init__(*args, **kwargs)
        assert self.enum is not NotImplemented, "`enum` not set"

    def process_bind_param(self, value, dialect):
        """
        Takes ``value`` and maps it to the internal integer.

        :raises ValueError:
            raised if ``value`` is not part of the class level
            ``enum`` mapping
        """
        if value is None:
            return None

        elif isinstance(value, Values):
            return value.int

        else:
            return self.process_result_value(value, dialect).int

    def process_result_value(self, value, dialect):
        if value is not None:
            for enum_value in self.enum:
                if value == enum_value:
                    return enum_value
            else:
                error_args = (repr(value), repr(self.enum))
                raise ValueError(
                    "failed to map %s to an enum value in %s" % error_args)

        return value

class UUIDType(TypeDecorator):
    """
    Custom column type which handles UUIDs in the appropriate
    manner for various databases.
    """
    impl = TypeEngine

    def load_dialect_impl(self, dialect):
        if dialect.name == "postgresql":
            return dialect.type_descriptor(POSTGRES_UUID())

        if dialect.name == "sqlite":
            return dialect.type_descriptor(VARCHAR(16))

        return dialect.type_descriptor(VARBINARY(16))

    def process_bind_param(self, value, dialect):
        if dialect.name == "postgresql" or value is None:
            return value

        return value.bytes

    def process_result_value(self, value, dialect):
        if dialect.name == "postgresql" or value is None:
            return value

        return uuid.UUID(bytes=value)

class OperatingSystemEnum(EnumType):
    """custom column type for working with :class:`.AgentState`"""
    enum = _OperatingSystem

class UseAgentAddressEnum(EnumType):
    """custom column type for working with :class:`.UseAgentAddress`"""
    enum = _UseAgentAddress

class AgentStateEnum(EnumType):
    """custom column type for working with :class:`.AgentState`"""
    enum = _AgentState

class WorkStateEnum(EnumType):
    """custom column type for working with :class:`.WorkState`"""
    enum = _WorkState

def id_column(column_type=None):
    """
    Produces a column used for `id` on each table.  Typically this is done
    using a class in :mod:`pyfarm.models.mixins` however because of the ORM
    and the table relationships it's cleaner to have a function produce
    the column.
    """
    return db.Column(
        column_type or Integer,
        primary_key=True, autoincrement=True, doc=ID_DOCSTRING, nullable=False)
<|endoftext|>