from __future__ import print_function
import collections
import random
import numpy as np
import tensorflow as tf
from tensorflow.contrib import rnn

n_input = 3
n_hidden = 512
e = .001
steps = 100000

logs_path = '/tmp/tensorflow/rnn_words'
writer = tf.summary.FileWriter(logs_path)

def build_dataset(words):
    count = collections.Counter(words).most_common()
    word_to_index = dict()
    for word, _ in count:
        word_to_index[word] = len(word_to_index)
    index_to_word = dict(zip(word_to_index.values(), word_to_index.keys()))
    return word_to_index, index_to_word

def lstm(x, weights, biases, n_input, n_hidden):
    x = tf.reshape(x, [1, n_input])
    x = tf.split(x, n_input, 1)
    rnn_cell = rnn.BasicLSTMCell(n_hidden)
    output, states =  rnn.static_rnn(rnn_cell, x, dtype='float32')
    return tf.matmul(output[-1], weights) + biases

def weight_variable(h, v):
    initial = tf.random_normal([h, v])
    return tf.Variable(initial)

def bias_variable(v):
    initial = tf.random_normal([v])
    return tf.Variable(initial)

data = []
f = open("aesop1.txt")
data = f.read().split()

wti, itw = build_dataset(data)
vocab_size = len(wti)

x = tf.placeholder(tf.float32, shape=[None, n_input, 1])
y = tf.placeholder(tf.float32, shape=[None, vocab_size])

weights = weight_variable(n_hidden, vocab_size)
biases = bias_variable(vocab_size)

out = lstm(x, weights, biases, n_input, n_hidden)

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=out, labels=y))
train_step = tf.train.RMSPropOptimizer(learning_rate=e).minimize(cost)
correct_prediction = tf.equal(tf.argmax(out,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(wti)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    step = 0
    offset = random.randint(0, n_input+1)
    end_offset = n_input + 1
    acc_total = 0
    loss_total = 0

    writer.add_graph(sess.graph)
    while step < steps:
        # gen mini batch with randomness
        if offset > (len(data)-end_offset):
            offset = random.randint(0, n_input+1)

        #indices of train points
        train_indices = [[wti[str(data[i])]] for i in range(offset, offset + n_input)]
        train_indices = np.reshape(np.array(train_indices), [-1, n_input, 1])

        #one hot of actual label
        out_onehot = np.zeros([vocab_size], dtype='float32')
        out_onehot[wti[str(data[offset+n_input])]] = 1.0
        out_onehot = np.reshape(out_onehot, [1,-1])

        _, acc, loss, prediction = sess.run([train_step, accuracy, cost, out],
                                            feed_dict={x: train_indices, y: out_onehot})
        loss_total += loss
        acc_total += acc
        if step % 1000 == 0:
            print(step)
            print("Loss: ", loss_total/step)
            print("Accuracy: ", acc_total*100/step, "%")
        step += 1
        offset += n_input + 1

    while True:
        prompt = "%s words: " % n_input
        sentence = input(prompt)
        words = sentence.strip().split(' ')

        if len(words) != n_input:
            continue
        try:
            train_indices = [wti[str(words[i])] for i in range(len(words))]
            for i in range(32):
                keys = np.reshape(np.array(train_indices), [-1, n_input, 1])
                onehot_pred = sess.run(out, feed_dict={x: keys})
                onehot_pred_index = int(tf.argmax(prediction, 1).eval())
                sentence = "%s %s" % (sentence,itw[onehot_pred_index])
                train_indices = train_indices[1:]
                train_indices.append(onehot_pred_index)
            print(sentence)
        except:
            print("Word not in dictionary")


# -*- coding: cp936 -*-
import xml.dom.minidom
import codecs
import os
fileName='d:/test.xml'
def t(value):
    dom = xml.dom.minidom.parse(fileName)
    root = dom.documentElement
    root.setAttribute('len',value)
    root.toxml()
    f = file(fileName,'w')
    writer = codecs.lookup('utf-8')[3](f)
    dom.writexml(writer,encoding='utf-8')
    writer.close()

def makeAttrib(dom,attribName,value):
    attrib = dom.createAttribute(attribName)
    attrib.appendChild(value)
    return attrib

def write():
    impl = xml.dom.minidom.getDOMImplementation()
    dom = impl.createDocument(None,'catalog',None)
    root = dom.documentElement
    text=unicode('ºº×Ö','cp936')
    item=makeEasyTag(dom,'item',text)
    root.appendChild(item)
    #xx = makeAttrib(dom,'len','xd')
    #.appendChild(xx)
    root.setAttribute('len','x')
    root.toxml()
    f=file('d:/test.xml','w')

    writer = codecs.lookup('utf-8')[3](f)
    dom.writexml(writer,encoding='utf-8')
    writer.close()

import string
import datetime
class Save2xml():
    '''save conversation to xml'''

    def __init__(self):
        pass
    def OpenFile(self,_xmlFileName):
        self.xmlFileName = _xmlFileName
        if os.path.exists(self.xmlFileName)==False:
            self.logFilexml = open(self.xmlFileName,'w')
            self.logFilexml.write('<?xml version="1.0"?>\n')
            self.logFilexml.write("<?xml-stylesheet type='text/xsl' href='MessageLog.xsl'?>\n<Log FirstSessionID='1' LastSessionID='0'></Log>")
            self.logFilexml.flush()
            self.logFilexml.close()
        self.dom = xml.dom.minidom.parse(self.xmlFileName)
        self.root = self.dom.documentElement
        self.LastSessionID = self.root.getAttribute('LastSessionID')
        self.CurrentSessionID=str(string.atoi(self.LastSessionID)+1)
        self.root.setAttribute('LastSessionID',self.CurrentSessionID)
    def WriteContent(self,content):
        #root = self.dom.documentElement
        item= makeEasyTag(self.dom,"Message","")
        item.setAttribute('SessionID',self.CurrentSessionID)
        curDateTuple=self.GetCurDate()
        item.setAttribute('Date',curDateTuple[0])
        item.setAttribute('Time',curDateTuple[1])
        item.setAttribute('DateTime',curDateTuple[2])

        itemFrom = makeEasyTag(self.dom,"From","")
        itemUser = makeEasyTag(self.dom,"User","")
        itemUser.setAttribute('FriendlyName','From')
        itemFrom.appendChild(itemUser)
        item.appendChild(itemFrom)
        itemTo = makeEasyTag(self.dom,"To","")
        itemUser = makeEasyTag(self.dom,"User","")
        itemUser.setAttribute('FriendlyName','Send')

        itemTo.appendChild(itemUser)
        item.appendChild(itemTo)
        itemText = makeEasyTag(self.dom,"Text",content)
        #itemText.setAttribute("Style",'font-family:Sans; color:#000000;')
        item.appendChild(itemText)
        self.root.appendChild(item)
        self.root.toxml()

    def CloseFile(self):
        f = file(self.xmlFileName,'w')
        import codecs
        writer=codecs.lookup('utf-8')[3](f)
        self.dom.writexml(writer,encoding='utf-8')
        writer.close()

    def GetCurDate(self):
        dt = datetime.datetime.today()
        return dt.date().isoformat(),dt.strftime("%H:%M:%S"),dt.isoformat()

    def __makeEasyTag(self,dom,tagname,value,type='text'):
        tag = dom.createElement(tagname)
        if value:
            if value.find(']]>')>-1:
                type='text'
            if type=='text':
                value=value.replace('&','&')
                value=value.replace('<','<')
                text = dom.createTextNode(value)
            elif type=='cdata':
                text = dom.createCDATASection(value)
            tag.appendChild(text)
        return tag

xx = Save2xml()
xx.OpenFile(fileName)
x = 0
while x<10:
    xx.WriteContent("shit"+str(x))
    x=x+1
xx.CloseFile()


import io, csv

class DataUtilities:
    @staticmethod
    def DictToCSV(data: list[dict]) -> str:
        if len(data) == 0:
            return ''

        csv_buffer = io.StringIO()
        csv_writer = csv.DictWriter(csv_buffer, fieldnames=list(data[0].keys()))

        csv_writer.writeheader()
        csv_writer.writerows(data)

        csv_data = csv_buffer.getvalue()
        csv_buffer.close()

        return csv_data

    @staticmethod
    def CSVToDict(data: str | bytes) -> list[dict]:
        csv_buffer = None

        if data is str:
            csv_buffer = io.StringIO(data)
        elif data is bytes:
            csv_buffer = io.BytesIO(data)
        else:
            raise Exception("Unknown type for data given.")

        csv_reader = csv.DictReader(csv_buffer)

        dict_data = [row for row in csv_reader]
        csv_buffer.close()

        return dict_data


# -*- coding: UTF-8 -*-
"""
title: 字母与数字
Given an array filled with letters and numbers, find the longest subarray with an equal number of letters and numbers.
Return the subarray. If there are more than one answer, return the one which has the smallest index of its left endpoint. If there is no answer, return an empty arrary.

Example 1:
Input: ["A","1","B","C","D","2","3","4","E","5","F","G","6","7","H","I","J","K","L","M"]
Output: ["A","1","B","C","D","2","3","4","E","5","F","G","6","7"]

Example 2:
Input: ["A","A"]
Output: []

Note:
array.length <= 100000
"""
from typing import List

class Solution:
    def findLongestSubarray(self, array: List[str]) -> List[str]:
        """前缀和 + 哈希表"""
        cur_sum, sum2idx = 0, {0: 0}
        start = end = 0
        for i, ch in enumerate(array, 1):
            cur_sum += 1 if ch.isdigit() else -1
            if cur_sum in sum2idx:
                if i - sum2idx[cur_sum] > end - start:
                    start, end = sum2idx[cur_sum], i
            else:
                sum2idx[cur_sum] = i
        return array[start: end]

if __name__ == '__main__':
    print(Solution().findLongestSubarray(
        ["A", "1", "B", "C", "D", "2", "3", "4", "E", "5", "F", "G", "6", "7", "H", "I", "J", "K", "L", "M"]))


'''
-------------------------------------------------------
[program description]
-------------------------------------------------------
Author:  Matthew Francis
ID:      180920880
Email:   fran0880@mylaurier.ca
__updated__ = "2019-03-19"
-------------------------------------------------------
'''
from Movie_utilities import read_movies
from functions import hash_table
from Hash_Set_array import Hash_Set
#from Movie import *

fh=open('movies.txt','r')
movielist = read_movies(fh)
hash_table(7 , movielist)

a = Hash_Set(7)
for val in movielist:
    a.insert(val)
a.debug()
fh.close()


from project.apps.curiosity import views
from django.urls import path

app_name = "curiosity"

urlpatterns = [
    path('', views.index, name='index'),
    path('posts/list/', views.PostListView.as_view(), name='post-list'),
    path('posts/create/', views.PostCreateView.as_view(), name='post-create'),
    path('posts/<slug:slug>/', views.PostDetailView.as_view(), name="post-detail"),
    path('posts/<slug:slug>/update/', views.PostUpdateView.as_view(), name="post-change"),
    path('posts/<slug:slug>/delete/', views.PostDeleteView.as_view(), name="post-delete"),
]

#
# urlpatterns += [
#     path('authors/list/', views.PostAuthorListView.as_view(), name='author-list'),
#     path('authors/create/', views.PostAuthorCreateView.as_view(), name='author-create'),
#     path('authors/<pk>/', views.PostAuthorDetailView.as_view(), name="author-detail"),
#     path('authors/<pk>/update/', views.PostAuthorUpdateView.as_view(), name="author-change"),
#     path('authors/<pk>/delete/', views.PostAuthorDeleteView.as_view(), name="author-delete"),
# ]

urlpatterns += [
    path('tags/list/', views.TagListView.as_view(), name='tag-list'),
    path('tags/create/', views.TagCreateView.as_view(), name='tag-create'),
    path('tags/<pk>/', views.TagDetailView.as_view(), name="tag-detail"),
    path('tags/<pk>/update/', views.TagUpdateView.as_view(), name="tag-change"),
    path('tags/<pk>/delete/', views.TagDeleteView.as_view(), name="tag-delete"),

]

urlpatterns += [
    path('channels/list/', views.ChannelListView.as_view(), name='channel-list'),
    path('channels/create/', views.ChannelCreateView.as_view(), name='channel-create'),
    path('channels/<pk>/', views.ChannelDetailView.as_view(), name="channel-detail"),
    path('channels/<pk>/update/', views.ChannelUpdateView.as_view(), name="channel-change"),
    path('channels/<pk>/delete/', views.ChannelDeleteView.as_view(), name="channel-delete"),
]

urlpatterns += [
    path('posts/<slug:slug>/magic/', views.magic_publishe, name='post-magic'),
    path('posts/get/file/', views.get_new_posts_of_file, name='get_new_posts_of_file'),
    path('posts/get/net/', views.get_new_posts_of_network, name='get_new_posts_of_network'),
    path('authors/<pk>/posts/list/', views.PostByAuthorListView.as_view(), name="author-post-list"),
    path('channels/<id>/posts/list/', views.PostByChannelListView.as_view(), name="channel-posts"),
    path('tags/<pk>/posts/list/', views.PostByTagListView.as_view(), name="tag-posts"),
]


import datetime as dt

from lucy.models.machine import Machine
from lucy.models import LucyObject

class Job(LucyObject):
    _type = 'jobs'

    def __init__(self, type, package, package_type, arch, suite,
                 builder=None, finished_at=None, assigned_at=None,
                 source=None, **kwargs):

        from lucy.models.source import Source
        from lucy.models.binary import Binary

        if package_type not in ["source", "binary"]:
            raise ValueError("package_type needs to be binary or source")

        if package_type == "source":
            package = Source.load(package)
            if source is None:
                source = package['_id']

        if package_type == "binary":
            package = Binary.load(package)
            if source is None:
                source = package['source']

        if package is None:
            raise ValueError("Bad package")

        package = package['_id']

        if builder:
            builder = Machine.load(builder)['_id']

        if source is None:
            raise ValueError("Bad source :(")

        super(Job, self).__init__(
            type=type,
            arch=arch,
            suite=suite,
            source=source,
            package=package,
            builder=builder,
            finished_at=finished_at,
            assigned_at=assigned_at,
            package_type=package_type,
            **kwargs)

    def get_package(self):
        from lucy.models.source import Source
        from lucy.models.binary import Binary

        if self['package_type'] == 'binary':
            return Binary.load(self['package'])

        if self['package_type'] == 'source':
            return Source.load(self['package'])

    def get_source(self):
        from lucy.models.source import Source
        return Source.load(self['source'])

    def get_reports(self, spec):
        from lucy.models.report import Report
        spec = spec.copy()
        spec.update({"job": self['_id']})
        for x in Report.query(spec):
            yield x

    def get_builder(self):
        builder = self.get('builder', None)
        if builder is None:
            return None
        return Machine.load(builder)

    def is_finished(self):
        return not self.get('finished_at', None) is None

    @classmethod
    def unassigned_jobs(cls, **kwargs):
        k = kwargs.copy()
        k.update({"builder": None, "finished_at": None})

        for x in cls.query(k):
            yield x

    @classmethod
    def next_job(cls, suites, arches, types, **kwargs):
        k = kwargs.copy()
        k.update({"builder": None,
                  "finished_at": None,
                  "type": {"$in": types},
                  "suite": {"$in": suites},
                  "arch": {"$in": arches}})
        v = cls.single(k)
        return v

    @classmethod
    def dead_jobs(cls, howlong, **kwargs):
        cutoff = dt.datetime.utcnow() - howlong
        for x in cls.unfinished_jobs(**{
            "assigned_at": {"$lt": cutoff},
            "builder": {"$ne": None},
            "finished_at": None
        }):
            yield x

    @classmethod
    def by_package(cls, package, **kwargs):
        for x in cls.query({"package": package}):
            yield x

    def is_pending(self):
        if self['finished_at'] is None:
            return True
        return False

    def is_failed(self):
        try:
            next(self.get_reports({"failed": False}))
            return False
        except StopIteration:
            return True

    def is_critical(self):
        if self['type'] in [
            "build",
            "piuparts",
            "adequite",
        ]:
            return True
        return False

    @classmethod
    def by_source(cls, source, **kwargs):
        return cls.query({"source": source})

    @classmethod
    def unfinished_jobs(cls, **kwargs):
        k = {}
        k.update({"finished_at": None,
                  "builder": {"$ne": None}})
        k.update(kwargs.copy())

        return cls.query(k)

    @classmethod
    def assigned_jobs(cls, builder, **kwargs):
        return cls.unfinished_jobs(**{"builder": builder})


import argparse
import os
import torch

from models.tta.autoencoder.autoencoder_trainer import AutoencoderKLTrainer
from models.tta.ldm.audioldm_trainer import AudioLDMTrainer
from utils.util import load_config

def build_trainer(args, cfg):
    supported_trainer = {
        "AutoencoderKL": AutoencoderKLTrainer,
        "AudioLDM": AudioLDMTrainer,
    }

    trainer_class = supported_trainer[cfg.model_type]
    trainer = trainer_class(args, cfg)
    return trainer

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--config",
        default="config.json",
        help="json files for configurations.",
        required=True,
    )
    parser.add_argument(
        "--num_workers", type=int, default=6, help="Number of dataloader workers."
    )
    parser.add_argument(
        "--exp_name",
        type=str,
        default="exp_name",
        help="A specific name to note the experiment",
        required=True,
    )
    parser.add_argument(
        "--resume",
        type=str,
        default=None,
        # action="store_true",
        help="The model name to restore",
    )
    parser.add_argument(
        "--log_level", default="info", help="logging level (info, debug, warning)"
    )
    parser.add_argument("--stdout_interval", default=5, type=int)
    parser.add_argument("--local_rank", default=-1, type=int)
    args = parser.parse_args()
    cfg = load_config(args.config)
    cfg.exp_name = args.exp_name

    # Model saving dir
    args.log_dir = os.path.join(cfg.log_dir, args.exp_name)
    os.makedirs(args.log_dir, exist_ok=True)

    if not cfg.train.ddp:
        args.local_rank = torch.device("cuda")

    # Build trainer
    trainer = build_trainer(args, cfg)

    # Restore models
    if args.resume:
        trainer.restore()
    trainer.train()

if __name__ == "__main__":
    main()


'''
服务器配置, 数据库配置
'''
import yaml
from utils.typecheck import typecheck

class Config:
    def __init__(self):
        pass

    @property
    def server_ip(self):
        return self.__server_ip

    @server_ip.setter
    @typecheck(str)
    def server_ip(self, server_ip):
        self.__server_ip = server_ip

    @property
    def server_port(self):
        return self.__server_port

    @server_port.setter
    @typecheck(int)
    def server_port(self, server_port):
        if server_port > 0 and server_port < 65536:
            self.__server_port = server_port
        else:
            raise ValueError('Wrong server port: %d' % server_port)

    def print(self):
        print('server: ')
        print('\tip: %s' % self.server_ip)
        print('\tport: %s' % self.server_port)

    # 全局配置
    __config = None

    @classmethod
    def get_instance(cls):
        if not Config.__config:
            raise ValueError('config not init')
        return Config.__config

    @classmethod
    def init(cls, path):
        if not path or len(path) == 0:
            raise ValueError('Yaml path error: %s' % path)

        file = open(path, 'r', encoding='utf8')
        file_data = file.read()
        file.close()

        # 解析yaml数据
        yaml_data = yaml.load(file_data)
        if not isinstance(yaml_data, dict):
            raise ValueError('Wrong config type')
        if 'server' not in yaml_data:
            raise ValueError('server config not found in yaml')

        server = yaml_data['server']
        if not isinstance(server, dict):
            raise ValueError('server config type error')

        config = Config()
        if 'ip' not in server:
            # 如果未设置要监听的网卡地址, 设置默认值
            config.server_ip = '0.0.0.0'
        else:
            config.server_ip = server['ip']

        if 'port' not in server:
            raise ValueError('server port must be set')
        else:
            config.server_port = server['port']

        Config.__config = config


def LIS(i, A):
    if res[i]!=-1:
        return res[i]
    ans = 0
    j = i+1
    while(j<len(arr)):
        if arr[j] > arr[i]:
            ans = max(ans, LIS(j, arr))
        j=j+1
    res[i] = 1 + ans
    return res[i]

arr = [100,9,8,7,6,30,20,56,63]

ans = 0
maxim = 0
path = []
for n in range(len(arr)):
    res = [-1] * 20
    ans = max(ans, LIS(n, arr))
    if ans>maxim:
        maxim = ans
        path = res

print(ans)
# path printing
for i in range(len(arr)):
    if path[i] > path[i+1]:
        print(arr[i])


"""
https://leetcode.com/explore/interview/card/facebook/5/array-and-strings/283/
"""
from typing import List

class Solution:
  def threeSum(self, nums: List[int]) -> List[List[int]]:
    if len(nums) < 3:
      return []

    o = []
    lookup = {} # val -> idx

    # gen lookup table
    for idx,v in enumerate(nums):
      lookup[nums[idx]] = idx

    i = j = k = 0
    used = []
    while i < len(nums):
      ci = nums[i]

      j = i + 1
      while j < len(nums):
        cj = nums[j]

        k = j + 1
        while k < len(nums):
          ck = nums[k]
          if (ci + cj + ck) == 0:
            idxset = set({i, j, k})

            # is this triplet already used?
            if idxset in used:
              k = k + 1
              continue

            used.append(idxset)

            sol = sorted([ci, cj, ck])
            print(f"nums: {nums} -> used:{used} -> idxset:{idxset} == {sol}")

            if not (sol in o):
              o.append(sol)

          k = k + 1

        j = j + 1

      i = i + 1

    return o

if __name__ == '__main__':
  s = Solution()

  def compare(out, exp):
    val = False

    if len(out) != len(exp):
      pc(out, exp, val)
      return

    i = 0
    j = 0

    o = list(out)
    e = list(exp)
    while i < len(out):
      ci = out.pop()

      j = 0
      found = False
      while j < len(exp):
        cj = exp[j]

        if ci == cj:
          found = True
          del exp[j]
          break

      if not found:
        break
    val = True

    pc(o, e, val)

  def pc(out, exp, val):
    print(f"{out} == {exp} -> {val}")

  compare(s.threeSum([]), [])
  compare(s.threeSum([0]), [])
  compare(s.threeSum([-1,0,1,2,-1,-4]), [[-1,-1,2],[-1,0,1]])


import csv
from os import listdir
import sys
import collections

directory = str(sys.argv[1])
outgroup_file = str(sys.argv[2])
output = str(sys.argv[3])

list_of_files = os.listdir(directory)

genes_dict = {}
for i in range(len(list_of_files)):
    print(list_of_files[i])
    if list_of_files[i] == outgroup_file: ## skip outgroup
        continue
    with open(directory + '/' + list_of_files[i], newline = '') as file:
        file_reader = csv.reader(file, delimiter = '\t')
        next(file_reader)
        for row in file_reader:
            gene = row[1]
            if len(key_trimmed.split(', ')) > 1:
                for ii in range(len(gene.split(', '))):
                    split_gene = gene.split(', ')[ii]
                    if split_gene not in genes_dict:
                        genes_dict[split_gene] = 1
                    else:
                        genes_dict[split_gene] += 1
            else:
                if gene not in genes_dict:
                    genes_dict[gene] = 1
                else:
                    genes_dict[gene] += 1

genes_list = []
for key, val in genes_dict.items():
    genes_list.append([key, val])

genes_list_sorted = sorted(genes_list, key=lambda x: x[0])

output = 'pav_per_gene' # str(sys.argv[2])
with open(output, 'w', newline = '') as output_csv:
    w = csv.writer(output_csv, delimiter = '\t')
    for i in range(len(genes_list_sorted)):
        row = [genes_list_sorted[i][0], genes_list_sorted[i][1]]
        w.writerow(row)


from utils import day
from more_itertools import chunked, divide
from string import ascii_letters

RAW = day(3)

values = dict(zip(ascii_letters, range(1,53)))
sacks = RAW.splitlines()

# part1
print(sum(
    values[set.intersection(*map(set, divide(2, sack))).pop()]
    for sack in sacks
))

# part2
print(sum(
    values[set.intersection(*map(set, group)).pop()]
    for group in chunked(sacks, 3)
))


# -*- coding: utf-8 -*-

"""Tests of the internal tabulate functions."""

from __future__ import print_function
from __future__ import unicode_literals
import tabulate as T
from common import assert_equal, assert_in, assert_raises, SkipTest

def test_multiline_width():
    "Internal: _multiline_width()"
    multiline_string = "\n".join(["foo", "barbaz", "spam"])
    assert_equal(T._multiline_width(multiline_string), 6)
    oneline_string = "12345"
    assert_equal(T._multiline_width(oneline_string), len(oneline_string))

def test_align_column_decimal():
    "Internal: _align_column(..., 'decimal')"
    column = ["12.345", "-1234.5", "1.23", "1234.5", "1e+234", "1.0e234"]
    output = T._align_column(column, "decimal")
    expected = [
            '   12.345  ',
            '-1234.5    ',
            '    1.23   ',
            ' 1234.5    ',
            '    1e+234 ',
            '    1.0e234']
    assert_equal(output, expected)

def test_align_column_none():
    "Internal: _align_column(..., None)"
    column = ['123.4', '56.7890']
    output = T._align_column(column, None)
    expected = ['123.4', '56.7890']
    assert_equal(output, expected)

def test_align_column_multiline():
    "Internal: _align_column(..., is_multiline=True)"
    column = ["1", "123", "12345\n6"]
    output = T._align_column(column, "center", is_multiline=True)
    expected = [
            "  1  ",
            " 123 ",
            "12345" + "\n" +
            "  6  "]
    assert_equal(output, expected)