The top tag is a UDT instance. That's why they aren't the same it's not an actual atomic tag.
It looks like this code snippet is from a binding where you are passing in a dictionary with the property isRecursive into it.
You could simplify the code a little:
fltr={
'recursive' : value['isRecursive']
}
If you don't want the UDT defintion in the returned list, but do want the child tags then add tagType to the filter.
If you still have issues with the keys returned then you could filter the return keys with a requried list.
def transform(self, value, quality, timestamp):
fltr={
'recursive':True,
'tagType':'AtomicTag'
}
path = '[default]myTags'
fullTags = system.tag.browse(path,fltr)
requiredKeys = ['fullPath','value','name','fakeProp']
return [{k:tag.setdefault(k,None) for k in requiredKeys} for tag in fullTags]
My intention is to dispay tag properties of all child tags of different tag types from base parent path.
i guess you are right tag.browse usually use to return one type of tag. I could get all the unique key of list of dict and use python get method to return vale when key does not exist.
path = value['path']
fltr={}
fltr['recursive'] = value['isRecursive']
lod = system.tag.browse(path, fltr)
keys = list(set(key for d in lod for key in d.keys()))
newLod = []
for d in lod:
d0={}
for key in keys:
if key=="value":
d0[key] = d[key].getValue()
else:
d0[key] = str(d.get(key, ""))
newLod.append(d0)
return newLod
You don't have to convert the set to a list. In fact, sets are more efficient for membership checks
I'd keep the None and the actual datatype instead of converting to strings. You can manage how nulls appear in a table with the nullFormat prop:
maybe exclude folders ? lod = filter(lambda tag: tag['tagType'] is not tag['tagType'].UdtInstance, lod)
All in all, I'd probably write it like this:
lod = system.tag.browse(
value['path'],
filter={'recursive': value['isRecursive']}
)
lod = filter(lambda tag: tag['tagType'] is not tag['tagType'].Folder, lod)
keys = set(key for d in lod for key in d.keys())
data = [{k: d.get(k) for k in keys} for d in lod]
for d in data:
d['value'] = d['value'].value
return data
last thing: Pick a better name than lod. What does it mean ? The only idea I have is "List Of Dicts".
You are right no need to convert to list. During debuging, I return the 'set', but custom property returned a string. So I wrapped it with list. (forgot to remove them).
This is very true. I was avoiding more debug, so decide to set to harmless string.
Yes i came up with lod means "list of dictionary". ds for dataset.
For list i set to plural.
Very helpful, when my mind read lod, immediately i know it is literally a list of dict.
newLod = [{k: d.get(k) for k in keys} for d in lod]
But I see the expanded version is more flexible/reusable code in this case.
Why would you loop thru each key-value pair, if you won't do some processing.
In this case you can actually eliminate the loop after as well.
newLod = [{k: d.get(k).value if k == 'value' else d.get(k) for k in keys} for d in lod]
So the script as a whole could be:
lod =system.tag.browse(
value['path'],
filter={'recursive': value['isRecursive']}
)
lod = filter(lambda tag: tag['tagType'] in not tag['tagType'].Folder, log)
keys = set(key for d in log for key in d.keys())
return [{k: d.get(K).value if k == 'value' else d.get(K) for k in keys} for d in lod]
I missed this question when I last answered...
I find it more readable.
We build a list of dicts, because that's what we need.
Then we reprocess what needs to be reprocessed.
Yes, there are 2 loops when it could be done in one.
But I find it makes things clearer, and unless you're processing a lot of rows, I doubt you'll see any difference.
I usually write for clarity of intent first, then rewrite it if needed.
Note that I specifically say "of intent", which is not always the same a general readability.
It's a distinction I recently started to make, because some people will find iterative loops more generally readable than comprehensions, but I don't think anyone can argue that comprehensions WITH EXPLICIT NAMES don't convey the intent better.
This is also why I prefer using filter() than filtering in a comprehension: clarity of intent.
And it's also why I make helper functions with just one line.