<commit_before>#!/usr/local/bin/python2.7
import sys

t_cmd = [
    'push',
    'pop',
    'add',
    'sub',
    'neg',
    'eq',
    'gt',
    'lt',
    'and',
    'or',
    'not'
]

t_segment = [
    'argument',
    'local',
    'static',
    'constant',
    'this',
    'that',
    'pointer',
    'temp',
]

def parse(line):
    # strip comments
    no_comments = line.split('#', 1)[0]
    no_comments = no_comments.split('//', 1)[0]
    tokens = no_comments.split()
    parsed_tokens = tokens
    if len(parsed_tokens) > 0:
        parsed_tokens[0] = t_cmd.index(tokens[0])
    if len(parsed_tokens) > 1:
        parsed_tokens[1] = t_segment.index(tokens[1])
    # parsed_tokens[2] is already set
    return parsed_tokens

def writecode(tokens):
    if not tokens:
        return
    asm_file.write('//')
    for token in tokens:
        asm_file.write(' ' + str(token))
    asm_file.write('\n')
    if t_cmd[tokens[0]] == 'add':
        asm_file.write('@SP\n')
        asm_file.write('M=M-1\n')
        asm_file.write('A=M\n')
        asm_file.write('D=M	// D is value at top of the stack\n')
        asm_file.write('@SP\n')
        asm_file.write('A=M-1	// Point to next highest on stack\n')
        asm_file.write('M=D+M	// Add D to that guy\n')
    if t_cmd[tokens[0]] == 'push':
        if t_segment[tokens[1]] == 'constant':
            asm_file.write('@' + tokens[2] + '\n')
            asm_file.write('D=A\n')
            asm_file.write('@SP\n')
            asm_file.write('A=M\n')
            asm_file.write('M=D\n')
            asm_file.write('@SP\n')
            asm_file.write('M=M+1\n')

cmd_name = sys.argv[0].split('/')[-1]

if len(sys.argv) != 2:
    sys.exit(cmd_name + " error: pass me one arg, the name of the file to compile")

intermediate_filename = sys.argv[1]

try:
    intermediate_code = open(intermediate_filename, "r")
except:
    sys.exit(cmd_name + " error. I couldn't open " + intermediate_filename + " for reading!")

asm_filename = intermediate_filename.replace('.vm', '.asm')

if intermediate_filename == asm_filename:
    asm_filename += ".asm"

try:
    asm_file = open(asm_filename, "w")
except:
    sys.exit(cmd_name + " error. I couldn't open " + asm_filename + " for writing!")

for line in intermediate_code:
    x = parse(line)
    writecode(x)
<commit_msg>Use class objects & methods exclusively<commit_after>#!/usr/local/bin/python2.7
import sys

class Cmd_arithmetic:
    def __init__(self, code):
        self.code = code

    def generate(self):
        return self.code

class Cmd_push:
    def __init__(self, code):
        self.code = code
        self.segment = 'constant'
        self.index = 0

    def generate(self):
        code = self.code
        if self.segment == 'constant':
            code = '@' + str(self.index) + '\n' + self.code
        return code

cmd_add = Cmd_arithmetic(
    """@SP
M=M-1
A=M
D=M	// D is value at top of the stack
@SP
A=M-1	// Point to next highest on stack
M=D+M  // Add D to that guy
"""
)

cmd_push = Cmd_push(
    """D=A
@SP
A=M
M=D
@SP
M=M+1
"""
)

def parse(line):
    # strip comments
    no_comments = line.split('#', 1)[0]
    no_comments = no_comments.split('//', 1)[0]
    tokens = no_comments.split()
    return (tokens)

def writecode(tokens):
    if not tokens:
        return
    asm_file.write('//')
    for token in tokens:
        asm_file.write(' ' + str(token))
    asm_file.write('\n')
    if tokens[0] == 'add':
        asm_file.write(cmd_add.generate())
    if tokens[0] == 'push':
        cmd_push.segment = tokens[1]
        cmd_push.index = tokens[2]
        asm_file.write(cmd_push.generate())

cmd_name = sys.argv[0].split('/')[-1]

if len(sys.argv) != 2:
    sys.exit(cmd_name + " error: pass me one arg, the name of the file to compile")

intermediate_filename = sys.argv[1]

try:
    intermediate_code = open(intermediate_filename, "r")
except:
    sys.exit(cmd_name + " error. I couldn't open " + intermediate_filename + " for reading!")

asm_filename = intermediate_filename.replace('.vm', '.asm')

if intermediate_filename == asm_filename:
    asm_filename += ".asm"

try:
    asm_file = open(asm_filename, "w")
except:
    sys.exit(cmd_name + " error. I couldn't open " + asm_filename + " for writing!")

for line in intermediate_code:
    x = parse(line)
    writecode(x)
<|endoftext|>


<commit_before>"""
Test for the chocolatey module
"""

import os

import pytest

import salt.modules.chocolatey as chocolatey
import salt.utils
import salt.utils.platform
from tests.support.mock import MagicMock, patch

pytestmark = [
    pytest.mark.skipif(
        not salt.utils.platform.is_windows(), reason="Not a Windows system"
    )
]

@pytest.fixture(scope="module")
def choco_path():
    return "C:\\path\\to\\chocolatey.exe"

@pytest.fixture(scope="module")
def choco_path_pd():
    return os.path.join(
        os.environ.get("ProgramData"), "Chocolatey", "bin", "chocolatey.exe"
    )

@pytest.fixture(scope="module")
def choco_path_sd():
    return os.path.join(
        os.environ.get("SystemDrive"), "Chocolatey", "bin", "chocolatey.bat"
    )

@pytest.fixture(scope="module")
def mock_false():
    return MagicMock(return_value=False)

@pytest.fixture(scope="module")
def mock_true():
    return MagicMock(return_value=True)

@pytest.fixture()
def configure_loader_modules():
    return {chocolatey: {"__context__": {}, "__salt__": {}}}

def test__clear_context(choco_path):
    """
    Tests _clear_context function
    """
    context = {
        "chocolatey._yes": ["--yes"],
        "chocolatey._path": choco_path,
        "chocolatey._version": "0.9.9",
    }
    with patch.dict(chocolatey.__context__, context):
        chocolatey._clear_context()
        # Did it clear all chocolatey items from __context__P?
        assert chocolatey.__context__ == {}

def test__yes_context():
    """
    Tests _yes function when it exists in __context__
    """
    with patch.dict(chocolatey.__context__, {"chocolatey._yes": ["--yes"]}):
        result = chocolatey._yes()
        expected = ["--yes"]
        # Did it return correctly
        assert result == expected
        # Did it populate __context__
        assert chocolatey.__context__["chocolatey._yes"] == expected

def test__yes_version_greater():
    """
    Test _yes when Chocolatey version is greater than 0.9.9
    """
    mock_version = MagicMock(return_value="10.0.0")
    with patch("salt.modules.chocolatey.chocolatey_version", mock_version):
        result = chocolatey._yes()
        expected = ["--yes"]
        # Did it return correctly
        assert result == expected
        # Did it populate __context__
        assert chocolatey.__context__["chocolatey._yes"] == expected

def test__yes_version_less_than():
    """
    Test _yes when Chocolatey version is less than 0.9.9
    """
    mock_version = MagicMock(return_value="0.9.0")
    with patch("salt.modules.chocolatey.chocolatey_version", mock_version):
        result = chocolatey._yes()
        expected = []
        # Did it return correctly
        assert result == expected
        # Did it populate __context__
        assert chocolatey.__context__["chocolatey._yes"] == expected

def test__find_chocolatey_context(choco_path):
    """
    Test _find_chocolatey when it exists in __context__
    """
    with patch.dict(chocolatey.__context__, {"chocolatey._path": choco_path}):
        result = chocolatey._find_chocolatey()
        expected = choco_path
        assert result == expected

def test__find_chocolatey_which(choco_path):
    """
    Test _find_chocolatey when found with `cmd.which`
    """
    mock_which = MagicMock(return_value=choco_path)
    with patch.dict(chocolatey.__salt__, {"cmd.which": mock_which}):
        result = chocolatey._find_chocolatey()
        expected = choco_path
        # Does it return the correct path
        assert result == expected
        # Does it populate __context__
        assert chocolatey.__context__["chocolatey._path"] == expected

def test__find_chocolatey_programdata(mock_false, mock_true, choco_path_pd):
    """
    Test _find_chocolatey when found in ProgramData
    """
    with patch.dict(chocolatey.__salt__, {"cmd.which": mock_false}), patch(
        "os.path.isfile", mock_true
    ):
        result = chocolatey._find_chocolatey()
        expected = choco_path_pd
        # Does it return the correct path
        assert result == expected
        # Does it populate __context__
        assert chocolatey.__context__["chocolatey._path"] == expected

def test__find_chocolatey_systemdrive(mock_false, choco_path_sd):
    """
    Test _find_chocolatey when found on SystemDrive (older versions)
    """
    with patch.dict(chocolatey.__salt__, {"cmd.which": mock_false}), patch(
        "os.path.isfile", MagicMock(side_effect=[False, True])
    ):
        result = chocolatey._find_chocolatey()
        expected = choco_path_sd
        # Does it return the correct path
        assert result == expected
        # Does it populate __context__
        assert chocolatey.__context__["chocolatey._path"] == expected

def test_version_check_remote_false():
    """
    Test version when remote is False
    """
    list_return_value = {"ack": ["3.1.1"]}
    with patch.object(chocolatey, "list_", return_value=list_return_value):
        expected = {"ack": ["3.1.1"]}
        result = chocolatey.version("ack", check_remote=False)
        assert result == expected

def test_version_check_remote_true():
    """
    Test version when remote is True
    """
    list_side_effect = [
        {"ack": ["3.1.1"]},
        {"ack": ["3.1.1"], "Wolfpack": ["3.0.17"], "blackbird": ["1.0.79.3"]},
    ]
    with patch.object(chocolatey, "list_", side_effect=list_side_effect):
        expected = {"ack": {"available": ["3.1.1"], "installed": ["3.1.1"]}}
        result = chocolatey.version("ack", check_remote=True)
        assert result == expected

def test_version_check_remote_true_not_available():
    """
    Test version when remote is True but remote version is unavailable
    """
    list_side_effect = [
        {"ack": ["3.1.1"]},
        {"Wolfpack": ["3.0.17"], "blackbird": ["1.0.79.3"]},
    ]
    with patch.object(chocolatey, "list_", side_effect=list_side_effect):
        expected = {"ack": {"installed": ["3.1.1"]}}
        result = chocolatey.version("ack", check_remote=True)
        assert result == expected
<commit_msg>Adding a unit test for the new changes. Thanks @garethgreenaway!<commit_after>"""
Test for the chocolatey module
"""

import os

import pytest

import salt.modules.chocolatey as chocolatey
import salt.utils
import salt.utils.platform
from tests.support.mock import MagicMock, patch

pytestmark = [
    pytest.mark.skipif(
        not salt.utils.platform.is_windows(), reason="Not a Windows system"
    )
]

@pytest.fixture(scope="module")
def choco_path():
    return "C:\\path\\to\\chocolatey.exe"

@pytest.fixture(scope="module")
def choco_path_pd():
    return os.path.join(
        os.environ.get("ProgramData"), "Chocolatey", "bin", "chocolatey.exe"
    )

@pytest.fixture(scope="module")
def choco_path_sd():
    return os.path.join(
        os.environ.get("SystemDrive"), "Chocolatey", "bin", "chocolatey.bat"
    )

@pytest.fixture(scope="module")
def mock_false():
    return MagicMock(return_value=False)

@pytest.fixture(scope="module")
def mock_true():
    return MagicMock(return_value=True)

@pytest.fixture()
def configure_loader_modules():
    return {chocolatey: {"__context__": {}, "__salt__": {}}}

def test__clear_context(choco_path):
    """
    Tests _clear_context function
    """
    context = {
        "chocolatey._yes": ["--yes"],
        "chocolatey._path": choco_path,
        "chocolatey._version": "0.9.9",
    }
    with patch.dict(chocolatey.__context__, context):
        chocolatey._clear_context()
        # Did it clear all chocolatey items from __context__P?
        assert chocolatey.__context__ == {}

def test__yes_context():
    """
    Tests _yes function when it exists in __context__
    """
    with patch.dict(chocolatey.__context__, {"chocolatey._yes": ["--yes"]}):
        result = chocolatey._yes()
        expected = ["--yes"]
        # Did it return correctly
        assert result == expected
        # Did it populate __context__
        assert chocolatey.__context__["chocolatey._yes"] == expected

def test__yes_version_greater():
    """
    Test _yes when Chocolatey version is greater than 0.9.9
    """
    mock_version = MagicMock(return_value="10.0.0")
    with patch("salt.modules.chocolatey.chocolatey_version", mock_version):
        result = chocolatey._yes()
        expected = ["--yes"]
        # Did it return correctly
        assert result == expected
        # Did it populate __context__
        assert chocolatey.__context__["chocolatey._yes"] == expected

def test__yes_version_less_than():
    """
    Test _yes when Chocolatey version is less than 0.9.9
    """
    mock_version = MagicMock(return_value="0.9.0")
    with patch("salt.modules.chocolatey.chocolatey_version", mock_version):
        result = chocolatey._yes()
        expected = []
        # Did it return correctly
        assert result == expected
        # Did it populate __context__
        assert chocolatey.__context__["chocolatey._yes"] == expected

def test__find_chocolatey_context(choco_path):
    """
    Test _find_chocolatey when it exists in __context__
    """
    with patch.dict(chocolatey.__context__, {"chocolatey._path": choco_path}):
        result = chocolatey._find_chocolatey()
        expected = choco_path
        assert result == expected

def test__find_chocolatey_which(choco_path):
    """
    Test _find_chocolatey when found with `cmd.which`
    """
    mock_which = MagicMock(return_value=choco_path)
    with patch.dict(chocolatey.__salt__, {"cmd.which": mock_which}):
        result = chocolatey._find_chocolatey()
        expected = choco_path
        # Does it return the correct path
        assert result == expected
        # Does it populate __context__
        assert chocolatey.__context__["chocolatey._path"] == expected

def test__find_chocolatey_programdata(mock_false, mock_true, choco_path_pd):
    """
    Test _find_chocolatey when found in ProgramData
    """
    with patch.dict(chocolatey.__salt__, {"cmd.which": mock_false}), patch(
        "os.path.isfile", mock_true
    ):
        result = chocolatey._find_chocolatey()
        expected = choco_path_pd
        # Does it return the correct path
        assert result == expected
        # Does it populate __context__
        assert chocolatey.__context__["chocolatey._path"] == expected

def test__find_chocolatey_systemdrive(mock_false, choco_path_sd):
    """
    Test _find_chocolatey when found on SystemDrive (older versions)
    """
    with patch.dict(chocolatey.__salt__, {"cmd.which": mock_false}), patch(
        "os.path.isfile", MagicMock(side_effect=[False, True])
    ):
        result = chocolatey._find_chocolatey()
        expected = choco_path_sd
        # Does it return the correct path
        assert result == expected
        # Does it populate __context__
        assert chocolatey.__context__["chocolatey._path"] == expected

def test_version_check_remote_false():
    """
    Test version when remote is False
    """
    list_return_value = {"ack": ["3.1.1"]}
    with patch.object(chocolatey, "list_", return_value=list_return_value):
        expected = {"ack": ["3.1.1"]}
        result = chocolatey.version("ack", check_remote=False)
        assert result == expected

def test_version_check_remote_true():
    """
    Test version when remote is True
    """
    list_side_effect = [
        {"ack": ["3.1.1"]},
        {"ack": ["3.1.1"], "Wolfpack": ["3.0.17"], "blackbird": ["1.0.79.3"]},
    ]
    with patch.object(chocolatey, "list_", side_effect=list_side_effect):
        expected = {"ack": {"available": ["3.1.1"], "installed": ["3.1.1"]}}
        result = chocolatey.version("ack", check_remote=True)
        assert result == expected

def test_version_check_remote_true_not_available():
    """
    Test version when remote is True but remote version is unavailable
    """
    list_side_effect = [
        {"ack": ["3.1.1"]},
        {"Wolfpack": ["3.0.17"], "blackbird": ["1.0.79.3"]},
    ]
    with patch.object(chocolatey, "list_", side_effect=list_side_effect):
        expected = {"ack": {"installed": ["3.1.1"]}}
        result = chocolatey.version("ack", check_remote=True)
        assert result == expected

def test_add_source(choco_path):
    """
    Test add_source when remote is False
    """
    cmd_run_all_mock = MagicMock(return_value={"retcode": 0, "stdout": "data"})
    cmd_run_which_mock = MagicMock(return_value=choco_path)
    with patch.dict(chocolatey.__salt__, {"cmd.which": cmd_run_which_mock,
                                          "cmd.run_all": cmd_run_all_mock}):
        expected_call = [
            choco_path,
            "sources",
            "add",
            "--name",
            "source_name",
            "--source",
            "source_location",
        ]

        result = chocolatey.add_source("source_name", "source_location")
        cmd_run_all_mock.assert_called_with(expected_call, python_shell=False)

        expected_call = [
            choco_path,
            "sources",
            "add",
            "--name",
            "source_name",
            "--source",
            "source_location",
            "--priority",
            "priority"
        ]

        result = chocolatey.add_source(
            "source_name", "source_location", priority="priority")
        cmd_run_all_mock.assert_called_with(expected_call, python_shell=False)
<|endoftext|>


<commit_before># PyVision License
#
# Copyright (c) 2006-2008 David S. Bolme
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither name of copyright holders nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import csv
import StringIO
import pyvision as pv

def convertVal(val):
    if val in ("True","False"):
        return val == "True"
    try:
        flt = float(val)
    except:
        return val

    if '.' in val:
        return flt
    else:
        return int(round(flt))

class Table:
    '''
    Store and manipulate table data
    '''

    def __init__(self,filename=None,default_value=None):
        self.col_headers = []
        self.col_label = None
        self.row_headers = []
        self.row_label = None
        self.col_format = {}
        self.hlines = False
        self.default_value = default_value
        self.data = {}
        self.rebuildTable()

        if filename != None:
            if isinstance(filename,str):
                f = open(filename,'rb')
                self.load(f)
            else:
                #Assume this is a file pointer
                self.load(filename)

    def load(self,f):
        reader = csv.reader(f)
        header=None
        #j = 0
        for data in reader:
            if header == None:
                header = data
                assert header[0] == "row"
                continue
            assert len(header) == len(data)

            for i in range(1,len(header)):
                row = convertVal(data[0])
                col = convertVal(header[i])
                val = convertVal(data[i])
                #print type(row),row,type(col),col,type(val),val
                self[row,col] = val

            #j += 1
            #if j > 300:
            #    break

    def sortByRowHeader(self,comp_func = cmp):
        self.row_headers.sort(comp_func)

    def sortByColHeader(self,comp_func = cmp):
        self.col_headers.sort(comp_func)

    def accumulateData(self,row,col,value):
        new_value = self.element(row,col) + value
        self.setData(row,col,new_value)

    def setColumnFormat(self,col,format):
        if format == None and self.col_format.has_key(col):
            # Clear formating for that column
            del self.col_format[col]
        else:
            # Set the formating for that column
            self.col_format[col] = format

    def __setitem__(self,key,value):
        return self.setElement(key[0],key[1],value)

    def setElement(self,row,col,value,accumulate=False):
        self.setData(row,col,value,accumulate=accumulate)

    def setData(self,row,col,value,accumulate=False):
        # Set an entry in the table
        labels_updated = False

        if col not in self.col_headers:
            self.col_headers.append(col)
            labels_updated = True

        if row not in self.row_headers:
            self.row_headers.append(row)
            labels_updated = True

        if labels_updated:
            self.rebuildTable()

        self.data[row][col] = value

    def rebuildTable(self):
        for row in self.row_headers:
            if not self.data.has_key(row): self.data[row] = {}
            for col in self.col_headers:
                if not self.data[row].has_key(col): self.data[row][col] = self.default_value

    def hasElement(self,row,col):
        return (self.data.has_key(row) and self.data[row].has_key(col))

    def __getitem__(self,key):
        return self.element(key[0],key[1])

    def element(self,row,col):
        if self.hasElement(row,col):
            return self.data[row][col]
        else:
            return self.default_value

    def elementAsText(self,row,col):
        if isinstance(self.col_format,str):
            return self.col_format%self.element(row,col)
        if isinstance(self.col_format,dict) and self.col_format.has_key(col):
            return self.col_format[col]%self.element(row,col)
        # Todo it would be nice to support callable objects

        # Otherwize just format as a string:
        return "%s"%(self.element(row,col),)

    def justifyText(self,text,width,side='l'):
        assert  side in ['c','l','r']
        l = len(text)
        if l > width:
            return text[:width]
        else:
            pad = width - l
            if side=='c':
                front = " "*(pad/2)
                back  = " "*(pad - pad/2)
                return front + text + back
            elif side=='r':
                return " "*pad + text
            else:
                return text + " "*pad

        return text #TODO:

    def asHtml(self, print_col_headers = True, print_row_headers = False, equal_cols = False, style='simple'):
        result = "
\n"
        result += '
\n'
        result += '    '
        for col in self.col_headers:
            result += '%s	'%col
        result += '\n'
        result += '
\n'

        i = 0
        for row in self.row_headers:
            bgcolor = '#FBEBCE'
            if i % 2 == 1:
                bgcolor = '#EFE0C4'
            result += '
\n'%bgcolor
            result += '    '
            for col in self.col_headers:
                align = 'LEFT'
                try:
                    #Check to see if the text looks like a number
                    val = float(self[row,col])
                    align = 'RIGHT'
                except:
                    # Default, justify left
                    pass

                val = self.elementAsText(row,col)
                result += '%s	'%(align,val)
            result += '\n'
            result += '
\n'
            i += 1
        result += "
\n"
        return result

    def asPlainText(self, print_col_headers = True, print_row_headers = True, equal_cols = False, separator="|"):
        '''Returns a text string which is a formated table.'''
        assert len(separator) == 1

        rows = self.row_headers
        cols = self.col_headers

        col_widths = {}
        for col in self.col_headers:
            if print_col_headers:
                col_widths[col] = len(str(col))
            else:
                col_widths[col] = 0
            for row in self.row_headers:
                w = len(self.elementAsText(row,col))
                if w > col_widths[col]:
                    col_widths[col] = w
        if equal_cols:
            new_widths = {}
            max_width = 0
            for key,value in col_widths.iteritems():
                max_width = max(max_width,value)
            for key in col_widths.keys():
                col_widths[key]=max_width

        row_header_width = 0
        for row in rows:
            row_header_width = max(row_header_width,len(str(row)))

        out = ""

        #Horizontal Rule
        if print_row_headers:
            out += "|" + "-"*(row_header_width+2)
        out += "|"
        for col in cols:
            out += "-"*(col_widths[col]+2)+"|"
        out = out[:-1]
        out += "|\n"

        if print_col_headers:
            out += "|"
            if print_row_headers:
                out += " "*(row_header_width+2)+"|"
            for col in cols:
                text = self.justifyText(str(col),col_widths[col],'l')
                out += " "+text+" |"
            out = out[:-1]
            out += "|\n"

            #Horizontal Rule
            if print_row_headers:
                out += "|" + "-"*(row_header_width+2)
            out += "|"
            for col in cols:
                out += "-"*(col_widths[col]+2)+"|"
            out = out[:-1]
            out += "|\n"

        for row in rows:
            out +="|"
            if print_row_headers:
                out += " " + self.justifyText(str(row),row_header_width,'l')+" |"
            for col in cols:
                text = self.elementAsText(row,col)
                try:
                    #Check to see if the text looks like a number
                    val = float(text)
                    # Numbers should be justifed right.
                    text = self.justifyText(text,col_widths[col],'r')
                except:
                    # Default, justify left
                    text = self.justifyText(text,col_widths[col],'l')
                assert len(text) == col_widths[col]
                out += " "+text+" "+separator
            #strip the last separator
            out = out[:-1]
            out += "|\n"

        #Horizontal Rule
        if print_row_headers:
            out += "|" + "-"*(row_header_width+2)
        out += "|"
        for col in cols:
            out += "-"*(col_widths[col]+2)+"|"
        out = out[:-1]
        out += "|\n"

        return out

    def nRows(self):
        return len(self.row_headers)

    def nCols(self):
        return len(self.col_headers)

    def asTex(self):
        '''Returns a text string which as a table formated for latex'''

    def asLists(self,headers=True):
        '''Returns the table data as a list of lists'''
        rows = self.row_headers
        cols = self.col_headers

        result = []

        if headers:
            tmp = ['row']
            for col in cols:
                tmp.append(col)
            result.append(tmp)

        for row in rows:
            tmp = []
            if headers:
                tmp.append(row)
            for col in cols:
                tmp.append(self.element(row,col))
            result.append(tmp)

        return result

    def head(self,N=10):
        '''Returns a table from the first N rows.'''
        rows = self.row_headers
        cols = self.col_headers

        result = pv.Table()

        for row in rows[:N]:
            for col in cols:
                result[row,col] = self[row,col]

        return result

    def tail(self,N=10):
        '''Returns a table from the last N rows.'''
        rows = self.row_headers
        cols = self.col_headers

        result = pv.Table()

        for row in rows[-N:]:
            for col in cols:
                result[row,col] = self[row,col]

        return result

    def save(self,filename,headers=True):
        '''Save the table to CSV'''
        if isinstance(filename,str):
            f = open(filename,'wb')
        else:
            f = filename # assume file pointer
        writer = csv.writer(f)
        writer.writerows(self.asLists(headers=headers))

    def __str__(self):
        return self.asPlainText()

import unittest
class _TestTable(unittest.TestCase):
    def setUp(self):
        color = Table(default_value=0)
        color.accumulateData('red','red',1)
        color.accumulateData('red','red',1)
        color.accumulateData('red','red',1)
        color.accumulateData('blue','blue',1)
        color.accumulateData('blue','blue',1)
        color.accumulateData('blue','blue',1)
        color.accumulateData('blue','blue',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','red',1)
        color.accumulateData('pink','red',1)
        color.accumulateData('blue','red',1)
        color.accumulateData('blue','red',1)
        color.accumulateData('red','blue',1)
        color.accumulateData('green','green',1)
        color.accumulateData('red','green',1)
        self.color = color

        # Simulate a face recognition problem with a
        # probe set of 1000 and a gallery set of 1000
        # 0.001 FAR and 0.100 FRR
        sim_face = Table(default_value=0)
        sim_face.setData('accept','accept',900)
        sim_face.setData('reject','reject',998001)
        sim_face.setData('accept','reject',100)
        sim_face.setData('reject','accept',999)
        self.sim_face = sim_face

    def test__str__(self):

        self.color.asPlainText()
        self.sim_face.asPlainText()

    def test_asLists(self):
        self.color.asLists()

    def test_save(self):
        expected = 'row,red,blue,pink,green\r\nred,3,1,0,1\r\nblue,2,4,0,0\r\npink,2,0,5,0\r\ngreen,0,0,0,1\r\n'
        output = StringIO.StringIO()
        self.color.save(output)
        self.assertEqual(output.getvalue(),expected)

        expected = '3,1,0,1\r\n2,4,0,0\r\n2,0,5,0\r\n0,0,0,1\r\n'
        output = StringIO.StringIO()
        self.color.save(output,headers=False)
        self.assertEqual(output.getvalue(),expected)

    def test_verification(self):
        self.sim_face

    def test_rowsort(self):
        tab = Table()

        tab[2,1] = 'b'
        tab[1,1] = 'a'
        tab[3,1] = 'c'

        #print tab
        tab.sortByRowHeader()
        #print tab

     <commit_msg>Changed formating for html output.<commit_after># PyVision License
#
# Copyright (c) 2006-2008 David S. Bolme
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither name of copyright holders nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import csv
import StringIO
import pyvision as pv

def convertVal(val):
    if val in ("True","False"):
        return val == "True"
    try:
        flt = float(val)
    except:
        return val

    if '.' in val:
        return flt
    else:
        return int(round(flt))

class Table:
    '''
    Store and manipulate table data
    '''

    def __init__(self,filename=None,default_value=None):
        self.col_headers = []
        self.col_label = None
        self.row_headers = []
        self.row_label = None
        self.col_format = {}
        self.hlines = False
        self.default_value = default_value
        self.data = {}
        self.rebuildTable()

        if filename != None:
            if isinstance(filename,str):
                f = open(filename,'rb')
                self.load(f)
            else:
                #Assume this is a file pointer
                self.load(filename)

    def load(self,f):
        reader = csv.reader(f)
        header=None
        #j = 0
        for data in reader:
            if header == None:
                header = data
                assert header[0] == "row"
                continue
            assert len(header) == len(data)

            for i in range(1,len(header)):
                row = convertVal(data[0])
                col = convertVal(header[i])
                val = convertVal(data[i])
                #print type(row),row,type(col),col,type(val),val
                self[row,col] = val

            #j += 1
            #if j > 300:
            #    break

    def sortByRowHeader(self,comp_func = cmp):
        self.row_headers.sort(comp_func)

    def sortByColHeader(self,comp_func = cmp):
        self.col_headers.sort(comp_func)

    def accumulateData(self,row,col,value):
        new_value = self.element(row,col) + value
        self.setData(row,col,new_value)

    def setColumnFormat(self,col,format):
        if format == None and self.col_format.has_key(col):
            # Clear formating for that column
            del self.col_format[col]
        else:
            # Set the formating for that column
            self.col_format[col] = format

    def __setitem__(self,key,value):
        return self.setElement(key[0],key[1],value)

    def setElement(self,row,col,value,accumulate=False):
        self.setData(row,col,value,accumulate=accumulate)

    def setData(self,row,col,value,accumulate=False):
        # Set an entry in the table
        labels_updated = False

        if col not in self.col_headers:
            self.col_headers.append(col)
            labels_updated = True

        if row not in self.row_headers:
            self.row_headers.append(row)
            labels_updated = True

        if labels_updated:
            self.rebuildTable()

        self.data[row][col] = value

    def rebuildTable(self):
        for row in self.row_headers:
            if not self.data.has_key(row): self.data[row] = {}
            for col in self.col_headers:
                if not self.data[row].has_key(col): self.data[row][col] = self.default_value

    def hasElement(self,row,col):
        return (self.data.has_key(row) and self.data[row].has_key(col))

    def __getitem__(self,key):
        return self.element(key[0],key[1])

    def element(self,row,col):
        if self.hasElement(row,col):
            return self.data[row][col]
        else:
            return self.default_value

    def elementAsText(self,row,col):
        if isinstance(self.col_format,str):
            return self.col_format%self.element(row,col)
        if isinstance(self.col_format,dict) and self.col_format.has_key(col):
            return self.col_format[col]%self.element(row,col)
        # Todo it would be nice to support callable objects

        # Otherwize just format as a string:
        return "%s"%(self.element(row,col),)

    def justifyText(self,text,width,side='l'):
        assert  side in ['c','l','r']
        l = len(text)
        if l > width:
            return text[:width]
        else:
            pad = width - l
            if side=='c':
                front = " "*(pad/2)
                back  = " "*(pad - pad/2)
                return front + text + back
            elif side=='r':
                return " "*pad + text
            else:
                return text + " "*pad

        return text #TODO:

    def asHtml(self, print_col_headers = True, print_row_headers = False, equal_cols = False, style='simple'):
        result = "
\n"
        result += '
\n'
        result += '    '
        if print_row_headers:
            result += '	'

        for col in self.col_headers:
            result += '%s	'%col
        result += '\n'
        result += '
\n'

        i = 0
        for row in self.row_headers:
            bgcolor = '#FBEBCE'
            if i % 2 == 1:
                bgcolor = '#EFE0C4'
            result += '
\n'%bgcolor
            result += '    '
            if print_row_headers:
                result += '%s	'%(row,)
            for col in self.col_headers:
                align = 'LEFT'
                try:
                    #Check to see if the text looks like a number
                    val = float(self[row,col])
                    align = 'RIGHT'
                except:
                    # Default, justify left
                    pass

                val = self.elementAsText(row,col)
                result += '%s	'%(align,val)
            result += '\n'
            result += '
\n'
            i += 1
        result += "
\n"
        return result

    def asPlainText(self, print_col_headers = True, print_row_headers = True, equal_cols = False, separator="|"):
        '''Returns a text string which is a formated table.'''
        assert len(separator) == 1

        rows = self.row_headers
        cols = self.col_headers

        col_widths = {}
        for col in self.col_headers:
            if print_col_headers:
                col_widths[col] = len(str(col))
            else:
                col_widths[col] = 0
            for row in self.row_headers:
                w = len(self.elementAsText(row,col))
                if w > col_widths[col]:
                    col_widths[col] = w
        if equal_cols:
            new_widths = {}
            max_width = 0
            for key,value in col_widths.iteritems():
                max_width = max(max_width,value)
            for key in col_widths.keys():
                col_widths[key]=max_width

        row_header_width = 0
        for row in rows:
            row_header_width = max(row_header_width,len(str(row)))

        out = ""

        #Horizontal Rule
        if print_row_headers:
            out += "|" + "-"*(row_header_width+2)
        out += "|"
        for col in cols:
            out += "-"*(col_widths[col]+2)+"|"
        out = out[:-1]
        out += "|\n"

        if print_col_headers:
            out += "|"
            if print_row_headers:
                out += " "*(row_header_width+2)+"|"
            for col in cols:
                text = self.justifyText(str(col),col_widths[col],'l')
                out += " "+text+" |"
            out = out[:-1]
            out += "|\n"

            #Horizontal Rule
            if print_row_headers:
                out += "|" + "-"*(row_header_width+2)
            out += "|"
            for col in cols:
                out += "-"*(col_widths[col]+2)+"|"
            out = out[:-1]
            out += "|\n"

        for row in rows:
            out +="|"
            if print_row_headers:
                out += " " + self.justifyText(str(row),row_header_width,'l')+" |"
            for col in cols:
                text = self.elementAsText(row,col)
                try:
                    #Check to see if the text looks like a number
                    val = float(text)
                    # Numbers should be justifed right.
                    text = self.justifyText(text,col_widths[col],'r')
                except:
                    # Default, justify left
                    text = self.justifyText(text,col_widths[col],'l')
                assert len(text) == col_widths[col]
                out += " "+text+" "+separator
            #strip the last separator
            out = out[:-1]
            out += "|\n"

        #Horizontal Rule
        if print_row_headers:
            out += "|" + "-"*(row_header_width+2)
        out += "|"
        for col in cols:
            out += "-"*(col_widths[col]+2)+"|"
        out = out[:-1]
        out += "|\n"

        return out

    def nRows(self):
        return len(self.row_headers)

    def nCols(self):
        return len(self.col_headers)

    def asTex(self):
        '''Returns a text string which as a table formated for latex'''

    def asLists(self,headers=True):
        '''Returns the table data as a list of lists'''
        rows = self.row_headers
        cols = self.col_headers

        result = []

        if headers:
            tmp = ['row']
            for col in cols:
                tmp.append(col)
            result.append(tmp)

        for row in rows:
            tmp = []
            if headers:
                tmp.append(row)
            for col in cols:
                tmp.append(self.element(row,col))
            result.append(tmp)

        return result

    def head(self,N=10):
        '''Returns a table from the first N rows.'''
        rows = self.row_headers
        cols = self.col_headers

        result = pv.Table()

        for row in rows[:N]:
            for col in cols:
                result[row,col] = self[row,col]

        return result

    def tail(self,N=10):
        '''Returns a table from the last N rows.'''
        rows = self.row_headers
        cols = self.col_headers

        result = pv.Table()

        for row in rows[-N:]:
            for col in cols:
                result[row,col] = self[row,col]

        return result

    def save(self,filename,headers=True):
        '''Save the table to CSV'''
        if isinstance(filename,str):
            f = open(filename,'wb')
        else:
            f = filename # assume file pointer
        writer = csv.writer(f)
        writer.writerows(self.asLists(headers=headers))

    def __str__(self):
        return self.asPlainText()

import unittest
class _TestTable(unittest.TestCase):
    def setUp(self):
        color = Table(default_value=0)
        color.accumulateData('red','red',1)
        color.accumulateData('red','red',1)
        color.accumulateData('red','red',1)
        color.accumulateData('blue','blue',1)
        color.accumulateData('blue','blue',1)
        color.accumulateData('blue','blue',1)
        color.accumulateData('blue','blue',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','pink',1)
        color.accumulateData('pink','red',1)
        color.accumulateData('pink','red',1)
        color.accumulateData('blue','red',1)
        color.accumulateData('blue','red',1)
        color.accumulateData('red','blue',1)
        color.accumulateData('green','green',1)
        color.accumulateData('red','green',1)
        self.color = color

        # Simulate a face recognition problem with a
        # probe set of 1000 and a gallery set of 1000
        # 0.001 FAR and 0.100 FRR
        sim_face = Table(default_value=0)
        sim_face.setData('accept','accept',900)
        sim_face.setData('reject','reject',998001)
        sim_face.setData('accept','reject',100)
        sim_face.setData('reject','accept',999)
        self.sim_face = sim_face

    def test__str__(self):

        self.color.asPlainText()
        self.sim_face.asPlainText()

    def test_asLists(self):
        self.color.asLists()

    def test_save(self):
        expected = 'row,red,blue,pink,green\r\nred,3,1,0,1\r\nblue,2,4,0,0\r\npink,2,0,5,0\r\ngreen,0,0,0,1\r\n'
        output = StringIO.StringIO()
        self.color.save(output)
        self.assertEqual(output.getvalue(),expected)

        expected = '3,1,0,1\r\n2,4,0,0\r\n2,0,5,0\r\n0,0,0,1\r\n'
        output = StringIO.StringIO()
        self.color.save(output,headers=False)
        self.assertEqual(output.getvalue(),expected)

    def test_verification(self):
        self.sim_face

    def test_rowsort(self):
        tab = Table()

        tab[2,1] = 'b'
        tab[1,1] = 'a'
        tab[3,1] = 'c'

        #print tab
        tab.sortByRowHeader()
        #print tab

     <|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Tests for the contrib/localflavor/ ID form fields.

tests = r"""

# IDPhoneNumberField ########################################################

>>> from django.contrib.localflavor.id.forms import IDPhoneNumberField
>>> f = IDPhoneNumberField(required=False)
>>> f.clean('')
u''
>>> f.clean('0812-3456789')
u'0812-3456789'
>>> f.clean('081234567890')
u'081234567890'
>>> f.clean('021 345 6789')
u'021 345 6789'
>>> f.clean('0213456789')
u'0213456789'
>>> f.clean('0123456789')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('+62-21-3456789')
u'+62-21-3456789'
>>> f.clean('+62-021-3456789')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('(021) 345 6789')
u'(021) 345 6789'
>>> f.clean('+62-021-3456789')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('+62-0812-3456789')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('0812345678901')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('foo')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']

# IDPostCodeField ############################################################

>>> from django.contrib.localflavor.id.forms import IDPostCodeField
>>> f = IDPostCodeField(required=False)
>>> f.clean('')
u''
>>> f.clean('12340')
u'12340'
>>> f.clean('25412')
u'25412'
>>> f.clean(' 12340 ')
u'12340'
>>> f.clean('12 3 4 0')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']
>>> f.clean('12345')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']
>>> f.clean('10100')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']
>>> f.clean('123456')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']
>>> f.clean('foo')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']

# IDNationalIdentityNumberField #########################################################

>>> from django.contrib.localflavor.id.forms import IDNationalIdentityNumberField
>>> f = IDNationalIdentityNumberField(required=False)
>>> f.clean('')
u''
>>> f.clean(' 12.3456.010178 3456 ')
u'12.3456.010178.3456'
>>> f.clean('1234560101783456')
u'12.3456.010178.3456'
>>> f.clean('12.3456.010101.3456')
u'12.3456.010101.3456'
>>> f.clean('12.3456.310278.3456')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid NIK/KTP number']
>>> f.clean('00.0000.010101.0000')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid NIK/KTP number']
>>> f.clean('1234567890123456')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid NIK/KTP number']
>>> f.clean('foo')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid NIK/KTP number']

# IDProvinceSelect ##########################################################

>>> from django.contrib.localflavor.id.forms import IDProvinceSelect
>>> s = IDProvinceSelect()
>>> s.render('provinces', 'LPG')
u'<select name="provinces">\n<option value="ACE">Aceh</option>\n<option value="BLI">Bali</option>\n<option value="BTN">Banten</option>\n<option value="BKL">Bengkulu</option>\n<option value="DIY">Yogyakarta</option>\n<option value="JKT">Jakarta</option>\n<option value="GOR">Gorontalo</option>\n<option value="JMB">Jambi</option>\n<option value="JBR">Jawa Barat</option>\n<option value="JTG">Jawa Tengah</option>\n<option value="JTM">Jawa Timur</option>\n<option value="KBR">Kalimantan Barat</option>\n<option value="KSL">Kalimantan Selatan</option>\n<option value="KTG">Kalimantan Tengah</option>\n<option value="KTM">Kalimantan Timur</option>\n<option value="BBL">Kepulauan Bangka-Belitung</option>\n<option value="KRI">Kepulauan Riau</option>\n<option value="LPG" selected="selected">Lampung</option>\n<option value="MLK">Maluku</option>\n<option value="MUT">Maluku Utara</option>\n<option value="NTB">Nusa Tenggara Barat</option>\n<option value="NTT">Nusa Tenggara Timur</option>\n<option value="PPA">Papua</option>\n<option value="PPB">Papua Barat</option>\n<option value="RIU">Riau</option>\n<option value="SLB">Sulawesi Barat</option>\n<option value="SLS">Sulawesi Selatan</option>\n<option value="SLT">Sulawesi Tengah</option>\n<option value="SLR">Sulawesi Tenggara</option>\n<option value="SLU">Sulawesi Utara</option>\n<option value="SMB">Sumatera Barat</option>\n<option value="SMS">Sumatera Selatan</option>\n<option value="SMU">Sumatera Utara</option>\n</select>'

# IDLicensePlatePrefixelect ########################################################################

>>> from django.contrib.localflavor.id.forms import IDLicensePlatePrefixSelect
>>> s = IDLicensePlatePrefixSelect()
>>> s.render('codes', 'BE')
u'<select name="codes">\n<option value="A">Banten</option>\n<option value="AA">Magelang</option>\n<option value="AB">Yogyakarta</option>\n<option value="AD">Surakarta - Solo</option>\n<option value="AE">Madiun</option>\n<option value="AG">Kediri</option>\n<option value="B">Jakarta</option>\n<option value="BA">Sumatera Barat</option>\n<option value="BB">Tapanuli</option>\n<option value="BD">Bengkulu</option>\n<option value="BE" selected="selected">Lampung</option>\n<option value="BG">Sumatera Selatan</option>\n<option value="BH">Jambi</option>\n<option value="BK">Sumatera Utara</option>\n<option value="BL">Nanggroe Aceh Darussalam</option>\n<option value="BM">Riau</option>\n<option value="BN">Kepulauan Bangka Belitung</option>\n<option value="BP">Kepulauan Riau</option>\n<option value="CC">Corps Consulate</option>\n<option value="CD">Corps Diplomatic</option>\n<option value="D">Bandung</option>\n<option value="DA">Kalimantan Selatan</option>\n<option value="DB">Sulawesi Utara Daratan</option>\n<option value="DC">Sulawesi Barat</option>\n<option value="DD">Sulawesi Selatan</option>\n<option value="DE">Maluku</option>\n<option value="DG">Maluku Utara</option>\n<option value="DH">NTT - Timor</option>\n<option value="DK">Bali</option>\n<option value="DL">Sulawesi Utara Kepulauan</option>\n<option value="DM">Gorontalo</option>\n<option value="DN">Sulawesi Tengah</option>\n<option value="DR">NTB - Lombok</option>\n<option value="DS">Papua dan Papua Barat</option>\n<option value="DT">Sulawesi Tenggara</option>\n<option value="E">Cirebon</option>\n<option value="EA">NTB - Sumbawa</option>\n<option value="EB">NTT - Flores</option>\n<option value="ED">NTT - Sumba</option>\n<option value="F">Bogor</option>\n<option value="G">Pekalongan</option>\n<option value="H">Semarang</option>\n<option value="K">Pati</option>\n<option value="KB">Kalimantan Barat</option>\n<option value="KH">Kalimantan Tengah</option>\n<option value="KT">Kalimantan Timur</option>\n<option value="L">Surabaya</option>\n<option value="M">Madura</option>\n<option value="N">Malang</option>\n<option value="P">Jember</option>\n<option value="R">Banyumas</option>\n<option value="RI">Federal Government</option>\n<option value="S">Bojonegoro</option>\n<option value="T">Purwakarta</option>\n<option value="W">Sidoarjo</option>\n<option value="Z">Garut</option>\n</select>'

# IDLicensePlateField #######################################################################

>>> from django.contrib.localflavor.id.forms import IDLicensePlateField
>>> f = IDLicensePlateField(required=False)
>>> f.clean('')
u''
>>> f.clean(' b 1234  ab ')
u'B 1234 AB'
>>> f.clean('B 1234 ABC')
u'B 1234 ABC'
>>> f.clean('A 12')
u'A 12'
>>> f.clean('DK 12345 12')
u'DK 12345 12'
>>> f.clean('RI 10')
u'RI 10'
>>> f.clean('CD 12 12')
u'CD 12 12'
>>> f.clean('CD 10 12')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('CD 1234 12')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('RI 10 AB')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('B 12345 01')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('N 1234 12')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('A 12 XYZ')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('Q 1234 AB')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('foo')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
"""
<commit_msg>Added a filter to silence the RuntimeWarning in the Indonesian localflavor tests. Thanks to Alex for the report.<commit_after># -*- coding: utf-8 -*-
# Tests for the contrib/localflavor/ ID form fields.

tests = r"""

# IDPhoneNumberField ########################################################
>>> import warnings
>>> warnings.filterwarnings("ignore", category=RuntimeWarning, module='django.contrib.localflavor.id.id_choices')

>>> from django.contrib.localflavor.id.forms import IDPhoneNumberField
>>> f = IDPhoneNumberField(required=False)
>>> f.clean('')
u''
>>> f.clean('0812-3456789')
u'0812-3456789'
>>> f.clean('081234567890')
u'081234567890'
>>> f.clean('021 345 6789')
u'021 345 6789'
>>> f.clean('0213456789')
u'0213456789'
>>> f.clean('0123456789')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('+62-21-3456789')
u'+62-21-3456789'
>>> f.clean('+62-021-3456789')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('(021) 345 6789')
u'(021) 345 6789'
>>> f.clean('+62-021-3456789')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('+62-0812-3456789')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('0812345678901')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']
>>> f.clean('foo')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid phone number']

# IDPostCodeField ############################################################

>>> from django.contrib.localflavor.id.forms import IDPostCodeField
>>> f = IDPostCodeField(required=False)
>>> f.clean('')
u''
>>> f.clean('12340')
u'12340'
>>> f.clean('25412')
u'25412'
>>> f.clean(' 12340 ')
u'12340'
>>> f.clean('12 3 4 0')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']
>>> f.clean('12345')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']
>>> f.clean('10100')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']
>>> f.clean('123456')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']
>>> f.clean('foo')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid post code']

# IDNationalIdentityNumberField #########################################################

>>> from django.contrib.localflavor.id.forms import IDNationalIdentityNumberField
>>> f = IDNationalIdentityNumberField(required=False)
>>> f.clean('')
u''
>>> f.clean(' 12.3456.010178 3456 ')
u'12.3456.010178.3456'
>>> f.clean('1234560101783456')
u'12.3456.010178.3456'
>>> f.clean('12.3456.010101.3456')
u'12.3456.010101.3456'
>>> f.clean('12.3456.310278.3456')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid NIK/KTP number']
>>> f.clean('00.0000.010101.0000')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid NIK/KTP number']
>>> f.clean('1234567890123456')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid NIK/KTP number']
>>> f.clean('foo')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid NIK/KTP number']

# IDProvinceSelect ##########################################################

>>> from django.contrib.localflavor.id.forms import IDProvinceSelect
>>> s = IDProvinceSelect()
>>> s.render('provinces', 'LPG')
u'<select name="provinces">\n<option value="ACE">Aceh</option>\n<option value="BLI">Bali</option>\n<option value="BTN">Banten</option>\n<option value="BKL">Bengkulu</option>\n<option value="DIY">Yogyakarta</option>\n<option value="JKT">Jakarta</option>\n<option value="GOR">Gorontalo</option>\n<option value="JMB">Jambi</option>\n<option value="JBR">Jawa Barat</option>\n<option value="JTG">Jawa Tengah</option>\n<option value="JTM">Jawa Timur</option>\n<option value="KBR">Kalimantan Barat</option>\n<option value="KSL">Kalimantan Selatan</option>\n<option value="KTG">Kalimantan Tengah</option>\n<option value="KTM">Kalimantan Timur</option>\n<option value="BBL">Kepulauan Bangka-Belitung</option>\n<option value="KRI">Kepulauan Riau</option>\n<option value="LPG" selected="selected">Lampung</option>\n<option value="MLK">Maluku</option>\n<option value="MUT">Maluku Utara</option>\n<option value="NTB">Nusa Tenggara Barat</option>\n<option value="NTT">Nusa Tenggara Timur</option>\n<option value="PPA">Papua</option>\n<option value="PPB">Papua Barat</option>\n<option value="RIU">Riau</option>\n<option value="SLB">Sulawesi Barat</option>\n<option value="SLS">Sulawesi Selatan</option>\n<option value="SLT">Sulawesi Tengah</option>\n<option value="SLR">Sulawesi Tenggara</option>\n<option value="SLU">Sulawesi Utara</option>\n<option value="SMB">Sumatera Barat</option>\n<option value="SMS">Sumatera Selatan</option>\n<option value="SMU">Sumatera Utara</option>\n</select>'

# IDLicensePlatePrefixelect ########################################################################

>>> from django.contrib.localflavor.id.forms import IDLicensePlatePrefixSelect
>>> s = IDLicensePlatePrefixSelect()
>>> s.render('codes', 'BE')
u'<select name="codes">\n<option value="A">Banten</option>\n<option value="AA">Magelang</option>\n<option value="AB">Yogyakarta</option>\n<option value="AD">Surakarta - Solo</option>\n<option value="AE">Madiun</option>\n<option value="AG">Kediri</option>\n<option value="B">Jakarta</option>\n<option value="BA">Sumatera Barat</option>\n<option value="BB">Tapanuli</option>\n<option value="BD">Bengkulu</option>\n<option value="BE" selected="selected">Lampung</option>\n<option value="BG">Sumatera Selatan</option>\n<option value="BH">Jambi</option>\n<option value="BK">Sumatera Utara</option>\n<option value="BL">Nanggroe Aceh Darussalam</option>\n<option value="BM">Riau</option>\n<option value="BN">Kepulauan Bangka Belitung</option>\n<option value="BP">Kepulauan Riau</option>\n<option value="CC">Corps Consulate</option>\n<option value="CD">Corps Diplomatic</option>\n<option value="D">Bandung</option>\n<option value="DA">Kalimantan Selatan</option>\n<option value="DB">Sulawesi Utara Daratan</option>\n<option value="DC">Sulawesi Barat</option>\n<option value="DD">Sulawesi Selatan</option>\n<option value="DE">Maluku</option>\n<option value="DG">Maluku Utara</option>\n<option value="DH">NTT - Timor</option>\n<option value="DK">Bali</option>\n<option value="DL">Sulawesi Utara Kepulauan</option>\n<option value="DM">Gorontalo</option>\n<option value="DN">Sulawesi Tengah</option>\n<option value="DR">NTB - Lombok</option>\n<option value="DS">Papua dan Papua Barat</option>\n<option value="DT">Sulawesi Tenggara</option>\n<option value="E">Cirebon</option>\n<option value="EA">NTB - Sumbawa</option>\n<option value="EB">NTT - Flores</option>\n<option value="ED">NTT - Sumba</option>\n<option value="F">Bogor</option>\n<option value="G">Pekalongan</option>\n<option value="H">Semarang</option>\n<option value="K">Pati</option>\n<option value="KB">Kalimantan Barat</option>\n<option value="KH">Kalimantan Tengah</option>\n<option value="KT">Kalimantan Timur</option>\n<option value="L">Surabaya</option>\n<option value="M">Madura</option>\n<option value="N">Malang</option>\n<option value="P">Jember</option>\n<option value="R">Banyumas</option>\n<option value="RI">Federal Government</option>\n<option value="S">Bojonegoro</option>\n<option value="T">Purwakarta</option>\n<option value="W">Sidoarjo</option>\n<option value="Z">Garut</option>\n</select>'

# IDLicensePlateField #######################################################################

>>> from django.contrib.localflavor.id.forms import IDLicensePlateField
>>> f = IDLicensePlateField(required=False)
>>> f.clean('')
u''
>>> f.clean(' b 1234  ab ')
u'B 1234 AB'
>>> f.clean('B 1234 ABC')
u'B 1234 ABC'
>>> f.clean('A 12')
u'A 12'
>>> f.clean('DK 12345 12')
u'DK 12345 12'
>>> f.clean('RI 10')
u'RI 10'
>>> f.clean('CD 12 12')
u'CD 12 12'
>>> f.clean('CD 10 12')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('CD 1234 12')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('RI 10 AB')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('B 12345 01')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('N 1234 12')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('A 12 XYZ')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('Q 1234 AB')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
>>> f.clean('foo')
Traceback (most recent call last):
    ...
ValidationError: [u'Enter a valid vehicle license plate number']
"""
<|endoftext|>


<commit_before>#!/usr/bin/python
import requests
import json
import csv
import sys

def parse_dataset_metadata(dataset):
    if 'rights' in dataset.keys():
        rights = dataset['rights'].encode('utf-8').strip()
        rights = rights.replace("\n", "")
    else:
        rights = ''
    return [dataset['key'].encode('utf-8'), dataset['owningOrganizationKey'].encode('utf-8'), rights]

def get_gbif_datasets(limit, offset):
    params = {'limit': limit, 'offset': offset}
    r = requests.get('http://api.gbif.org/v1/dataset/', params=params)
    request_result = r.json()['results']
    return request_result

def getOccurrences(key):
    params = {'datasetKey':  key}
    r = requests.get('http://api.gbif.org/v1/occurrence/count', params=params)
    try:
        count = r.json()
    except:
        sys.stderr.write('could not parse json for number of occurrences for key {0}\n'.format(key))
        sys.exit(-1)
    return count

all_datasets = []
more_results_to_find = True
offset = 0
limit = 20
print 'key,owningOrganizationKey,numberOfOccurrences,rights'
csvwriter = csv.writer(sys.stdout, lineterminator='\n')

while more_results_to_find:
    #sys.stderr.write('LOG: calling GBIF')
    datasets = get_gbif_datasets(limit, offset)
    all_datasets += datasets
    offset += 20
    if len(datasets) == 0:
        more_results_to_find = False

for dataset in all_datasets:
    dataset_list = parse_dataset_metadata(dataset)
    key = dataset_list[0]
    count = getOccurrences(key)
    dataset_list.insert(2, count)
    csvwriter.writerow(dataset_list)
<commit_msg>Change owningOrganizationKey to publishingOrganizationKey<commit_after>#!/usr/bin/python
import requests
import json
import csv
import sys

def parse_dataset_metadata(dataset):
    if 'rights' in dataset.keys():
        rights = dataset['rights'].encode('utf-8').strip()
        rights = rights.replace("\n", "")
    else:
        rights = ''
    return [dataset['key'].encode('utf-8'), dataset['publishingOrganizationKey'].encode('utf-8'), rights]

def get_gbif_datasets(limit, offset):
    params = {'limit': limit, 'offset': offset}
    r = requests.get('http://api.gbif.org/v1/dataset/', params=params)
    request_result = r.json()['results']
    return request_result

def getOccurrences(key):
    params = {'datasetKey':  key}
    r = requests.get('http://api.gbif.org/v1/occurrence/count', params=params)
    try:
        count = r.json()
    except:
        sys.stderr.write('could not parse json for number of occurrences for key {0}\n'.format(key))
        sys.exit(-1)
    return count

all_datasets = []
more_results_to_find = True
offset = 0
limit = 20
print 'key,publishingOrganizationKey,numberOfOccurrences,rights'
csvwriter = csv.writer(sys.stdout, lineterminator='\n')

while more_results_to_find:
    #sys.stderr.write('LOG: calling GBIF')
    datasets = get_gbif_datasets(limit, offset)
    all_datasets += datasets
    offset += 20
    if len(datasets) == 0:
        more_results_to_find = False

for dataset in all_datasets:
    dataset_list = parse_dataset_metadata(dataset)
    key = dataset_list[0]
    count = getOccurrences(key)
    dataset_list.insert(2, count)
    csvwriter.writerow(dataset_list)
<|endoftext|>


<commit_before># stdlib
import re
import subprocess

def test_create_overlay_networks_docker() -> None:
    # this connects all the tailscale containers to the other docker compose project
    # networks thus allowing tailscale to find a direct route between them
    containers = [
        "test_network_1-tailscale-1",
        "test_domain_1-tailscale-1",
        "test_domain_2-tailscale-1",
    ]
    networks = [
        "test_network_1_default",
        "test_domain_1_default",
        "test_domain_2_default",
    ]
    for container in containers:
        for network in networks:
            try:
                cmd = f"docker network connect {network} {container}"
                print(f"Connecting {container} to {network}")
                subprocess.call(cmd, shell=True)
            except Exception as e:
                print(f"Exception running: {cmd}. {e}")

def test_vpn_scan() -> None:
    # we need to scan two containers so that the first container itself gets scanned
    # externally by another container to make sure all of the containers on the VPN
    # are externally scanned and their firewall rules verified
    containers = [
        "test_network_1-tailscale-1",
        "test_domain_1-tailscale-1",
    ]

    allowed_ports = [80]
    blocked_ports = [21, 4000, 8001, 8011, 8080, 5050, 5432, 5555, 5672, 15672]

    # run in two containers so that all IPs are scanned externally
    for container in containers:
        try:
            cmd = f"cat scripts/vpn_scan.sh | docker exec -i {container} ash"
            print(f"Scanning {container}")
            output = subprocess.check_output(cmd, shell=True)
            output = output.decode("utf-8")
        except Exception as e:
            print(f"Exception running: {cmd}. {e}")

        for port in allowed_ports:
            matcher = re.compile(f" {port} port .+succeeded")
            lines = re.findall(matcher, output)
            assert len(lines) > 0

        for port in blocked_ports:
            matcher = re.compile(f" {port} port .+succeeded")
            lines = re.findall(matcher, output)
            assert len(lines) == 0
<commit_msg>Add tear down to of network connections to scan_network tests<commit_after># stdlib
import subprocess

def docker_network_connect(cmd: str = "connect") -> None:
    # this connects all the tailscale containers to the other docker compose project
    # networks thus allowing tailscale to find a direct route between them
    projects = [
        "network_1",
        "domain_1",
        "domain_2",
    ]
    for project in projects:
        for network in projects:
            try:
                if project == network:
                    continue
                container_name = f"test_{project}-tailscale-1"
                network_name = f"test_{network}_default"
                cmd = f"docker network {cmd} {network_name} {container_name}"
                print(f"Connecting {container_name} to {network_name}")
                subprocess.call(cmd, shell=True)
            except Exception as e:
                print(f"Exception running: {cmd}. {e}")

# def test_create_overlay_networks_docker() -> None:
#     docker_network_connect(cmd="connect")

# def test_vpn_scan() -> None:
#     # we need to scan two containers so that the first container itself gets scanned
#     # externally by another container to make sure all of the containers on the VPN
#     # are externally scanned and their firewall rules verified
#     containers = [
#         "test_network_1-tailscale-1",
#         "test_domain_1-tailscale-1",
#     ]

#     allowed_ports = [80]
#     blocked_ports = [21, 4000, 8001, 8011, 8080, 5050, 5432, 5555, 5672, 15672]

#     # run in two containers so that all IPs are scanned externally
#     for container in containers:
#         try:
#             cmd = f"cat scripts/vpn_scan.sh | docker exec -i {container} ash"
#             print(f"Scanning {container}")
#             output = subprocess.check_output(cmd, shell=True)
#             output = output.decode("utf-8")
#         except Exception as e:
#             print(f"Exception running: {cmd}. {e}")

#         for port in allowed_ports:
#             matcher = re.compile(f" {port} port .+succeeded")
#             lines = re.findall(matcher, output)
#             assert len(lines) > 0

#         for port in blocked_ports:
#             matcher = re.compile(f" {port} port .+succeeded")
#             lines = re.findall(matcher, output)
#             assert len(lines) == 0

def test_remove_overlay_networks_docker() -> None:
    docker_network_connect(cmd="disconnect")
<|endoftext|>


<commit_before>from cdn.storage.cassandra.services import ServicesController
from mock import patch, Mock
import cassandra

from unittest import TestCase

class CassandraStorageTests(TestCase):

    @patch.object(ServicesController, 'session')
    @patch.object(cassandra.cluster.Session, 'execute')
    def test_get_service(self, mock_session, mock_execute):
        project_id = 123456
        service_name = 'mock_service'

        sc = ServicesController(None)
        sc.get(project_id, service_name)

        mock_execute.execute.assert_called_with(args={project_id})

        pass
<commit_msg>added basic unit test for get<commit_after>import cassandra
import json
from cdn.storage.cassandra.services import ServicesController
from mock import patch
from unittest import TestCase

class CassandraStorageTests(TestCase):

    @patch.object(ServicesController, 'session')
    @patch.object(cassandra.cluster.Session, 'execute')
    def test_get_service(self, mock_session, mock_execute):
        project_id = 123456
        service_name = 'mock_service'

        cassandra_response = []
        cassandra_response.append(project_id)
        cassandra_response.append(service_name)

        domains = ["{domain: 'www.mocksite.com'}"]
        origins = ["{origin: 'www.mocksite.com'}"]
        caching_rules = ["{name: 'www.mocksite.com'}"]
        restrictions = ["{rules: 'www.mocksite.com'}"]

        cassandra_response.append(domains)
        cassandra_response.append(origins)
        cassandra_response.append(caching_rules)
        cassandra_response.append(restrictions)

        # mock the response from cassandra
        mock_execute.execute.return_value = json.dumps([cassandra_response])

        sc = ServicesController(None)
        actual_response = json.loads(sc.get(project_id, service_name))

        self.assertEqual(actual_response[0][0], project_id)
        self.assertEqual(actual_response[0][1], service_name)
<|endoftext|>


<commit_before>from __future__ import print_function, unicode_literals

import re
import itertools
from HTMLParser import HTMLParser

from coherence import log
from coherence.upnp.core import DIDLLite
from coherence.upnp.core.utils import ReverseProxyUriResource
from coherence.upnp.core.DIDLLite import (
    Resource,
)
from coherence.backend import (
    BackendItem, Container, AbstractBackendStore,
)

import api
import settings

_htmlparser = HTMLParser()

class MoeFmProxyStream(ReverseProxyUriResource, log.Loggable):
    logCategory = 'moefm_stream'

    def __init__(self, uri, parent):
        self.parent = parent
        ReverseProxyUriResource.__init__(self, uri.encode("utf-8"))

    def log_playing(self):
        if self.parent.store.last_played_item is self:
            obj_id = self.parent.sub_id
            d = api.moefm.get(
                "/ajax/log?log_obj_type=sub&log_type=listen&obj_type=song&api=json", # noqa
                {"obj_id": obj_id}
            )
            d.addCallback(lambda res: self.debug(
                "Logged %s: %r", obj_id, res,
            ))
            d.addErrback(lambda res: self.warning(
                "Unable to log %s: %r", obj_id, res,
            ))

    def render(self, request):
        self.debug("render %r", self.parent.item_data)
        self.parent.container.on_item_play(self.parent)
        self.parent.store.last_played_item = self
        reactor.callLater(self.parent.duration_seconds / 2, self.log_playing)
        return ReverseProxyUriResource.render(self, request)

class MoeFmTrack(BackendItem):
    logCategory = "moefm"
    next_sn = 0

    def __init__(self, item_data, container):
        BackendItem.__init__(self)
        self.item_data = item_data
        self.container = container
        self.sub_id = item_data["sub_id"]
        self.storage_id = "track-%s$%s" % (self.sub_id, container.get_id())
        self.__class__.next_sn += 1
        self.sort_key = self.__class__.next_sn

        track_number = None
        m = re.match(
            r"^song\.(\d+)\s+.*$",
            _htmlparser.unescape(item_data["title"]),
            re.I,
        )
        if m:
            track_number, = m.groups()

        title = _htmlparser.unescape(item_data["sub_title"])
        self.name = title
        self.title = title
        self.originalTrackNumber = track_number
        self.artist = _htmlparser.unescape(item_data["artist"])
        self.album = _htmlparser.unescape(item_data["wiki_title"])
        self.cover = item_data["cover"]["large"]
        self.duration = item_data["stream_time"]
        self.duration_seconds = int(item_data["stream_length"])
        if not re.match(r"^\d{2}:\d{2}:\d{2}(?:\.\d+)?", self.duration):
            self.duration = "0:" + self.duration  # Add hour part

        self.mimetype = "audio/mpeg"

        self.item = None

    def get_id(self):
        return self.storage_id

    def get_item(self):
        if self.item is None:
            upnp_id = self.get_id()
            upnp_parent_id = self.parent.get_id()
            self.debug("get_item %s %s %s", upnp_id, upnp_parent_id, self.name)
            item = DIDLLite.MusicTrack(upnp_id, upnp_parent_id, self.name)
            item.restricted = True
            item.name = self.name
            item.originalTrackNumber = self.originalTrackNumber
            item.title = self.title
            item.artist = self.artist
            item.album = self.album
            item.albumArtURI = self.cover
            item.duration = self.duration

            proxied_url = "%s%s" % (self.store.urlbase, self.get_id())
            proxied_url = proxied_url.encode("utf-8")
            self.url = proxied_url
            self.location = MoeFmProxyStream(self.item_data["url"], self)

            protocol = "http-get"

            res = Resource(
                proxied_url,
                ("%s:*:%s:*" % (protocol, self.mimetype)).encode("utf-8")
            )
            res.size = self.item_data["file_size"] * 1024
            res.duration = self.duration
            item.res.append(res)

            self.item = item

        return self.item

    def get_url(self):
        return self.url

class MoeFmTrackContainer(Container):
    logCategory = "moefm_track_container"
    ContainerClass = DIDLLite.PlaylistContainer

    def __init__(self, store, parent, title, api_params=None):
        super(MoeFmTrackContainer, self).__init__(parent, title)
        self.sorting_method = lambda x, y: cmp(x.sort_key, y.sort_key)
        self.store = store
        self.api_params = api_params if api_params is not None else {}
        self.loaded = False

    def get_item(self):
        if not self.loaded:
            return self.load_tracks().addCallback(lambda _: self.get_item())

        if self.item is None:
            self.item = self.ContainerClass(
                self.storage_id, self.parent_id, self.name
            )

        self.item.childCount = self.get_child_count()
        return self.item

    def get_children(self, *args, **kwargs):
        if not self.loaded:
            return self.load_tracks().addCallback(
                lambda _: self.get_children(*args, **kwargs)
            )

        return super(MoeFmTrackContainer, self).get_children(*args, **kwargs)

    def get_api_params(self):
        return self.api_params

    def on_got_response(self, resp_container):
        self.info("Got response")
        resp = resp_container["response"]
        self.debug("Information: %r", resp["information"])
        if resp["information"]["has_error"]:
            self.error("Got error response: %s" % resp)
            return

        items = []
        for item_data in resp["playlist"]:
            item = MoeFmTrack(item_data, self)
            items.append(item)
            self.add_child(item)

        self.on_update_completed()
        self.loaded = True
        return items

    def on_got_error(self, error):
        self.warning("Unable to retrieve tracks: %s", error)
        return error

    def load_tracks(self):
        params = {"perpage": settings.get("tracks_per_request", 30)}
        params.update(self.get_api_params())
        d = api.moefm.get("/listen/playlist?api=json", params)
        return d.addCallbacks(self.on_got_response, self.on_got_error)

    def on_update_completed(self):
        self.update_id += 1
        self.store.on_update_completed(self)

    def on_item_play(self, item):
        pass

class MoeFmRandomPlaylist(MoeFmTrackContainer):
    storage_id = "magic"

    def __init__(self, store, parent):
        super(MoeFmRandomPlaylist, self).__init__(store, parent, "Magic")

    def remove_child(self, child, external_id=None, update=True):
        try:
            self.children.remove(child)
            # We'd like the item to be accessible even after removing it
            # self.store.remove_item(child)
        except ValueError:
            pass
        else:
            if update:
                self.update_id += 1

    @property
    def need_more_tracks(self):
        current_count = self.get_child_count()
        return current_count < settings.get("min_tracks_in_playlist", 120)

    @property
    def loaded(self):
        return not self.need_more_tracks

    loaded = loaded.setter(lambda self, value: None)

    def load_tracks(self):
        def on_completed(items):
            if self.need_more_tracks:
                return self.load_tracks().addCallback(
                    lambda x: itertools.chain(x, items)
                )
            else:
                return items

        d = super(MoeFmRandomPlaylist, self).load_tracks()
        return d.addCallback(on_completed)

    def on_item_play(self, item):
        self.remove_child(item)

class MoeFmPlaylistStore(AbstractBackendStore):
    logCategory = "moefm"
    name = "Moe FM"
    implements = ["MediaServer"]
    wmc_mapping = {"16": 1000}

    def __init__(self, server, **kwargs):
        AbstractBackendStore.__init__(self, server, **kwargs)

        self.init_completed()

    def __repr__(self):
        return self.__class__.__name__

    def append_item(self, item, storage_id=None):
        if storage_id is None:
            storage_id = item.get_id()

        if storage_id is None:
            storage_id = self.getnextID()

        storage_id = str(storage_id)
        return super(MoeFmPlaylistStore, self).append_item(item, storage_id)

    def get_by_id(self, id):
        self.info("get_by_id: %r", id)
        if isinstance(id, basestring):
            id = id.split("@", 1)
            id = id[0].split(".")[0]

        return self.store.get(str(id))

    def upnp_init(self):
        self.current_connection_id = None
        self.server.connection_manager_server.set_variable(
            0,
            "SourceProtocolInfo",
            ["http-get:*:audio/mpeg:*"],
            default=True,
        )

        root_item = Container(None, "Moe FM")
        self.root_item = root_item
        self.set_root_item(root_item)
        root_item.add_child(MoeFmRandomPlaylist(self, root_item))

        dummy = Container(root_item, "Dummy")
        root_item.add_child(dummy)

    def on_update_completed(self, container):
        self.update_id += 1
        try:
            self.server.content_directory_server.set_variable(
                0, "SystemUpdateID", self.update_id,
            )
            value = (container.get_id(), container.get_update_id())
            self.info("on_update_completed %s %s", self.update_id, value)
            self.server.content_directory_server.set_variable(
                0, "ContainerUpdateIDs", value,
            )
        except Exception as e:
            self.warning("%r", e)

if __name__ == '__main__':
    from twisted.internet import reactor

    def main():
        from coherence.base import Coherence, Plugins
        Plugins().set("MoeFmPlaylistStore", MoeFmPlaylistStore)
        conf = dict(settings.get("coherence_config", {}))
        conf.update({
            "plugin": [{"backend": "MoeFmPlaylistStore"}]
        })
        Coherence(conf)

    reactor.callWhenRunning(main)
    reactor.run()
<commit_msg>Refactor part 2<commit_after>from __future__ import print_function, unicode_literals

import re
import itertools
from HTMLParser import HTMLParser

from coherence import log
from coherence.upnp.core import DIDLLite
from coherence.upnp.core.utils import ReverseProxyUriResource
from coherence.upnp.core.DIDLLite import (
    Resource,
)
from coherence.backend import (
    BackendItem, Container, AbstractBackendStore,
)

import api
import settings

_htmlparser = HTMLParser()

class MoeFmProxyStream(ReverseProxyUriResource, log.Loggable):
    logCategory = 'moefm_stream'

    def __init__(self, uri, parent):
        self.parent = parent
        ReverseProxyUriResource.__init__(self, uri.encode("utf-8"))

    def log_playing(self):
        if self.parent.store.last_played_item is self:
            obj_id = self.parent.sub_id
            d = api.moefm.get(
                "/ajax/log?log_obj_type=sub&log_type=listen&obj_type=song&api=json", # noqa
                {"obj_id": obj_id}
            )
            d.addCallback(lambda res: self.debug(
                "Logged %s: %r", obj_id, res,
            ))
            d.addErrback(lambda res: self.warning(
                "Unable to log %s: %r", obj_id, res,
            ))

    def render(self, request):
        self.debug("render %r", self.parent.item_data)
        self.parent.container.on_item_play(self.parent)
        self.parent.store.last_played_item = self
        reactor.callLater(self.parent.duration_seconds / 2, self.log_playing)
        return ReverseProxyUriResource.render(self, request)

class MoeFmTrack(BackendItem):
    logCategory = "moefm"
    next_sn = 0

    def __init__(self, item_data, container):
        BackendItem.__init__(self)
        self.item_data = item_data
        self.container = container
        self.sub_id = item_data["sub_id"]
        self.storage_id = "track-%s$%s" % (self.sub_id, container.get_id())
        self.__class__.next_sn += 1
        self.sort_key = self.__class__.next_sn

        track_number = None
        m = re.match(
            r"^song\.(\d+)\s+.*$",
            _htmlparser.unescape(item_data["title"]),
            re.I,
        )
        if m:
            track_number, = m.groups()

        title = _htmlparser.unescape(item_data["sub_title"])
        self.name = title
        self.title = title
        self.originalTrackNumber = track_number
        self.artist = _htmlparser.unescape(item_data["artist"])
        self.album = _htmlparser.unescape(item_data["wiki_title"])
        self.cover = item_data["cover"]["large"]
        self.duration = item_data["stream_time"]
        self.duration_seconds = int(item_data["stream_length"])
        if not re.match(r"^\d{2}:\d{2}:\d{2}(?:\.\d+)?", self.duration):
            self.duration = "0:" + self.duration  # Add hour part

        self.mimetype = "audio/mpeg"

        self.item = None

    def get_id(self):
        return self.storage_id

    def get_item(self):
        if self.item is None:
            upnp_id = self.get_id()
            upnp_parent_id = self.parent.get_id()
            self.debug("get_item %s %s %s", upnp_id, upnp_parent_id, self.name)
            item = DIDLLite.MusicTrack(upnp_id, upnp_parent_id, self.name)
            item.restricted = True
            item.name = self.name
            item.originalTrackNumber = self.originalTrackNumber
            item.title = self.title
            item.artist = self.artist
            item.album = self.album
            item.albumArtURI = self.cover
            item.duration = self.duration

            proxied_url = "%s%s" % (self.store.urlbase, self.get_id())
            proxied_url = proxied_url.encode("utf-8")
            self.url = proxied_url
            self.location = MoeFmProxyStream(self.item_data["url"], self)

            protocol = "http-get"

            res = Resource(
                proxied_url,
                ("%s:*:%s:*" % (protocol, self.mimetype)).encode("utf-8")
            )
            res.size = self.item_data["file_size"] * 1024
            res.duration = self.duration
            item.res.append(res)

            self.item = item

        return self.item

    def get_url(self):
        return self.url

class MoeFmTrackContainer(Container):
    logCategory = "moefm_track_container"
    ContainerClass = DIDLLite.PlaylistContainer
    preferred_id = None

    def __init__(self, store, parent, title, api_params=None):
        super(MoeFmTrackContainer, self).__init__(parent, title)
        self.sorting_method = lambda x, y: cmp(x.sort_key, y.sort_key)
        self.store = store
        self.api_params = api_params if api_params is not None else {}
        self.loaded = False
        if self.preferred_id:
            self.storage_id = self.preferred_id
            if store.get_by_id(self.storage_id):
                self.storage_id += "$" + parent.get_id()

    def get_item(self):
        if not self.loaded:
            return self.load_tracks().addCallback(lambda _: self.get_item())

        if self.item is None:
            self.item = self.ContainerClass(
                self.storage_id, self.parent_id, self.name
            )

        self.item.childCount = self.get_child_count()
        return self.item

    def get_children(self, *args, **kwargs):
        if not self.loaded:
            return self.load_tracks().addCallback(
                lambda _: self.get_children(*args, **kwargs)
            )

        return super(MoeFmTrackContainer, self).get_children(*args, **kwargs)

    def get_api_params(self):
        return self.api_params

    def on_got_response(self, resp_container):
        self.info("Got response")
        resp = resp_container["response"]
        self.debug("Information: %r", resp["information"])
        if resp["information"]["has_error"]:
            self.error("Got error response: %s" % resp)
            return

        items = []
        for item_data in resp["playlist"]:
            item = MoeFmTrack(item_data, self)
            items.append(item)
            self.add_child(item)

        self.on_update_completed()
        self.loaded = True
        return items

    def on_got_error(self, error):
        self.warning("Unable to retrieve tracks: %s", error)
        return error

    def load_tracks(self):
        params = {"perpage": settings.get("tracks_per_request", 30)}
        params.update(self.get_api_params())
        d = api.moefm.get("/listen/playlist?api=json", params)
        return d.addCallbacks(self.on_got_response, self.on_got_error)

    def on_update_completed(self):
        self.update_id += 1
        self.store.on_update_completed(self)

    def on_item_play(self, item):
        pass

class MoeFmMultiPageTrackContainer(MoeFmTrackContainer):
    def __init__(self, *args, **kwargs):
        super(MoeFmMultiPageTrackContainer, self).__init__(*args, **kwargs)
        self.current_page = 1

    @property
    def should_load_next_page(self):
        return True

    def load_tracks(self):
        def on_completed(items):
            if items:
                self.current_page += 1

            if items and self.should_load_next_page:
                return self.load_tracks().addCallback(
                    lambda x: itertools.chain(x, items)
                )
            else:
                return items

        d = super(MoeFmMultiPageTrackContainer, self).load_tracks()
        return d.addCallback(on_completed)

    def get_api_params(self):
        params = super(MoeFmMultiPageTrackContainer, self).get_api_params()
        params["page"] = self.current_page
        return params

class MoeFmRandomPlaylist(MoeFmMultiPageTrackContainer):
    preferred_id = "magic"

    def __init__(self, store, parent):
        super(MoeFmRandomPlaylist, self).__init__(store, parent, "Magic")

    def remove_child(self, child, external_id=None, update=True):
        try:
            self.children.remove(child)
            # We'd like the item to be accessible even after removing it
            # self.store.remove_item(child)
        except ValueError:
            pass
        else:
            if update:
                self.update_id += 1

    @property
    def need_more_tracks(self):
        current_count = self.get_child_count()
        return current_count < settings.get("min_tracks_in_playlist", 120)

    @property
    def should_load_next_page(self):
        return self.need_more_tracks

    @property
    def loaded(self):
        return not self.need_more_tracks

    loaded = loaded.setter(lambda self, value: None)

    def on_item_play(self, item):
        self.remove_child(item)
        self.on_update_completed()

class MoeFmPlaylistStore(AbstractBackendStore):
    logCategory = "moefm"
    name = "Moe FM"
    implements = ["MediaServer"]
    wmc_mapping = {"16": 1000}

    def __init__(self, server, **kwargs):
        AbstractBackendStore.__init__(self, server, **kwargs)

        self.init_completed()

    def __repr__(self):
        return self.__class__.__name__

    def append_item(self, item, storage_id=None):
        if storage_id is None:
            storage_id = item.get_id()

        if storage_id is None:
            storage_id = self.getnextID()

        storage_id = str(storage_id)
        return super(MoeFmPlaylistStore, self).append_item(item, storage_id)

    def get_by_id(self, id):
        self.info("get_by_id: %r", id)
        if isinstance(id, basestring):
            id = id.split("@", 1)
            id = id[0].split(".")[0]

        return self.store.get(str(id))

    def upnp_init(self):
        self.current_connection_id = None
        self.server.connection_manager_server.set_variable(
            0,
            "SourceProtocolInfo",
            ["http-get:*:audio/mpeg:*"],
            default=True,
        )

        root_item = Container(None, "Moe FM")
        self.root_item = root_item
        self.set_root_item(root_item)
        root_item.add_child(MoeFmRandomPlaylist(self, root_item))

        dummy = Container(root_item, "Dummy")
        root_item.add_child(dummy)

    def on_update_completed(self, container):
        self.update_id += 1
        try:
            self.server.content_directory_server.set_variable(
                0, "SystemUpdateID", self.update_id,
            )
            value = (container.get_id(), container.get_update_id())
            self.info("on_update_completed %s %s", self.update_id, value)
            self.server.content_directory_server.set_variable(
                0, "ContainerUpdateIDs", value,
            )
        except Exception as e:
            self.warning("%r", e)

if __name__ == '__main__':
    from twisted.internet import reactor

    def main():
        from coherence.base import Coherence, Plugins
        Plugins().set("MoeFmPlaylistStore", MoeFmPlaylistStore)
        conf = dict(settings.get("coherence_config", {}))
        conf.update({
            "plugin": [{"backend": "MoeFmPlaylistStore"}]
        })
        Coherence(conf)

    reactor.callWhenRunning(main)
    reactor.run()
<|endoftext|>