String slicing in Python script

In my client startup script I am trying to capture the first four characters of the PC name with this script

HostName1 = system.tag.readBlocking('[System]Client/Network/Hostname') # Grab the whole host name, Should be EVRZ-HMI-NBurn for example.
print HostName1

HostPref = HostName1[0:3] # just grab the first four characters, this is an example of String Slicing.
print HostPref
print "Hello dummy"

print HostName1[:3]

According to the help, the string slice of HostName1[0:3] should work. But it just puts the whole string into HostPref. If I try HostName1[2] then it fails and says invalid index.
PS I don't know how to post the code snippet properly.

system.tag.readBlocking() returns a list of 'Qualified Value'. You need the first element [0], and you need the .value portion of this as a string.

system.tag.readBlocking('tagpath')[0].value

HostName1 = system.tag.readBlocking('[System]Client/Network/Hostname')[0].value
print HostName1

HostPref = HostName1[0:3] # just grab the first four characters, this is an example of String Slicing.
print HostPref
print "Hello dummy"

print HostName1[:3]
3 Likes

@ematschke, please see Wiki - how to post code on this forum.

3 Likes

The tagpath should also be in a list:

system.tag.readBlocking(['tagpath'])[0].value
2 Likes

It should still work if the tag path isn't a list. It can be a string of a single tag.

https://docs.inductiveautomation.com/display/DOC81/system.tag.readBlocking

1 Like

Yes, it does. What I should be saying is, 'Always do it the same darn way regarless of the number of tags. Then, there are no surprises.'

EDIT Sorry about that. Almost became Canadian.

EDIT 2: Apologies to all of my Canadian friends. At least I wasn't turning Scottish.
EDIT 3: Apologies to all my Scottish friends...

5 Likes

As long as you're not turning French...

@ematschke
People told you how to fix it, but I believe understanding what went wrong is the best way of understanding how to do it right, so... Here's a quick rundown of what was happening:

  • system.tag.readBlocking returns a list of qualified values
  • you were taking a slice of that list with [:3]
  • slicing doesn't raise any exceptions, even if you try getting a slice bigger than the actual list, so you got a list of just one qualified value, because you're fetching data for just one tag
  • when you tried printing hostName[:3], you printed that single element list. It should look like [[some_value, Good, some_date (timestamp)]]
    the outter brackets [] show that you're printing a list, and the inner [] are part of the representation of a qualified value. The 3 values are the actual value of the tag, its quality, and the timestamp indicating when it was last modified.
  • trying to access a particular element with [x] DOES raise an error if you're trying to access an element that doesn't exist (it raises an IndexError), which is why you got an error with HostName[2]

It should make it a bit clearer what steps you need to take if you want to slice the value of that tag:

data = system.tag.readBlocking([some_path]) # data is a list of qualified values

qval = data[0] # qval is the first item in the list

hostname = qval.value # hostname is the value extracted from the qualified value

sliced_string = hostname[:3] # now you can actually get the first 3 characters of that string

# putting it all together:
sliced_string = system.tag.readBlocking([some_path])[0].value[:3]
7 Likes

I forgot to mention that this is in Ignition 8.1. This code originally came from Ignition 7.9 where it worked. I obviously tried unsuccessfully to transition to the new methods in 8.1. Life was so much simpler then.... Thanks everyone for the insight. I will clean it up and let y'all know how it goes.

Even in 7.9, a tag read would return a qualified value.

https://docs.inductiveautomation.com/display/DOC79/system.tag.read

1 Like

Here is my old code from 7.9 that was working.

HostName1 = system.tag.read('[System]Client/Network/Hostname')	# Grab the whole host name, Should be LPCX_Vault45 for example.
HostPref = HostName1.value[:4]			# just grab the first four characters

Here is the new code in 8.1 and with some testing, either method works.

HostName1 = system.tag.readBlocking('[System]Client/Network/Hostname')[0].value		# Grab the host name VALUE, Should be 'EVRZ-HMI-NBurn' for example.
HostNamex = system.tag.readBlocking('[System]Client/Network/Hostname')				# Grab the whole host name, Should be [EVRZ-HMI-NBurn, good, Fri 11:08.....] for example.
HostPref = HostName1[0:4]			# grab the first four characters of the value, this is an example of String Slicing.
HostPrefx = HostNamex[0].value[0:4]	# grab the first four characters of the value of the first item in the List. (only one tag in the list anyway)

print HostPref
print HostPrefx
print HostName1						# this is just the value
print HostNamex[0].value			# this is the whole qualified list including value, quality, and timestamp and we are printing just the value part.

My question to the experts, What is the best way to implement, HostName1 or HostNamex in the above examples? Does it matter? I guess really the only difference between 7.9 and 8.1 is that now I need to specify the List item even though the List is only one tag.

No, not at all. Just use whatever maps into your head the most. I personally prefer HostName1 style for a single read.

1 Like

I prefer, @JordanCClark's advice so my preference for a single tag read is

system.tag.readBlocking(['[System]Client/Network/Hostname'])[0].value

Then it always work and I don't have to explain to someone new to Ignition why sometimes the function uses a list and sometimes it doesn't.

3 Likes