Python Binary Tree - python-3.x

I'm working on a binary tree in Python3 and so far almost everything has been working like expected; however, I have a function that is supposed to return a list of all children for any given node and for whatever reason I'm only getting a list of the object addresses, and not calling my overridden __str__(self) method.
from collections import deque # http://docs.python.org/3.1/tutorial/datastructures.html
class BinaryNode: # binary tree functionality via iterative means
def __init__(self, name, data):
self.Left = None
self.Right = None
self.Parent = None
self.Name = name
self.Data = data
return
def AddNew(self, name, data):
q = []
q.append(self)
while q:
i = q.pop()
if i.Name == name:
i.Data = data
return i
elif name < i.Name:
if i.Left:
q.append(i.Left)
else:
i.Left = BinaryNode(name, data)
i.Left.Parent = i
return i.Left
else:
if i.Right:
q.append(i.Right)
else:
i.Right = BinaryNode(name, data)
i.Right.Parent = i
return i.Right
def Find(self, name):
q = deque()
q.append(self)
'''if self.Left: q.append(self.Left)
if self.Right: q.append(self.Right)'''
while q:
i = q.pop()
print(i)
if i.Name == name:
return i
elif name < i.Name:
if i.Left: q.append(i.Left)
else: return None
else:
if i.Right: q.append(i.Left)
else: return None
def Children(self):
children = []
q = deque()
if self.Left: q.append(self.Left)
if self.Right: q.append(self.Right)
while q:
i = q.popleft()
if i.Left: q.append(i.Left)
if i.Right: q.append(i.Right)
children.append(i)
return children
def Parents(self):
lst = []
i = self.Parent
while i is not None:
lst.append(i)
i = i.Parent
return lst
def __str__(self): return "{} : {}".format(self.Name, self.Data)
and I'm testing it by calling
test = BinaryNode("Jesse", 21)
print(test)
print(test.AddNew("David", 22))
print(test.AddNew("Marli", 23))
print(str(test.Children()))
print(test.Find("David"))
print(test.Find("David").Children())
print(test.Find("Gary")) #Will return None
with the resulting console output
Jesse : 21
David : 22
Marli : 23
[<__main__.BinaryNode object at 0x000000000333E160>, <__main__.BinaryNode object at 0x000000000333E1D0>, <__main__.BinaryNode object at 0x000000000333E198>]
David : 22
[<__main__.BinaryNode object at 0x000000000333E1D0>]
None
UPDATE:
Here is the answer I implemented:
def __repr__ (self): return str(self)

Python containers always use the representation of contained objects.
Implement a __repr__ method too and that'll be used when printing the list; you can make it an alias for __str__ if you wish:
__repr__ = __str__
or explicitly print each element in your list:
print(', '.join(map(str, test.Children())))

Related

Seeking advise on create a maze to solve with BFS in Python

Seeking advise on how structure python to create a maze, solve it with BFS and to have basic navigation within maze with number of moves required to navigate. Use move along the path, Up, Left, Right, Down. Below is some code that I mangled together to think about and figure how to structure python for this BFS algorithm code.
Is anyone open to mentoring on this BFS algorithm navigation maze python structure?
To basically follow the following algorithm:
function BREADTH-FIRST-SEARCH(problem) returns a solution node or failure
node ← NODE(problem.INITIAL)
if problem.IS-GOAL(node.STATE) then return node
frontier ← a FIFO queue, with node as an element
reached ← {problem.INITIAL}
while not IS-EMPTY(frontier ) do
node ← POP(frontier )
for each child in EXPAND(problem, node) do
s ← child.STATE
if problem.IS-GOAL(s) then return child
if s is not in reached then
add s to reached
add child to frontier
return failure
import sys
def parse_map(filename):
with open(filename, "r") as f:
return [[char for char in line] for line in f.read().rstrip("\n").split("\n")][3:]
def count_x(house_map):
return sum([ row.count('p') for row in house_map ] )
def printable_house_map(house_map):
return "\n".join(["".join(row) for row in house_map])
def add_x(house_map, row, col):
return house_map[0:row] + [house_map[row][0:col] + ['p',] + house_map[row][col+1:]] + house_map[row+1:]
def successors(house_map):
return [ add_x(house_map, r, c) for r in range(0, len(house_map)) for c in range(0,len(house_map[0])) if house_map[r][c] == '.' ]
def is_goal(house_map, k):
return count_x(house_map) == k
def bfs_graph_search(house_map):
fringe = [initial_house_map]
if house_map.goal_test(node.state):
return fringe
fringe = deque([house_map])
visited = set()
while fringe:
fringe = fringe.popleft()
visited.add(node.state)
for child in node.expand(problem):
if child.state not in fringe and child not in visited:
if house_map.goal_test(child.state):
return child
fringe.append(child)
return None
def solve(initial_house_map,k):
fringe = [initial_house_map]
while len(fringe) > 0:
for new_house_map in successors( fringe.pop() ):
if is_goal(new_house_map,k):
return(new_house_map,True)
fringe.append(new_house_map)
if __name__ == "__main__":
house_map=parse_map('map1.txt')
k = 2
print ("Initial ]house map:\n" + printable_house_map(house_map) + "\n\nSearching for solution...\n")
solution = solve(house_map,k)
print ("Found:")
print (printable_house_map(solution[0]) if solution[1] else "False")
class Agent:
def __init__(self, initial, goal=None):
self.initial = initial
self.goal = goal
def actions(self, state):
raise NotImplementedError
def result(self, state, action):
raise NotImplementedError
def goal_test(self, state):
if isinstance(self.goal, list):
return is_in(state, self.goal)
else:
return state == self.goal
def path_cost(self, c, state1, action, state2):
return c + 1
def value(self, state):
raise NotImplementedError
class FringeGraph:
def __init__(self, state, parent=None, action=None, path_cost=0):
self.state = state
self.parent = parent
self.action = action
self.path_cost = path_cost
self.depth = 0
if parent:
self.depth = parent.depth + 1
def path(self):
node, path_back = self, []
while node:
path_back.append(node)
node = node.parent
return list(reversed(path_back))
def solution(self):
return [node.action for node in self.path()[1:]]
def expand(self, agent):
return [self.child_node(agent, action)
for action in agent.actions(self.state)]
def child_node(self, agent, action):
next_state = agent.result(self.state, action)
next_node = Node(next_state, self, action, problem.path_cost(self.path_cost, self.state, action, next_state))
return next_node
class Agent:
def __init__(self, initial, goal=None):
self.initial = initial
self.goal = goal
def actions(self, state):
raise NotImplementedError
def result(self, state, action):
raise NotImplementedError
def goal_test(self, state):
if isinstance(self.goal, list):
return is_in(state, self.goal)
else:
return state == self.goal
def path_cost(self, c, state1, action, state2):
return c + 1
def value(self, state):
raise NotImplementedError
class FringeGraph:
def __init__(self, state, parent=None, action=None, path_cost=0):
self.state = state
self.parent = parent
self.action = action
self.path_cost = path_cost
self.depth = 0
if parent:
self.depth = parent.depth + 1
def path(self):
node, path_back = self, []
while node:
path_back.append(node)
node = node.parent
return list(reversed(path_back))
def solution(self):
return [node.action for node in self.path()[1:]]
def expand(self, agent):
return [self.child_node(agent, action)
for action in agent.actions(self.state)]
def child_node(self, agent, action):
next_state = agent.result(self.state, action)
next_node = Node(next_state, self, action, agent.path_cost(self.path_cost, self.state, action, next_state))
return next_node

Python pre-order to postfix notation reverse polish notation

I am trying to find a solution in Python to try and move the pre-order notation e.g."* + 7 3 - 2 9" or "+ 55 26" to post notation or the reverse polish notation. the expected result would be e.g. "7 3 + 2 9 - *" and "55 26 +" respectively. I did some research on the binary trees however with the math functions I am struggling. What I have currently is the following:
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.data = data
Function to check for operators
def isOperator(self, c):
return c == '+' or c == '-' or c == '*' or c == '/'
Insert Node
def insert(self, data):
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
Print the Tree
def PrintTree(self):
if self.left:
self.left.PrintTree()
print( self.data),
if self.right:
self.right.PrintTree()
Preorder traversal
Root -> Left ->Right
def PreorderTraversal(self, root):
res = []
if root:
res.append(root.data)
res = res + self.PreorderTraversal(root.left)
res = res + self.PreorderTraversal(root.right)
return res
Postorder traversal
Left ->Right -> Root
def PostorderTraversal(self, root):
res = []
if root:
res = self.PostorderTraversal(root.left)
res = res + self.PostorderTraversal(root.right)
res.append(root.data)
return res
Any assistance in getting this code complete will be highly appreciated, as I am not able to figure this out.
Thank you in advance
First some issues:
Your insert method applies binary search tree logic, which is not relevant for the expression tree you want to build. Instead it should keep track of the insertion spot for any next data.
It is not clear whether these are all methods of the Node class, but at least isOperator is unrelated to any instance values, so it should not be a method (with self argument), but either a stand alone function or a static method. Moreover, if the input is valid, then an operator is anything that is not a number.
Methods should not print (except for debugging purposes): leave that for the main driver code to do. Methods can help printing by returning an iterator, or a representation (implementing __repr__).
It is common practice to not use an initial capital letter for function names and reserve that for class names.
I would suggest a separate class for the tree. This will be handy to track where the next node should be inserted, using a path (stack).
Here is how you could implement it:
class Node:
def __init__(self, data, left=None, right=None):
self.left = left
self.right = right
self.data = data
def __iter__(self): # default iteration is inorder
if self.left:
yield from self.left
yield self.data
if self.right:
yield from self.right
def preorder(self):
yield self.data
if self.left:
yield from self.left.preorder()
if self.right:
yield from self.right.preorder()
def postorder(self):
if self.left:
yield from self.left.postorder()
if self.right:
yield from self.right.postorder()
yield self.data
class Tree:
def __init__(self):
self.root = None
self.path = []
def insert(self, data):
if not self.root:
node = self.root = Node(data)
elif not self.path:
raise ValueError("Cannot add more nodes")
elif self.path[-1].left:
node = self.path[-1].right = Node(data)
else:
node = self.path[-1].left = Node(data)
if not data.isnumeric(): # internal node
self.path.append(node)
else:
while self.path and self.path[-1].right:
self.path.pop()
#staticmethod
def fromstr(s):
tree = Tree()
for token in s.split():
tree.insert(token)
return tree
def __iter__(self):
if self.root:
yield from self.root
def preorder(self):
if self.root:
yield from self.root.preorder()
def postorder(self):
if self.root:
yield from self.root.postorder()
Here is how you can run it:
def postorder(s):
tree = Tree.fromstr(s)
# Just for debugging, print the tree in inorder:
print(*tree) # this calls `__iter__`
return " ".join(tree.postorder())
print(postorder("* + 7 3 - 2 9"))
Output (inorder and postorder):
7 + 3 * 2 - 9
7 3 + 2 9 - *

how can i iterate class objects while using generator in python?

i want to compare the 2000 pairs of a and b, and print the matching pairs and count of them.can anyone help me to get rid of it.it shows this error TypeError: 'seq_generator' object is not iterable at line 34
class generator(object):
def __init__(self,s,start_A,fact_A):
self.s=s
self.start_A=start_A
self.fact_A = fact_A
def seq_gen_A(self):
while self.s>0:
self.gen_A=(self.start_A*self.fact_A)%2147483647
self.g=self.gen_A
self.start_A=self.gen_A
self.bin_A=(bin(self.gen_A)[-16:])
yield self.bin_A
self.s=self.s-1
def next(self):
for i in self.seq_gen_A():
return i
def main():
s=200
count=0
a=generator(s,65,16807)
b=generator(s,8921,48271)
print("Matching pair")
print("*************")
for i in range(0,s):
if next(a)==next(b):
count+=1
print(a,b)
print('Matching pair count',count)
You are defining your generator not correctly. You need methods __iter__ and __next__:
class generator(object):
def __init__(self, s, start_A, fact_A):
self.s = s
self.start_A = start_A
self.fact_A = fact_A
def __iter__(self):
return self
def __next__(self):
if self.s <= 0:
raise StopIteration()
gen_A = (self.start_A*self.fact_A)%2147483647
self.start_A = gen_A
yield bin(gen_A)[-16:]
self.s -= 1

Python, Linked list: AttributeError: 'function' object has no attribute 'get_next'

I'm trying to do an implementation of a simple linked list but I keep getting this exception: AttributeError: 'function' object has no attribute 'get_next'.
here is my code:
class Lista:
def __init__(self):
self.root = None
self.len_l = 0
def __str__(self):
if not self.len_l:
return "::EMPTY::"
lista_c = ""
next_node = self.root
while next_node:
if next_node.get_next():
if type(next_node.get_datos()) != str:
lista_c += "%s -> "%(next_node.get_datos())
else:
lista_c += "'%s' -> "%(next_node.get_datos())
else:
if type(next_node.get_datos()) != str:
lista_c += " %s"%(next_node.get_datos())
else:
lista_c += " '%s'"%(next_node.get_datos())
next_node = next_node.get_next()
return lista_c
def add(self, dato):
self.root = nodo(dato,self.root)
self.len_l += 1
def find(self,dato):
if not self.len_l:
raise LSLexception("empty list")
this_node = self.root
while this_node.get_next():
if dato == this_node.get_datos():
return this_node
this_node = this_node.get_next()
return -1
def Valid_pos(self,pos):
if self.len_l == 0:
raise LSLexception("empty list")
if pos not in range(0,self.len_l):
raise LSLexception("data overflow")
def remove(self,dato):
if not self.len_l:
raise LSLexception("empty list")
if self.root.get_datos() == dato:
self.root = self.root.get_next()
previous_node = self.root
this_node = previous_node.get_next()
while this_node.get_next():
if this_node.get_datos() == dato:
previous_node.set_next(this_node.get_next())
return this_node
else:
previous_node = this_node
this_node = previous_node.get_next()
return -1
The problem occurs in the function remove in this line while this_node.get_next(): but I'm using that same line in the function "find" an I. Works fine, any ideas? Is for college so there are some things I can't change.
You forget to put parentheses when you try to call get_next, so some of the node variables are assigned to a function instead of a node.
Like this_node = previous_node.get_next in def remove(self, dato), you might want to change that to
this_node = previous_node.get_next()
Also, set_next in previous_node.set_next = this_node.get_next also looks like a function to me. You might want to change that too.

Instances ship attributes to other instances after construction

I was looking for a way to access configuration file entries from instance- resp. class-bound variables. Therefor I have created the following module:
from ..lib.files import ConfigFile
from abc import abstractmethod
__all__ = ['ClassConfig',
'InstanceConfig',
'Configurable']
class ConfigEntry():
"""
A Config entry
"""
__value = None
def __init__(self, value=None):
"""
Initializes the
"""
self.__value = value
def __set__(self, __, value):
self.__value = value
#property
def value(self):
"""
Returns the value
"""
return self.__value
class ClassConfig(ConfigEntry):
"""
A class config entry
"""
def __get__(self, obj, cls):
"""
Returns its value, when called by a class, else itself
"""
if obj == None:
return self.value
else:
return self
class InstanceConfig(ConfigEntry):
"""
An instance config entry
"""
def __get__(self, obj, cls):
"""
Returns its value, when called by an instance, else itself
"""
if obj != None:
return self.value
else:
return self
class Configurable():
"""
Configuration file binding
"""
__SUFFIX = '.conf'
__TYPES = {int: 'int',
float: 'float',
str: 'str',
bool: 'bool'}
__file_ = None
__lbi = '['
__lei = ']'
__ls = ','
__ts = '←'
__loaded = False
def __init__(self, path, suffix=None):
"""
Initialize the config file
"""
# Initializes instance methods
self.__setinstattr()
suffix = suffix if suffix != None else self.__SUFFIX
self.__file_ = ConfigFile(path + suffix)
self.load()
def __setinstattr(self):
"""
Set instance attributes
"""
self.__fields = self.__inst___fields
self._file = self.__inst____file
self._force_load = self.__inst__force_load
self.load = self.__inst_load
self.store = self.__inst_store
#staticmethod
def __filter(attrs):
return [a for a in attrs
if a == a.upper()
and not a.startswith('_')]
#staticmethod
def __encode(val):
"""
Encode a value
"""
t = type(val)
if t == list:
return Configurable.__lbi + \
Configurable.__ls.join([Configurable.__encode(i)
for i in val]) \
+ Configurable.__lei
elif val == None:
return None
else:
return Configurable.__ts.join([str(val),
Configurable.__TYPES.get(t, '?')])
#staticmethod
def __decode(val):
"""
Decode a value
"""
def det_type(token):
"""
Determine the type of a token
"""
t = token.strip().split(Configurable.__ts)
if len(t) == 2:
raw_val = t[0]
tpe = t[1]
if tpe == Configurable.__TYPES[str]:
return str(raw_val)
elif tpe == Configurable.__TYPES[int]:
return int(raw_val)
elif tpe == Configurable.__TYPES[float]:
return float(raw_val)
elif tpe == Configurable.__TYPES[bool]:
return True if raw_val.lower() in ['1',
'true',
't'] else False
else:
try:
return int(raw_val)
except:
try:
return float(raw_val)
except:
return raw_val
return token
def str2list(s):
"""
Try to parse a list from a string
"""
def getlist(val):
"""
Get a list from a reversed character list of a string
"""
result = []
token = ''
while val:
c = val.pop()
if c == Configurable.__lei:
token = Configurable.__lei
result = [getlist(val)] + result
elif c == Configurable.__lbi:
if (not Configurable.__lbi in token) and (not Configurable.__lei in token):
result = [det_type(token)] + result
token = c
return result
elif c == Configurable.__ls:
if (not Configurable.__lbi in token) and (not Configurable.__lei in token):
result = [det_type(token)] + result
token = ''
else:
token = c + token
if token:
result = [det_type(token)] + result
return result
l = []
for char in s:
l.append(char)
l = getlist(l)
if len(l) == 0:
return l
return l.pop()
return str2list(val)
#classmethod
def __fields(cls):
"""
Get fields for an instance
"""
result = {}
class Subclass(cls):
def __init__(self):
pass
instance = Subclass()
attrs = Configurable.__filter(dir(instance))
for a in attrs:
aval = getattr(instance, a)
if isinstance(aval, ClassConfig):
value = getattr(cls, a)
result[a] = value
return result
def __inst___fields(self):
"""
Get fields of an instance
"""
result = {}
cls = self.__class__
attrs = Configurable.__filter(dir(cls))
for a in attrs:
val = getattr(cls, a)
if isinstance(val, InstanceConfig):
value = getattr(self, a)
result[a] = value
return result
#classmethod
#abstractmethod
def _file(cls):
"""
Returns the file
XXX: Implement by calling
super()._file(static_path)
"""
pass
#classmethod
def _file_path(cls, path, suffix=None):
"""
Returns the file relative to a path
"""
suffix = suffix if suffix != None else cls.__SUFFIX
f = ConfigFile(path + suffix)
f.create()
return f
def __inst____file(self):
"""
Returns the file
"""
return self.__file_
#classmethod
def load(cls):
"""
Loads the config file content, if not yet done into the class
"""
if not cls.__loaded:
return cls._force_load()
return True
def __inst_load(self):
"""
Loads the config file content, if not yet done into the instance
"""
if not self.__loaded:
return self._force_load()
return True
#classmethod
def _force_load(cls):
"""
Loads the config file's content to the class
"""
if cls._file().exists:
data = cls._file().dict()
for field in Configurable.__filter(data):
setattr(cls, field,
Configurable.__decode(data[field]))
cls.__loaded = True
return True
return False
def __inst__force_load(self):
"""
Loads the config file's content to the instance
"""
if self._file().exists:
data = self._file().dict()
for field in Configurable.__filter(data):
setattr(self, field,
Configurable.__decode(data[field]))
self.__loaded = True
return True
return False
#classmethod
def store(cls):
"""
Writes class config to file
"""
result = True
content = cls.__fields()
if not cls._file().exists:
cls._file().create()
for new_field in content:
set_result = cls._file().set(new_field,
Configurable.__encode(content[new_field]))
result = False if not set_result else result
return result
def __inst_store(self):
"""
Writes instance config to file
"""
result = True
content = self.__fields()
if not self._file().exists:
self._file().create()
for new_field in content:
set_result = self._file().set(new_field,
Configurable.__encode(content[new_field]))
result = False if not set_result else result
return result
The Configurable class is now inherited by several sub-classes, which may have global configuration (the class-bound stuff) and user-dependen configuration (the instance-bound stuff) like that:
class Spam(Configurable):
EGGS = InstanceConfig('foo')
GLOBAL_EGGS = ClassConfig('bar')
Now I face the problem, that each time a load() is performed on many instances in sequence, the InstanceConfigEntry will copy the value from the previuos instance:
class RETARD(Daemon):
"""
Real Estate Translation, Archiving and Redirection Daemon
"""
__source = None # The source interface instance
__targets = [] # The target interface instances
__locked = False # System locked state flag
__start_time = None # Start time of loop
__sleeping = 0 # Remaining time to sleep
#===========================================================================
# Default customer config
#===========================================================================
SOURCE = InstanceConfig('') # Name of the source interface
TARGETS = InstanceConfig([]) # Names of the target interfaces
INTERVAL = InstanceConfig(120.0) # Loop interval
DEBUG = InstanceConfig(False) # Print the import config?
def __init__(self, customer):
"""
Constructor
"""
print('SOURCE1: ' + str(self.SOURCE))
super().__init__(customer)
print('SOURCE2: ' + str(self.SOURCE))
self.__load()
print('SOURCE3: ' + str(self.SOURCE))
# Disable logger on high level to prevent PyXB
# from printing messages to the terminal
logging.disable(9999)
<SNIP>
When loaded like this (daemons contains four different instances):
daemons = []
for customer in customers:
daemons.append(RETARD(customer))
It will produce this output:
SOURCE1:
SOURCE2: IS24
SOURCE3: IS24
SOURCE1: IS24
SOURCE2: is24
SOURCE3: is24
SOURCE1: is24
SOURCE2: infobase
SOURCE3: infobase
SOURCE1: infobase
SOURCE2: infobase
SOURCE3: infobase
I do not understand this behaviour, since I did not change the class' attributes anywhere but just those of the instances.
How can I avoid the instances to ship their changed attributes to the next instance?
The problem here, wich I did not realize was, that the InstanceConfig and ClassConfig entries as bound to the class at the time, the module is loaded. When I assigned other content to the respective attributes during runtime from within an instance, it of course just changed the content of the still class-bound *Config instance.
I worked arund this issue by defaulting values iff they are not contained within the respective config file like so:
from ..lib.files import ConfigFile
from abc import abstractmethod
__all__ = ['ClassConfig',
'InstanceConfig',
'Configurable']
class ConfigEntry():
"""
A Config entry
"""
__value = None
__default = None
def __init__(self, default=None):
"""
Initializes the
"""
self.__default = default
self.__value = default
def __set__(self, __, value):
"""
Sets the value
"""
self.__value = value
#property
def value(self):
"""
Returns the value
"""
return self.__value
#property
def default(self):
"""
Access default value
"""
return self.__default
class ClassConfig(ConfigEntry):
"""
A class config entry
"""
def __get__(self, obj, cls):
"""
Returns its value, when called by a class, else itself
"""
if obj == None:
return self.value
else:
return self
class InstanceConfig(ConfigEntry):
"""
An instance config entry
"""
def __get__(self, obj, cls):
"""
Returns its value, when called by an instance, else itself
"""
if obj != None:
return self.value
else:
return self
class Configurable():
"""
Configuration file binding
"""
__SUFFIX = '.conf'
__TYPES = {int: 'int',
float: 'float',
str: 'str',
bool: 'bool'}
__file_ = None
__lbi = '[' # List begin identifier
__lei = ']' # List end identifier
__ls = ',' # List separator
__ts = '←' # Type separator
__loaded = False
def __init__(self, path, suffix=None):
"""
Initialize the config file
"""
# Initializes instance methods
self.__setinstattr()
suffix = suffix if suffix != None else self.__SUFFIX
self.__file_ = ConfigFile(path + suffix)
self.load()
def __setinstattr(self):
"""
Set instance attributes
"""
self.__fields = self.__inst___fields
self._file = self.__inst____file
self._force_load = self.__inst__force_load
self.load = self.__inst_load
self.store = self.__inst_store
#staticmethod
def __filter(attrs):
return [a for a in attrs
if a == a.upper()
and not a.startswith('_')]
#staticmethod
def __encode(val):
"""
Encode a value
"""
t = type(val)
if t == list:
return Configurable.__lbi + \
Configurable.__ls.join([Configurable.__encode(i)
for i in val]) \
+ Configurable.__lei
elif val == None:
return None
else:
return Configurable.__ts.join([str(val),
Configurable.__TYPES.get(t, '?')])
#staticmethod
def __decode(val):
"""
Decode a value
"""
def det_type(token):
"""
Determine the type of a token
"""
t = token.strip().split(Configurable.__ts)
if len(t) == 2:
raw_val = t[0]
tpe = t[1]
if tpe == Configurable.__TYPES[str]:
return str(raw_val)
elif tpe == Configurable.__TYPES[int]:
return int(raw_val)
elif tpe == Configurable.__TYPES[float]:
return float(raw_val)
elif tpe == Configurable.__TYPES[bool]:
return True if raw_val.lower() in ['1',
'true',
't'] else False
else:
try:
return int(raw_val)
except:
try:
return float(raw_val)
except:
return raw_val
return token
def str2list(s):
"""
Try to parse a list from a string
"""
def getlist(val):
"""
Get a list from a reversed character list of a string
"""
result = []
token = ''
while val:
c = val.pop()
if c == Configurable.__lei:
token = Configurable.__lei
result = [getlist(val)] + result
elif c == Configurable.__lbi:
if (not Configurable.__lbi in token) and (not Configurable.__lei in token):
result = [det_type(token)] + result
token = c
return result
elif c == Configurable.__ls:
if (not Configurable.__lbi in token) and (not Configurable.__lei in token):
result = [det_type(token)] + result
token = ''
else:
token = c + token
if token:
result = [det_type(token)] + result
return result
l = []
for char in s:
l.append(char)
l = getlist(l)
if len(l) == 0:
return l
return l.pop()
return str2list(val)
#classmethod
def __fields(cls):
"""
Get fields for an instance
"""
result = {}
class Subclass(cls):
def __init__(self):
pass
instance = Subclass()
attrs = Configurable.__filter(dir(instance))
for a in attrs:
aval = getattr(instance, a)
if isinstance(aval, ClassConfig):
result[a] = aval
return result
def __inst___fields(self):
"""
Get fields of an instance
"""
result = {}
cls = self.__class__
attrs = Configurable.__filter(dir(cls))
for a in attrs:
val = getattr(cls, a)
if isinstance(val, InstanceConfig):
result[a] = val
return result
#classmethod
#abstractmethod
def _file(cls):
"""
Returns the file
XXX: Implement by calling
super()._file(static_path)
"""
pass
#classmethod
def _file_path(cls, path, suffix=None):
"""
Returns the file relative to a path
"""
suffix = suffix if suffix != None else cls.__SUFFIX
f = ConfigFile(path + suffix)
f.create()
return f
def __inst____file(self):
"""
Returns the file
"""
return self.__file_
#classmethod
def load(cls):
"""
Loads the config file content, if not yet done into the class
"""
if not cls.__loaded:
return cls._force_load()
return True
def __inst_load(self):
"""
Loads the config file content, if not yet done into the instance
"""
if not self.__loaded:
return self._force_load()
return True
#classmethod
def _force_load(cls):
"""
Loads the config file's content to the class
"""
if cls._file().exists:
data = cls._file().dict()
else:
data = {}
fields = cls.__fields()
for field in fields:
val = data.get(field)
if val == None:
val = fields[field].default
else:
val = Configurable.__decode(val)
setattr(cls, field, val)
cls.__loaded = True
return True
def __inst__force_load(self):
"""
Loads the config file's content to the instance
"""
if self._file().exists:
data = self._file().dict()
else:
data = {}
fields = self.__fields()
for field in fields:
val = data.get(field)
if val == None:
val = fields[field].default
else:
val = Configurable.__decode(val)
setattr(self, field, val)
self.__loaded = True
return True
#classmethod
def store(cls):
"""
Writes class config to file
"""
result = True
fields = cls.__fields()
if not cls._file().exists:
cls._file().create()
for field in fields:
val = fields[field].value
set_result = cls._file().set(field,
Configurable.__encode(val))
result = False if not set_result else result
return result
def __inst_store(self):
"""
Writes instance config to file
"""
result = True
fields = self.__fields()
if not self._file().exists:
self._file().create()
for field in fields:
val = fields[field].value
set_result = self._file().set(field,
Configurable.__encode(val))
result = False if not set_result else result
return result

Resources