Getting "list assignment out of range" error when setting variable through exec or locals() - python-3.8

I am trying to change a variable by referring to it via a string.
The problem arises, when I try to replace a variable which before was was an array with length 1 with one that is longer ("list assignment out of range" is thrown when trying to assign a value to the second array element)
I tried using locals()[variable] = [-1, -1, -1] as well as exec(variable + ' = [-1, -1, -1]') to set the variable beforehand.
My code for reference:
exec('tmp = ' + variable) # save variable in case input gets reset
exec(variable + " = [-1, -1, -1]") # replace with 3-length array
try:
# set the first array element according to user input
exec(variable + '[0] = float(input("Enter lower bound for " + variable + ": "))')
except ValueError: # in case user is dumb
print("Invalid input")
exec(variable + ' = tmp')
continue
try:
# set the second array element according to user input (this line throws the error)
exec(variable + '[1] = float(input("Enter upper bound for " + variable + ": "))')
if eval(variable + '[1] < ' + variable + '[0]'): # more user safeguards
print("Value can't be lower than " + str(aq_p[0]))
exec(variable + ' = tmp')
continue
except ValueError:
print("Invalid input")
exec(variable + ' = tmp')
continue
For some context: It's about setting up a physics simulation where a dozen parameters have to be set (and later versions may include other parameters) which is why I want to keep the code as general as possible instead of hard-coding the input for every parameter. I wanted to avoid using a dictionary with all the parameters in it, as that may complicate other things and was hoping to be able to use locals() similarly.
As a side note: The continues in the code are for a larger loop which is too long to include here.

Related

Auto-send inputs to another python script

I have a python script that accepts 2 user inputs before it goes away and does something. I'm in a position where I now need to run the script multiple times, with different values for either of the 2 inputs. I'd rather not have to keep re-running the script and manually enter the values each time as I have over 100 different combinations.
I believe this can be done fairly fluidly in python.
Here is an example: input.py
import pandas as pd
# Variables for user input
print("Please enter your name: ")
UserInput = input()
name = str(UserInput)
print("Now enter your Job title: ")
UserInput2 = input()
job = str(UserInput2)
# Create filename with name and current date
currenttime = pd.to_datetime('today').strftime('%d%m%Y')
filename = name + '_' + currenttime + ".csv"
print('\nHi ' + name + '. ')
print('Hope your job as a ' + job + ' is going well.')
print("I've saved your inputs to " + filename)
print('Speak to you soon. Bye.')
# Create DataFrame, append inputs and save to csv
series = pd.Series({'Name ': name, 'Job Title ': job})
df = pd.DataFrame([series])
df.to_csv(filename, index=False)
Below is my attempt of auto-sending inputs to input.py using the subprocess module (might not be the correct approach). The file calls input.py successfully, but I cannot figure what other arguments I need to add to send the specified values.
Code used: auto.py
import subprocess
subprocess.run(['python', 'input.py'])
# These don't work
#subprocess.run(['python', 'input.py', 'Tim', 'Doctor'])
#subprocess.run(['python', 'input.py'], input=('Tim', 'Doctor'))
#subprocess.run(['python', 'input.py'], stdin=('Tim', 'Doctor'))
Ideally I want to have a list of the different inputs I want to send to the script so that it loops and adds the second batch of inputs, loops again then third batch and so on.
I'm unsure if I'm using correct subprocess method.
Any help would be greatly appreciated.
Use something like this in your input.py
import pandas as pd
import sys
# Variables for user input
UserInput = sys.argv[0]
name = str(UserInput)
UserInput2 = sys.argv[1]
job = str(UserInput2)
# Create filename with name and current date
currenttime = pd.to_datetime('today').strftime('%d%m%Y')
filename = name + '_' + currenttime + ".csv"
print('\nHi ' + name + '. ')
print('Hope your job as a ' + job + ' is going well.')
print("I've saved your inputs to " + filename)
print('Speak to you soon. Bye.')
# Create DataFrame, append inputs and save to csv
series = pd.Series({'Name ': name, 'Job Title ': job})
df = pd.DataFrame([series])
df.to_csv(filename, index=False)
auto.py will be
import subprocess
subprocess.run(['python', 'input.py','Tim', 'Doctor'])
let me know if that helps and I can modify your need accordingly.
auto.py output:

Dictionary Item not populating correctly

I am out of wits on this one. I have a list like below that is available on the fly. I want to be able to create an array or a collection so that I could use it further in a loop.
Xob::SISBTXTRPR-5298
Xob::SISBTXTRPR-5326
Xob::SISBTXTRPR-5327
Xob::SISBTXTRPR-5328
Yob::SISBTXTRPR-3999
Yob::SISBTXTRPR-4000
I have tried to create a dictionary item like below but the output is not what I am expecting
While i <= iPuntedIssuesCount
If sRemovedStoriesForTaskTracker.Exists(Trim(JSONObj("contents")("puntedIssues")(i)("assigneeName"))) Then
sRemovedStoriesForTaskTracker(Trim(JSONObj("contents")("puntedIssues")(i)("assigneeName"))) = sRemovedStoriesForTaskTracker(Trim(JSONObj("contents")("puntedIssues")(i)("assigneeName"))) & " + " & JSONObj("contents")("puntedIssues")(i)("key")
Else
sRemovedStoriesForTaskTracker.Add key:=Trim(JSONObj("contents")("puntedIssues")(i)("assigneeName")), Item:=JSONObj("contents")("puntedIssues")(i)("key")
End If
i = i + 1
Wend
sRemovedStoriesForTaskTracker is the dictionary item.
The output in the dictionary items that I am getting is like so:
Xob::SISBTXTRPR-5298 + SISBTXTRPR-5326 + SISBTXTRPR-5327 + SISBTXTRPR-5328.
I want the dictionary to populate like this
Xob::SISBTXTRPR-5298
Xob::SISBTXTRPR-5326
Xob::SISBTXTRPR-5327
Xob::SISBTXTRPR-5328
You don't show your source JSON, or how you're outputting the dictionary values, and your posted code doesn't seem to match what you say you want to do.
In any case, your code as-posted would benefit hugely from the use of a few variables as noted by #Damian. It's so dense it's difficult to follow.
While i <= iPuntedIssuesCount
Set d = JSONObj("contents")("puntedIssues")(i)
k = Trim(d("assigneeName"))
v = d("key")
If dictRemoved.Exists(k) Then
dictRemoved(k) = dictRemoved(k) & " + " & v
Else
dictRemoved.Add k, v
End If
i = i + 1
Wend

SSRS - Line break in Matrix cell

In a SSRS Matrix cell I want to be able to have a line break between each output given.
I have the following code in my MS SQL Server Stored Procedure which I then point my SSRS report to
SELECT Customer, Hostname, (QName + QHostname + Qtag + QSerial + QCategory + QType + QItem + QManu + QModel + QVersion) AS AdditionalInfo1
FROM TableQ
At the moment in the AdditionalInfo1 cell when one of the options is returned they are separated by a comma
e.g.
QName, QHostname, Qtag.
Instead I would like them to be separated by a line break all within the same cell
e.g.
QName
QHostname
Qtag
I have tried putting + char(13) + between each Q... in AdditionalInfo1 but this didn't work.
For SSRS, you want to use Chr(10), not Chr(13). I've used this in expressions and as a Join delimiter argument and it produced the desired effect: line breaks within the textbox.
Edit:
Below is an expression that will include the fields with line breaks if a value is present, or omit both if the field is null.
=Fields!QName.Value
+ IIF(ISNOTHING(Fields!QHostname.Value),"", vbCrLf + Fields!QHostname.Value)
+ IIF(ISNOTHING(Fields!Qtag.Value),"", vbCrLf + Fields!Qtag.Value)
+ IIF(ISNOTHING(Fields!QSerial.Value),"", vbCrLf + Fields!QSerial.Value)
+ IIF(ISNOTHING(Fields!QCategory.Value),"", vbCrLf + Fields!QCategory.Value)
+ IIF(ISNOTHING(Fields!QType.Value),"", vbCrLf + Fields!QType.Value)
+ IIF(ISNOTHING(Fields!QItem.Value),"", vbCrLf + Fields!QItem.Value)
+ IIF(ISNOTHING(Fields!QManu.Value),"", vbCrLf + Fields!QManu.Value)
+ IIF(ISNOTHING(Fields!QModel.Value),"", vbCrLf + Fields!QModel.Value)
+ IIF(ISNOTHING(Fields!QVersion.Value),"", vbCrLf + Fields!QVersion.Value)
Instead of concatenating all the 'Q' columns into a single string keep them as separate fields. Then create individual placeholders in a single cell, one for each field. You can do this quite quickly by clicking into the cell (which is rich TextBox) and typing the field name (as it appears in the DataSet) enclosed by square brackets
eg:
[QName]
[QHostname]
[Qtag]

How do I program a loop into a DDEPoke call on VBA?

I am attempting to program a loop into a DDEPoke call to a VBA-supported function known as OPC. This will enable me to write to a PLC (RSLogix 500) database from an excel spreadsheet.
This is the code:
Private Function Open_RsLinx()
On Error Resume Next
Open_RsLinx = DDEInitiate(RsLinx, C1)
If Err.Number <> 0 Then
MsgBox "Error Connecting to topic", vbExclamation, "Error"
OpenRSLinx = 0 'Return false if there was an error
End If
End Function
Sub CommandButton1_Click()
RsLinx = Open_RsLinx()
For i = 0 To 255
DDEPoke RsLinx, "N16:0", Cells(1 + i, 2)
Next i
DDETerminate RsLinx
End Sub
This code works and will, if there is a link set up with an OPC server (in this case through RSLinx) write data to the PLC.
The problem is that I can't get the part DDEPoke RsLinx, "N16:0", Cells(1 + i, 2) to write data, sequentially, from one excel cell to one element of the PLC's data array.
I tried to do DDEPoke RsLinx, "N16:i", Cells(1 + i, 2) and DDEPoke RsLinx, "N16:0+i", Cells(1 + i, 2) but neither has any effect and the program doesn't write anything at all.
How can I set up the code to get N16:0 to increment all the way up to N16:255 and then stop?
Break the variable i out of the string. Be careful for the implicit type conversion though, depending on which (Str() or CStr()), you'll wind up with a leading space. Thus, convert the number Str(i), then wrap with Trim() to make sure there's no extra spaces, and concatenate that result back to your "N" string:
RsLinx = Open_RsLinx()
For i = 0 To 255
DDEPoke RsLinx, "N16:" & Trim(Str(i)), Cells(1 + i, 2)
Next i
The reason the i didn't work when it's inside the string is because that in VBA, anything within a set of quotes is considered a literal string. Unlike some other languages (PHP comes to mind) where variables can be resolved within a string like that, VBA must have variables concatenated. Consider the following:
Dim s As String
s = "world"
Debug.Print "Hello s!"
This outputs the literal of Hello s! to the immediate window, because s is treated not as a variable, but as part of the literal string. The correct way is through concatenation:
Dim s As String
s = "world"
Debug.Print "Hello " & s & "!"
That outputs the expected Hello World! to the immediate window, because s is now treated as a variable and is resolved and concatenated.
If that were not the case, the following might be difficult to deal with:
Dim i As Integer
For i = 0 to 9
Debug.Print "this" & i
Next i
You would then have:
th0s0
th1s1
th2s2
th3s3
th4s4
'etc
That'd make things pretty difficult to manage in a lot of cases.
With all that said, there are some languages - notably PHP - where, when using a certain set of quotes (either "" or '' - I don't recall which offhand), in fact does resolve the variable when embedded into the string itself:
$i = 5;
echo "this is number $i";
VBA does not have this feature.
Hope it helps...

VB.Net Substring Error

At the moment, I have three different times that the following code is ran, back-to-back just with the variables changed:
txtCourseName.LoadFile(strRootLocation + "\subject\" + strSubject + "\" + "\class\" + cmbCourses.SelectedItem, RichTextBoxStreamType.PlainText)
aData = txtCourseName.Text
i = aData.IndexOf("<h3 class=""panel-title"">") + "<h3 class=""panel-title"">".Length
j = aData.IndexOf("</h3>") - i
txtCourseName.Text = aData.Substring(i, j)
For every time it is ran, the rich-text box that is being used is changed, aData is changed to bData, cData, etc., and the data that i and j are indexing is changed. It will run properly for the first two iterations, returning what it is supposed to into the text box, however on the third one, it gives me a System.ArgumentOutOfRangeException with the additional information of Length cannot be less than zero.
My only assumption for what could be causing this is that the third iteration, which I included below, is only supposed to find a 7-letter long string of characters and this is causing some math issues.
I have no idea how to fix this.
txtCourseNumber.LoadFile(strRootLocation + "\subject\" + strSubject + "\" + "\class\" + cmbCourses.SelectedItem, RichTextBoxStreamType.PlainText)
cData = txtCourseNumber.Text
i = cData.IndexOf("Course Number: </b>") + "Course Number: </b>".Length
j = cData.IndexOf("</li>") - i
txtCourseNumber.Text = cData.Substring(i, j)
Example Data That Is Returned By Each Iteration
aData - "English 4"
bData - "insert some really long course description here"
cData - "10045C"