Quantify labels with Names in them

Oh, ok, good to know sir. thanks

I would use what @PGriffith wrote, run it in script console to make that list in plain text, and copy and paste the tags over to the script.

What about a situation where you had a tag that was an exception to the rule where you did not want to include it's count? Easy enough with my hardcoded approach but now your list comprehension needs a caveat. Though I suppose there's an argument there to be made about overall tag structure as well if you have a exception to the rule then maybe it should not be there, but exceptions certainly exist in otherwise uniform structures, sometimes it just happens.

I think I am being nitpicky for sure, and I have used tag path generation on the fly in projects, but I've been thinking about the "idea" or "rightest" way to code for maintainability (either for myself or for others) and I think hardcoded tag paths and named queries are necessary for it.

Analogous to this is the rule of thumb in databases is you should not do SELECT * FROM table in a named query because what about if a column is added that is not supposed to be displayed or given to the client, well your query does it and now your table has an extra ugly squished column at the end.

I guess this is really a decision between convention over configuration vs hardcoding.

Sorry to derail the thread, I think this was an interesting topic about design decisions within Ignition that is not really talked asked about a lot on the forum.

1 Like

Strongly disagree. They are too easy to miss in a refactoring, or be a barrier to necessary refactoring.

On top of that, a one- or two-line comprehension is, IMNSHO, always easier to maintain than a five- or ten- or fifty-line string constant.

As for the occasional exception, you can always .append() afterwards, or use slicing to insert where needed. That really highlights that it is an exception, too.

Anyways, I think you are seriously harming whoever is stuck following in your footsteps, Brian.

1 Like

I have to admit that I'm horrified that {level} shows up twice in this pattern. This folder hierarchy totally sabotages commonality of names at all but the innermost levels, preventing effective use of the outer level folder as a tagpath parameter in overview templates/windows/views.

4 Likes

In the past when I was completely green and first learned about convention over configuration I thought it was amazing did a lot of it in our in-house program to the point where a new hire who completed the Inductive University was completely unable to do anything to our business logic scripts because a lot of the logic was hidden and other things were just "magically" taken care of.

That is obviously not the case here, this is just a list comprehension, but my own mistakes in the past that I had to undo have made me try to find the right balance between convention and configuration within Ignition and default to configuration when I am not sure - the one good thing about configuration is that it's all right there, there's nothing behind the scenes going on its just hardcoded exactly what it is doing.

I see your point about using an append or an index and I think that is fair.

To argue against myself earlier, if I had a hardcoded list of 200 line tags, I don't think anyone would be confused about what I am reading or writing to, its all right there hardcoded in your face. But the disadvantages would be comprehending what overall structure the list of tags represent, that would be very difficult for a person to read 200 strings and make sense vs reading the logic of a list comprehension is most likely easier.

What use cases are convention preferred and configuration preferred is something I am still trying to workout.

I would argue that it is an arbitrary distinction. In both cases, comments should explain what is going on.

1 Like

I don't write queries like this in all but the simplest of testing situations. Though I always approach it from a query optimization perspective rather than the unforeseen schema change, though that is also a good argument against.

This is exactly why I have a wrapper function that reads tag values and spits out a value dictionary where the key is the tag name. Then when it is used later in the code it's obvious (at least to me) what is happening.

1 Like

If you are disciplined enough to ensure tag names and tag folder names are valid python identifiers, you can wrap such a dictionary in a subclass that accepts property names as aliases for value keys. I use this one a great deal:

# Handy tool for objects as "bags of properties"
# by Peter Norvig, enhanced as a subclass of dict() by Philip J. Turmel
# http://norvig.com/python-iaq.html
class SmartMap(dict):
	def __repr__(self):
		args = []
		for (k,v) in self.items():
			if isinstance(v, basestring):
				args.append('%s=%s' % (k, v))
			else:
				try:
					z = len(v)
					args.append('%s=%s' % (k, type(v)))
				except:
					args.append('%s=%s' % (k, repr(v)))
		return 'SmartMap(%s)' % ', '.join(args)
	def __str__(self):
		args = []
		for k,v in self.items():
			if isinstance(v, basestring):
				args.append('%s=%s' % (k, v))
			else:
				try:
					z = len(v)
					args.append('%s=%s' % (k, repr(v)))
				except:
					args.append('%s=%s' % (k, str(v)))
		return 'SmartMap(%s)' % ', '.join(args)
	def clone(self):
		return type(self)(**self)
	def __getattr__(self, attr):
		if attr.startswith('__'):
			raise AttributeError(attr)
		if attr in self:
			return self[attr]
		return None
	def __setattr__(self, attr, val):
		if attr.startswith('__'):
			super.__setattr__(self, attr, val)
		self[attr] = val

This implementation is optimized to return None for missing keys, similar to javascript's behavior with missing properties.

Note that it is a dictionary, and can be initialized like any other dictionary. Just don't put this in a persistent global dictionary.

3 Likes