I am trying to build a tree from a list of objects, which are characterised by several properties.
Each object can have 3 properties that play a role in building a tree, that is velocity altitude exposure.
#Data structure
class Test():
pass
tests = []
for el in data:
test = Test()
test.velocity = el[0] #100km/h or 120km/h or 140km/h
test.altitude = el[1] #20m or 40m or 60m
test.exposure = el[2] #10uSv or 20uSv or 30uSv
#more data is assigned which is not shown as irrelevant
tests.append(test)
# I am trying to build a data tree like the one below.
# Obviously it would be different than this one and depend on actual data input.
# Example built statically using anytree
Tests
├── 100km/h
│ ├── 20m
│ │ └── 10uSv
│ ├── 40m
│ │ └── 10uSv
│ └── 60m
│ └── 20uSv
├── 120km/h
│ ├── 40m
│ │ ├── 20uSv
│ │ └── 30uSv
│ └── 60m
│ ├── 20uSv
│ └── 30uSv
└── 140km/h
└── 20m
└── 30uSv
Although this problem looks simple (might not be) I just can not figure it out.
Cheers!
You dont provide original data, so I tried to guess them.
I started with constructing nested dicts and then converting them to anytree format with recursive function.
Here is the code:
import itertools
import anytree
data = [
['100km/h', '20m', '10uSv'],
['100km/h', '40m', '10uSv'],
['100km/h', '60m', '20uSv'],
['120km/h', '40m', '20uSv'],
['120km/h', '40m', '30uSv'],
['120km/h', '60m', '20uSv'],
['120km/h', '60m', '30uSv'],
['140km/h', '20m', '30uSv'],
]
# Construct nested dicts
res = {'Tests': {}}
for a, b, c in data:
res['Tests'].setdefault(a, {}).setdefault(b, {}).setdefault(c, True)
__import__('pprint').pprint(res)
# {'Tests': {'100km/h': {'20m': {'10uSv': True},
# '40m': {'10uSv': True},
# '60m': {'20uSv': True}},
# '120km/h': {'40m': {'20uSv': True, '30uSv': True},
# '60m': {'20uSv': True, '30uSv': True}},
# '140km/h': {'20m': {'30uSv': True}}}}
# Convert nested dicts to anytree format
def dict_to_tree(d, parent=None):
if isinstance(d, bool):
return
for key in d:
node = anytree.Node(key, parent)
dict_to_tree(d[key], node)
root = anytree.Node('Tests')
dict_to_tree(res['Tests'], root)
for pre, fill, node in anytree.RenderTree(root):
print(f'{pre}{node.name}')
# Tests
# ├── 100km/h
# │ ├── 20m
# │ │ └── 10uSv
# │ ├── 40m
# │ │ └── 10uSv
# │ └── 60m
# │ └── 20uSv
# ├── 120km/h
# │ ├── 40m
# │ │ ├── 20uSv
# │ │ └── 30uSv
# │ └── 60m
# │ ├── 20uSv
# │ └── 30uSv
# └── 140km/h
# └── 20m
# └── 30uSv
Related
A little backstory: I'm making a multitool for a bigger program but ran into an issue that I really can't get my head around. It's just print statements that are used for showing the user all the avalible options. I apologise if there's any wrong grammar or if I've misspelled some words, if something is unreadable feel free to let me know and I can explain what I meant.
Problem: I want them to get printed on the same row under the credline_mid. Pic 1 = How it prints it Pic 2 = a recreation made in paint that shows how I want to have it. Any help that could be given would be much appreciated.
[Pic 1]
[Pic 2]
Code:
def logo_mid():
print(Fore.MAGENTA + r"""____/\\\_______/\\\_____________________________/\\\\\\\\\\\\\\\_________________________________/\\\\\\______
___\///\\\___/\\\/_____________________________\///////\\\/////_________________________________\////\\\______
_____\///\\\\\\/_____________________________________\/\\\_________________________________________\/\\\______
_______\//\\\\___________________/\\\\\\\\\\\________\/\\\____________/\\\\\_________/\\\\\________\/\\\______
________\/\\\\__________________\///////////_________\/\\\__________/\\\///\\\_____/\\\///\\\______\/\\\______
________/\\\\\\______________________________________\/\\\_________/\\\__\//\\\___/\\\__\//\\\_____\/\\\______
______/\\\////\\\____________________________________\/\\\________\//\\\__/\\\___\//\\\__/\\\______\/\\\______
____/\\\/___\///\\\__________________________________\/\\\_________\///\\\\\/_____\///\\\\\/_____/\\\\\\\\\___
___\///_______\///___________________________________\///____________\/////_________\/////______\/////////____""")
def credline_mid():
print("""
_____________________________________________Made by [EN/SWE] PewPew#4450______________________________________________""")
def fav_options():
print("""
╔═══════════════╗
║ Favorites ║
╠══╦════════════╣
│1 │Inject │
│2 │Reinstall │
│3 │Quit X-Tool │
└──┴────────────┘""", end='')
def installer_options():
print("""
╔══════════════════╗
║ File installer ║
╠══╦═══════════════╣
│4 │Visuals │
│5 │Translations │
│6 │ASI plugins │
│7 │LUA scripts │
│8 │UI configs │
│9 │XML maps │
│10│Vehicles │
│11│Outfits │
│12│Headers │
└──┴───────────────┘""", end='')
def delete_options():
print("""
╔══════════════════╗
║ Delete Options ║
╠══╦═══════════════╣
│13│Translations │
│14│Hotkeys │
│15│Saved options │
│16│Headers │
│17│ASI Files │
│18│LUA Scripts │
│19│Reinstall │
└──┴───────────────┘""", end='')
def social_options():
print("""
╔══════════════════╗
║ Social Links ║
╠══════════════════╣
│ X-Force Socials │
├──┬───────────────┤
│20│Youtube Channel│
│21│Discord Server │
│22│Dashboard │
│23│Forum │
├──┴───────────────┤
│ My Own Socials │
├──┬───────────────┤
│24│Shop │
│25│Youtube Channel│
│26│Discord Server │
└──┴───────────────┘""", end='')
def misc_options():
print("""
╔══════════════════╗
║ Misc ║
╠══╦═══════════════╣
│27│X-Tool Tutorial│
│28│Credits │
│29│X-Tool Support │
│30│Update checker │
│31│Changelog │
│32│Dev-Mode │
│33│Quit X-Tool │
│34│Inject │
└──┴───────────────┘""", end='')
def settings_options():
print("""
╔════════════════════╗
║ Settings ║
╠══╦═════════════════╣
│35│UI-Editor │
│36│Sound Editor │
│37│Favorites Editor │
│38│Reset X-Tool │
│39│Hotkeys │
└──┴─────────────────┘""", end='')
logo_mid()
credline_mid()
fav_options()
installer_options()
delete_options()
social_options()
misc_options()
settings_options()
I've tried putting end='' on the end of the print statement but didnt work.
Then I looked for some stack overflow threads that fit my problem, unfortunately I didn't find anything.
Lastly I tried using our beloved friend chatgpt but unfortunately no help there.
First, seprate menus into just strings
fav_options = """╔═══════════════╗
║ Favorites ║
╠══╦════════════╣
│1 │Inject │
│2 │Reinstall │
│3 │Quit X-Tool │
└──┴────────────┘""";
installer_options = """╔══════════════════╗
║ File installer ║
╠══╦═══════════════╣
│4 │Visuals │
│5 │Translations │
│6 │ASI plugins │
│7 │LUA scripts │
│8 │UI configs │
│9 │XML maps │
│10│Vehicles │
│11│Outfits │
│12│Headers │
└──┴───────────────┘""";
Then make a list of them , and place them in a 2D array
menus = [fav_options, installer_options]
full_menu = [m.splitlines() for m in menus]
And iterate each line, replacing None (returned from zip_longest when the zip is out of range) with the width of the column.
from itertools import zip_longest
for row in zip_longest(*full_menu):
line = []
for i, menu in enumerate(row):
if menu == None:
line.append(' ' * len(full_menu[i][0])) # get width of menu header
else:
line.append(menu)
print(' '.join(line))
Example output
╔═══════════════╗ ╔══════════════════╗
║ Favorites ║ ║ File installer ║
╠══╦════════════╣ ╠══╦═══════════════╣
│1 │Inject │ │4 │Visuals │
│2 │Reinstall │ │5 │Translations │
│3 │Quit X-Tool │ │6 │ASI plugins │
└──┴────────────┘ │7 │LUA scripts │
│8 │UI configs │
│9 │XML maps │
│10│Vehicles │
│11│Outfits │
│12│Headers │
└──┴───────────────┘
the "multitool" is controlled either thrue voice controll, inputing a number
You could run an REST API, or other RPC server and still send requests to that via voice... You ideally would not use input() for that.
I am trying to create a leetcode like online judge. I need to reload the submission module but import.reload() does not work.
The code:
class Test:
current_exercise = None
current_name = None
def _import(self, exercise):
exercise = 'exercise' # for testing
if exercise == self.current_name:
module = sys.modules[f'puzzles.{exercise}']
self.current_exercise = importlib.reload(module) # <---- not working
else:
self.current_name = exercise
self.current_exercise = __import__(f'puzzles.{exercise}').exercise
def _test(self, exercise):
solution = self._import(exercise)
print(self.current_exercise.main())
if __name__=='__main__':
import shutil
t= Test()
# first run
t._test('exercise')
# copy another solution.py for reload test
shutil.copy(f"./puzzles/other_exercise/solution.py", f"./puzzles/exercise/solution.py")
# second run
t._test('exercise')
My directory;
.
├── codetest.py
├── puzzles
│ ├── __init__.py
│ ├── exercise
│ │ ├── __init__.py
│ │ ├── solution.py
│ ├── other_exercise
│ │ ├── __init__.py
│ │ ├── solution.py
exercise/solution.py:
def main():
print('EXERCISE')
exercise/init.py
from .solution import main
from .test import cases
other_exercise/solution.py:
def main():
print('OTHER EXERCISE')
Output:
> EXERCISE
> EXERCISE # <--- not sucessfull, should be 'OTHER EXERCISE'
This works:
import sys
import time
import importlib
class Test:
current_exercise = None
current_name = None
def _import(self, exercise):
if exercise == self.current_name:
self.current_exercise.solution = importlib.reload(self.current_exercise.solution)
else:
self.current_name = exercise
self.current_exercise = importlib.import_module(f'puzzles.{exercise}')
print('mod',self.current_exercise)
print('nam',self.current_exercise.__name__)
print('fil',self.current_exercise.__file__)
print('pkg',self.current_exercise.__package__)
def _test(self, exercise):
solution = self._import(exercise)
print(self.current_exercise.solution.main())
if __name__=='__main__':
import shutil
shutil.copy(f"./puzzles/exercise/solution.0", f"./puzzles/exercise/solution.py")
t= Test()
# first run
t._test('exercise')
# copy another solution.py for reload test
shutil.copy("./puzzles/other_exercise/solution.py", "./puzzles/exercise/solution.py")
print(open("./puzzles/exercise/solution.py").read())
# second run
t._test('exercise')
I went with an alternative; load solution.py as a text and create a module from that string. The module is not registered in sys.modules and can be overwritten. However imp is deprecated.
import imp
class Test:
current_exercise = None
def _import(self, exercise):
# load module code
with open(f'./puzzles/{exercise}/solution.py') as f:
code = f.read()
# register/create the module
self.current_exercise = imp.new_module('mymodule')
# import/fill the module
exec(code, self.current_exercise.__dict__)
def _test(self, exercise):
self._import(exercise)
print(self.current_exercise.main())
I take notes with cherrytree, an hierarchical note taking application written in python. A shortcut allows to insert date node, and the structure of date nodes in the tree is as follows:
├─ year
│ └─ month1
│ │ └─ day1
│ │ └─ day2
│ └─ month2
├─ year2
├─ a user node
I'd like to insert date nodes in a parent node named "journal" or whatever, as follows:
├─ journal
│ └─ year1
│ │ └─ month1
│ │ │ └─ day1
│ │ └─ month2
│ └─ year2
├─ a user node
The function node_date in core.py is:
def node_date(self, *args):
"""Insert Date Node in Tree"""
now_year = time.strftime("%Y").decode(locale.getlocale()[1])
now_month =time.strftime("%B").decode(locale.getlocale()[1])
now_day = time.strftime("%A %d %B %Y").decode(locale.getlocale()[1])
#print now_year, now_month, now_day
if self.curr_tree_iter:
curr_depth = self.treestore.iter_depth(self.curr_tree_iter)
if curr_depth == 0:
if self.treestore[self.curr_tree_iter][1] == now_year:
self.node_child_exist_or_create(self.curr_tree_iter, now_month)
self.node_date()
return
else:
if self.treestore[self.curr_tree_iter][1] == now_month\
and self.treestore[self.treestore.iter_parent(self.curr_tree_iter)][1] == now_year:
self.node_child_exist_or_create(self.curr_tree_iter, now_day)
return
if self.treestore[self.curr_tree_iter][1] == now_year:
self.node_child_exist_or_create(self.curr_tree_iter, now_month)
self.node_date()
return
self.node_child_exist_or_create(None, now_year)
self.node_date()
Could someone help me to adapt it? I'm not a developer (my skills in python stop at modifying now_day date format in the way I prefer...), and I'd like to separate notes and journal nodes, without having to move manually the date node automatically created by shortcut. Thank you for your help.
I got help on a project repo issue. My node_date method is now:
def node_date(self, *args):
"""Insert Date Node in Tree"""
top_node = "journal"
now_year = time.strftime("%Y").decode(locale.getlocale()[1])
now_month =time.strftime("%Y-%B").decode(locale.getlocale()[1])
now_day = time.strftime("%A %d %B %Y").decode(locale.getlocale()[1])
#print now_year, now_month, now_day
self.node_child_exist_or_create(None, top_node)
self.node_child_exist_or_create(self.curr_tree_iter, now_year)
self.node_child_exist_or_create(self.curr_tree_iter, now_month)
self.node_child_exist_or_create(self.curr_tree_iter, now_day)
As I said to the contributor, I don't understand why all thoses if/else in the project code while his solution is so simple, but for now it seems to work in the way I wanted.
I have a problem, below is my root tree:
In my root I have that:
---dir1---sub1(images exif time 10:05:05 to 10:09:55)
---sub2(images exif time 10:11:15 to 10:15:42)
---sub3(images exif time 10:22:15 to 10:24:41)
---sub4(images exif time 10:28:15 to 10:35:40)
---dir2---sub1(images exif time 10:05:06 to 10:09:57)
---sub2(images exif time 10:11:15 to 10:15:40)
---sub3(images exif time 10:22:15 to 10:24:43)
---sub4(images exif time 10:28:15 to 10:35:40)
---sub5(images exif time 10:40:15 to 10:43:40)
---dir3---sub1(images exif time 10:05:05 to 10:09:54)
---sub2(images exif time 10:11:15 to 10:15:40)
---sub3(images exif time 10:22:15 to 10:24:41)
---sub4(images exif time 10:28:15 to 10:35:40)
---sub5(images exif time 10:40:15 to 10:43:42)
---dir4---sub1(images exif time 10:05:06 to 10:09:57)
---sub2(images exif time 10:11:15 to 10:15:40)
---sub3(images exif time 10:22:15 to 10:24:43)
---sub4(images exif time 10:28:15 to 10:35:40)
---sub5(images exif time 10:40:15 to 10:43:40)
---dir5---sub1(images exif time 10:05:05 to 10:09:54)
---sub2(images exif time 10:11:15 to 10:15:40)
---sub3(images exif time 10:22:15 to 10:24:41)
---sub4(images exif time 10:28:15 to 10:35:40)
---sub5(images exif time 10:40:15 to 10:43:42)
I have 5 dirs in my root and each contains sub-folders(with images) number of sub-folders it's not a same all the time, What I want to do is from first - dir1 get sub1 and put it to new destination folder after go to next dir (dir2) scan sub-folders to check exif(time) if its a same as sub1 from dir1 and copy it to same directory after go to next dir3 and do same for all others dir-s and subfolders, and after create newdir2 go and take sub2 from dir1 and do again same loop till end...
something like:
---newdir1---sub1(from dir1)
---sub1(from dir2)
---sub1(from dir3)
---sub1(from dir4)
---sub1(from dir5)
---newdir2---sub2(from dir1)
---sub2(from dir2)
---sub2(from dir3)
---sub2(from dir4)
---sub2(from dir5)
---newdir3---sub3(from dir1)
---sub3(from dir2)
---sub3(from dir3)
---sub3(from dir4)
---sub3(from dir5)
---newdir4---sub4(from dir1)
---sub4(from dir2)
---sub4(from dir3)
---sub4(from dir4)
---sub4(from dir5)
---newdir5---sub5(from dir2)
---sub5(from dir3)
---sub5(from dir4)
---sub5(from dir5)
I have a part of script with sort my images to dictionary by some time interval, how I can join it to my script?? to get my sub-s with same key to same dir ??:
import os
import exifread
from datetime import datetime, timedelta
TIME_RANGE = 2
src_root = 'F:\gopro_egouts\gopro_img_test\\2018-03-06'
dst_root = src_root + '-copie'
src_dirs_dict = {}
for cam_dir in os.listdir(src_root):
laps_root = os.path.join(src_root, cam_dir)
for lap_dir in os.listdir(laps_root):
files_root = os.path.join(laps_root, lap_dir)
min_time = None
max_time = None
for cam_file in os.listdir(files_root):
with open(os.path.join(files_root, cam_file), 'rb') as f:
tags = exifread.process_file(f, details=False, stop_tag="EXIF DateTimeOriginal")
time_taken = tags.get("EXIF DateTimeOriginal")
if time_taken:
file_time = datetime.strptime(str(time_taken), '%Y:%m:%d %H:%M:%S')
if min_time is not None:
if file_time < min_time:
min_time = file_time
else:
min_time = file_time
if max_time is not None:
if file_time > max_time:
max_time = file_time
else:
max_time = file_time
is_key = None
for key in src_dirs_dict.keys():
if (min_time >= key[0] and min_time < key[1]) \
or (max_time >= key[0] and max_time < key[1]):
is_key = key
break
min_time = min_time.replace(second=0)
max_time = min_time + timedelta(minutes=TIME_RANGE)
if is_key:
key_min, key_max = is_key
if min_time < key_min:
key_min = min_time
if max_time > key_max:
key_max = max_time
new_key = (key_min, key_max)
if new_key == is_key:
src_dirs_dict[new_key].append(files_root)
else:
src_dirs_dict[new_key] = src_dirs_dict.pop(is_key) + [files_root]
else:
new_key = (min_time, max_time)
src_dirs_dict[new_key] = [files_root]
print(src_dirs_dict)
My print showing me that:
{(datetime.datetime(2018, 3, 6, 10, 31), datetime.datetime(2018, 3, 6, 10, 32)): ['F:\\gopro_egouts\\gopro_img_test\\2018-03-06\\CAM0101 1\\Time Lapse 3',...
I have a working script with working well but taking a sub-folders one by one , and when some Time-lapse is missing, there I have a problem, his mixing my sub-s(automatically taking next one from next dir with wrong time), where I have to add my exif script from above to here(how modify it)... how to join it together???
Any help will be appreciated.
from collections import defaultdict
import shutil
import os
import re
src_root = r'F:\gp\gp_test\\2018-03-06'
dst_root = src_root + '-copie'
#os.makedirs(dst_root, exist_ok=True)
src_dirname, src_folders, _ = next(os.walk(src_root))
src_folders = sorted(src_folders)
src_folders = [os.path.join(src_root, folder) for folder in src_folders]
print(src_folders)
job = defaultdict(list)
print('mes {} dossier cam'.format(len(src_folders)))
for folder in src_folders:
print()
dirname, src_sub_folders, _ = next(os.walk(os.path.join(src_dirname, folder)))
src_sub_folders = sorted(src_sub_folders, key=lambda x: [re.search(r'(\D+)', x).group(1)] + list(map(int, re.findall(r'\d+', x))))
print("mes 5 CAM avec {} time laps '{}'".format(len(src_sub_folders), folder))
for index, sub_folder in enumerate(src_sub_folders, start=1):
job['Time Lapse-{}'.format(index)].append(os.path.join(dirname, sub_folder))
#print()
for dst_folder, src_folders in sorted(job.items()):
for index, src_folder in enumerate(src_folders, start=1):
dst_new_folder = os.path.join(dst_root, dst_folder, 'CAM-{}'.format(index))
print('{} -> {}'.format(src_folder, dst_new_folder))
shutil.copytree(src_folder, dst_new_folder)
#shutil.rmtree(src_root)
for root, dirs, files in os.walk(dst_root):
for f in files:
prefix = os.path.basename(root)
prefix1 = os.path.basename(src_root)
os.rename(os.path.join(root, f), os.path.join(root, "{}-{}-{}".format(prefix1, prefix, f)))
print("images rennomer ")
print("fini")
print("dossier supprimé")
I'm really sorry if that will be not to clear for users, but English it's not my strongest language ...
In a nutshell, you have images of the same set of events shot on a number of cameras.
Currently, they are grouped first by camera, then by event:
├── Camera1
│ ├── Event1
│ ├── Event2
│ ├── Event3
│ ├── Event4
│ └── Event5
├── Camera2
│ ├── Event1
│ ├── Event2
│ ├── Event3
│ ├── Event4
│ └── Event5
├── Camera3
│ ├── Event1
│ ├── Event2
│ ├── Event3
│ ├── Event4
│ └── Event5
├── Camera4
│ ├── Event1
│ ├── Event2
│ ├── Event3
│ ├── Event4
│ └── Event5
└── Camera5
├── Event1
├── Event2
├── Event3
├── Event4
└── Event5
... where some events may be missing and the event numbering may not match because one or more events may not be recorded by all cameras.
And you want the same set of images grouped first by event, then by camera:
├── Event1
│ ├── Camera1
│ ├── Camera2
│ ├── Camera3
│ ├── Camera4
│ └── Camera5
├── Event2
│ ├── Camera1
│ ├── Camera2
│ ├── Camera3
│ ├── Camera4
│ └── Camera5
├── Event3
│ ├── Camera1
│ ├── Camera2
│ ├── Camera3
│ ├── Camera4
│ └── Camera5
├── Event4
│ ├── Camera1
│ ├── Camera2
│ ├── Camera3
│ ├── Camera4
│ └── Camera5
└── Event5
├── Camera1
├── Camera2
├── Camera3
├── Camera4
└── Camera5
Here's an idea... I am kind of "thinking aloud" in pseudo-code:
Create the output directories {Event1..EventN}/Camera{1..N}
MissingDirectory=false
for each input directory Camera{1..N}
if this directory has the full number of subdirectories
copy all subdirectories to output area
else
MissingDirectory=true
end if
end for
if MissingDirectory
for each output Event directory
get times of all files from all cameras for current event
sort list and take median time of current event
end for
for each un-copied input directory
get the mean time of all the files in it
assign this directory's files to output directory with nearest median time
end for
endif
You can convert your EXIF times to pure seconds since midnight (s) with:
s = (hours*3600) + (minutes*60) + seconds
Here's a way to get the time (in seconds since midnight) that an image was taken:
import exifread
def getImageTime(filename):
"Read EXIF data of given file and return time in seconds since midnight"
f=open(filename,'rb')
tags=exifread.process_file(f)
DateTime=tags["EXIF DateTimeOriginal"].printable
# DateTime looks like: "2013:03:09 08:59:50"
Time=DateTime.split()[-1]
# Time looks like: "08:59:50"
h,m,s=Time.split(":")
# Return seconds since midnight: 32390
return (int(h)*3600) + (int(m)*60) + int(s)
s=getImageTime("image.jpg")
print(s)
After some more thought, this won't work very well if one of the cameras is set, say, 20 minutes different from the others, since all its images from all the sequences will tend to get put into the first or last directory. Needs some more thought...
With python and unittest I have this structure of test directory:
tests/
__init__.py
test_001.py
data/
data_001_in.py
data_001_out.py
where
data_001_in.py : the input data to use in the functions to test
data_001_out.py : the output data expected from the function to test
I have the inputs and outputs in python dictionaries because it is easier for me than using json, sqlite, etc.
I try use a set of input/output data with the same format and apply the test over each pair of data:
tests/
__init__.py
test_001.py
data/
data_001_in.py
data_001_out.py
data_002_in.py
data_002_out.py
data_003_in.py
data_003_out.py
Is there any package/approach to make this task more easier?
inspirated in the question nose, unittest.TestCase and metaclass: auto-generated test_* methods not discovered, I solved with a metaclass. First, I change the directory data structure to
├── data
│ ├── __init__.py
│ ├── data001
│ │ ├── __init__.py
│ │ ├── datain.py
│ │ ├── dataout.py
│ └── data002
│ ├── __init__.py
│ ├── datain.py
│ ├── dataout.py
└── metatest.py
Second, I make a metaclass for create new test with the data in the subdirectories and base tests.
import unittest
import os
import copy
def data_dir():
return os.path.join(os.path.dirname(__file__), 'data')
def get_subdirs(dir_name):
""" retorna subdirectorios con path completo"""
subdirs = []
for f in os.listdir(dir_name):
f_path = os.path.join(dir_name, f)
if os.path.isdir(f_path):
subdirs.append(f)
return subdirs
def get_data_subdirs():
return get_subdirs(data_dir())
def data_py_load(file_name):
""" carga diccionario data desde archivo .py """
name = file_name.split('.py')[0]
path_name = 'data.' + name
exec_str = "from {} import *".format(path_name)
exec(exec_str)
return data
class TestDirectories(type):
def __new__(cls, name, bases, attrs):
subdirs = get_data_subdirs()
callables = dict([
(meth_name, meth) for (meth_name, meth) in attrs.items() if
meth_name.startswith('_test')
])
data = {}
for d in subdirs:
data[d] = {}
data[d]['name'] = d
out_path = "{}.dataout.py".format(d)
data[d]['out'] = data_py_load(out_path)
var_path = "{}.datain.py".format(d)
data[d]['in'] = data_py_load(var_path)
for meth_name, meth in callables.items():
for d in subdirs:
new_meth_name = meth_name[1:]
# name of test to add, _test to test
test_name = "{}_{}".format(new_meth_name, d)
# deep copy for dictionaries
testeable = lambda self, func=meth, args=copy.deepcopy(data[d]): func(self, args)
attrs[test_name] = testeable
return type.__new__(cls, name, bases, attrs)
class TestData(unittest.TestCase):
__metaclass__ = TestDirectories
def _test_name(self, data):
in_name = data['in']['name']
out_name = data['out']['name']
print in_name, out_name
self.assertEquals(in_name, out_name)
if __name__ == '__main__':
unittest.main(verbosity=2)
And, when I run
$ python metatest.py
test_name_data001 (__main__.TestData) ... Alice Alice
ok
test_name_data002 (__main__.TestData) ... Bob Bob
ok
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK