Putting a variable into a string (quote) python - python

I am facing a problem while calling the variable values within the double quote
Here's my code:
AccountID = ["1234567","5678912"]
for account in range(len(AccountID)):
response = sts.assume_role(RoleArn=(f"arn:aws:iam::{AccountID[account]}:role/Cloudbees_Jenkins"), RoleSessionName="learnaws-test-session")
print(response)
I have return response output with no variable values
File "test3.py", line 19
response = (RoleArn=(f"arn:aws:iam::{AccountID[account]}:role/Cloudbees_Jenkins"), RoleSessionName="learnaws-test-session")
^
SyntaxError: invalid syntax
how would i return an expected results like:
arn:aws:iam::1234567:role/Cloudbees_Jenkins
arn:aws:iam::5678912:role/Cloudbees_Jenkins

You could use f-strings, a very convenient way to refer to variables inside print statements in python.
In your case, it would look like this:
response = f"arn:aws:iam::{int(AccountID[0])}:role/Cloudbees_Jenkins"

response = (RoleArn=(f"arn:aws:iam::{AccountID[account]}:role/Cloudbees_Jenkins"), RoleSessionName="learnaws-test-session")
The problem here has nothing to do with generating the string.
The problem is that in Python the = (assignment) operator does not produce an output value.
So the expression RoleArn = ...a_bunch_of_stuff... only assigns that stuff to RoleArn. It doesn't produce any output value that can be assigned to response.
And the assignement RoleSessionName="learnaws-test-session" doesn't produce any return value that can be assigned to be part of the tuple that is being assigned to RoleArn.
So just break the code up into three lines:
RoleSessionName="learnaws-test-session"
RoleArn= f"arn:aws:iam::{AccountID[account]}:role/Cloudbees_Jenkins"
response = (RoleArn, RoleSessionName)
In recent Python versions (3.8 and newer) you can use the "walrus operator" := to both assign a value and return that value to be used in an expression, but in your code you should not because it IMO makes the code less clear.

AccountID = [1234567,5678912]
for i in AccountID:
print("arn:aws:iam::",i,"role/Cloudbees_Jenkins")

Related

Python - function calling exec() does not see variable

I have following script that works well on it's own, but once I wrap it all into a function does not return data.
The command changes based on input data structure. This is an example of the command I want to feed into the exec():
cross_data=pd.crosstab(src_data['result'],[src_data['c1'],src_data['c2']],normalize='index')
This is my function I want to wrap the code in and call:
def calcct(file_path='src_data.csv', separator = ",", res_col = 'result'):
#define function
src_data = csv_import(file_path, separator) #import data
reorder_cols = reorder_columns(src_data, res_col) #work with data
head_list=list(reorder_cols.columns.values) #get dataframe headers
# create command based on headers and execute that. Should return dataframe called cross_data.
exec(crosstabcmd(head_list))
return cross_data
Results in:
NameError: name 'cross_data' is not defined
I cannot seem to find the correct syntax for calling exec inside a function.
I tried defining and passing the cross_data variable, but I just get an error it doesnt see pandas when I do that.
Or is there some better way? I need to compose the command of 2-x column names, count and names of columns are variable.
First up
You probably don't mean to be using exec - that's a pretty low-level functionality! There isn't really enough context to understand how to fix this yet. Could you write out (in your question) what the crosstabcmd function looks like?
The error
NameError: name 'cross_data' is not defined
is because you've never defined a variable called cross_data in the scope of function calcct, i.e. you have never done cross_data = "something".
I'll give it a go
Assuming you have something like
import pandas as pd
def crosstabcmd(head_list):
# ? I can only guess what your crosstabcmd does, this won't work though
return pd.crosstab(*head_list, normalize='index')
then the solution would look like:
def calcct(file_path = 'src_data.csv', separator = ",", res_col = 'result'):
src_data = csv_import(file_path, separator) #import data
reorder_cols = reorder_columns(src_data, res_col) #work with data
head_list=list(reorder_cols.columns.values) #get dataframe headers
cross_data = crosstabcmd(head_list)
return cross_data
In my case I had main script which called a second script. I needed to use the "c" variable within the second script. Therefore I used locals(),loc as arguments for exec().
loc = {}
a = 10
b = 5
def abc(a,b):
qwerty = "c = %d + %d"%(a,b)
exec(qwerty, locals(), loc)
c = loc['c']
d = c+2
print(d)
abc(a,b)

Cannot use a variable that was returned from a function

Code is as follows:
def join_files(Fund):
Month_1 = pd.read_excel(Fund[0])
Month_2 = pd.read_excel(Fund[1])
Joined_1 = Month_1[["UNIQUE_ID","NET_AMOUNT"]].merge(Month_2[["UNIQUE_ID","NET_AMOUNT",]], on = "UNIQUE_ID", how = "left")
return Joined_1
join_files(GF)
print(Joined_1)
When I run the code, it gives me an error on the 'print(Joined_1)' line and says that it is an undefined name even though the code above runs successfully.
I know the function works since if I change the return statement to print() the output is printed.
That's because your variable of Joined_1 is contained with the join_files() function. After you return Joined_1, the value of that variable is returned (but not captured). Then you ask to print the variable, but at that point the script is no longer aware of the Joined_1 variable. I think you're looking for something more like this.
def join_files(Fund):
... // I haven't verified your your excel read logic
return(Joined_1)
ret_val = join_files(GF)
print(ret_val)
You could do a small test with this to get a template started for you:
def use_returned_value(some_val)
new_value = some_val
return new_value
return_value = use_returned_value(1234)
print(return_value)

eval after exec: seemingly same strings do not provide the same result (may be encoding problem)

I defined the _exec_ function for getting the output of a function represented by a string.
For instance the sgn function evaluated with the arg value (see code below).
Then I will have to perform a single eval in the end.
(Warning: exec or eval of unknown code must be secured before use.)
def _exec_(thecode):
local = {}
exec(thecode, globals(), local)
return local["_output_"]
sgn = "\nif _input_[0]<0:\n _output_ = -1\nif _input_[0]==0:\n _output_ = 0\nif _input_[0]>0:\n _output_ = 1"
arg = "[5]"
code_list = ["_input_ = "+arg+sgn]
print(eval("1+_exec_(code_list[0])"))
The last 2 lines provide the good result.
However I will have to use it for an undetermined number of times with various "string-functions" and "string-arguments".
Is it possible to do it with only 1 named string instead of a list of strings?
I tried:
code = "1+_exec_(_input_ = "+arg+sgn+")"
print(eval(code))
which lead to SyntaxError: invalid syntax.
Maybe the encoding of special characters is wrong, then I tried:
code = "1+_exec_(_input_ = "+arg+sgn.encode('unicode-escape').decode()+")"
print(eval(code))
which lead to SyntaxError: unexpected character after line continuation character.
I also tried to use the answer to Python: exec() a code block and eval() the last line, without success.
They aren't the same strings, "seemingly" or otherwise. Just take the eval out of both print(eval(...)) calls and compare:
>>> print("1+_exec_(code_list[0])")
1+_exec_(code_list[0])
vs:
>>> code = "1+_exec_(_input_ = "+arg+sgn+")"
>>> print(code)
1+_exec_(_input_ = [5]
if _input_[0]<0:
_output_ = -1
if _input_[0]==0:
_output_ = 0
if _input_[0]>0:
_output_ = 1)
That latter one doesn't look anything like something that might be expected to be valid syntax.

Python, how can I initialize a variable during function/method calls

In most interpreted languages (example given in psuedo PHP) I would be able to do something like this
function f($name, &$errors = null) {
if(something_wrong) {
if(!is_null($errors) {
$errors[] = 'some error';
}
return false;
}
}
if(!f('test', $errs = array()) {
print_r($errs);
}
And get a result like
Array
(
[0] => some error
)
However when I try this in Python
def f(name, errors = None):
if something_wrong:
if errors:
errors.append('some error')
return False
if not f('test', errs = []):
print str(errs)
I get an error
TypeError: f() got an unexpected keyword argument 'errs'
Which makes perfect sense in the context of Python thinking I am trying to set a specific argument, and not create a new variable altogether.
However if I try
if not f('test', (errs = [])):
print str(errs)
I get
f('test', (errs = []))
^
SyntaxError: invalid syntax
Because I think now it assumes I am trying to create a tuple.
Is there any way to keep this code on one line, or do I absolutely have to initialise the variable on it's own before passing it to the function/method? From what I can tell the only solution is this
errs = []
if not f('test', errs):
print str(errs)
It should be called as f(name, errors = []) or f(name, []). If you want to init with attribute name, python requires the variable key you given is same with any attribute name you declared in the function definition.
"In Python, assignment is a statement, not an expression, and can
therefore not be used inside an arbitrary expression."
see http://effbot.org/pyfaq/why-can-t-i-use-an-assignment-in-an-expression.htm

splitting up strings to x amount of characters

I am trying to make a decrypter that decrypts code from the encrypter I made. I am getting this type error when I run the code though
getcrypt = ''.join(map(Decrypt.get,split_up_into_sixteen_chars(x_str)))
TypeError: split_up_into_sixteen_cjars() takes 0 positional arguments but 1 was given
I'm fairly new to programming and not sure whats causing this.
heres my code
Decrypt = {'1s25FF5ML10IF7aC' : 'A', 1s2afF5ML10I7ac' : 'a'} #I obviously have more than this but I'm trying to make it as simplified as possible
def split_up_into_sixteen_chars():
while len(x_str)>0:
v = x_str[:16]
print(v)
x_str = (input())
getcrypt = ''.join(map(Decrypt.get,split_up_into_sixteen_chars(x_str)))
print(getcrypt)
You have defined a function that takes no parameters:
def split_up_into_sixteen_chars():
yet you are passing it one:
split_up_into_sixteen_chars(x_str)
You need to tell Python that the function takes one parameter here, and name it:
def split_up_into_sixteen_chars(x_str):
The name used does not have to match the name that you pass in for the function call, but it does have to match what you use inside the function. The following function would also work; all I did was rename the parameter:
def split_up_into_sixteen_chars(some_string):
while len(some_string) > 0:
v = some_string[:16]
print(v)
This works because the parameter some_string becomes a local name, local to the function. It only exists inside of the function, and is gone again once the function completes.
Note that your function creates an infinite loop; the length of some_string will either always be 0, or always be longer than 0. The length does not change in the body of the loop.
The following would work better:
def split_up_into_sixteen_chars(some_string):
while len(some_string) > 0:
v = some_string[:16]
print(v)
some_string = some_string[16:]
because then we replace some_string with a shorter version of itself each time.
Your next problem is that the function doesn't return anything; Python then takes a default return value of None. Printing is something else entirely, print() writes the data to your console or IDE, but the caller of the function does not get to read that information.
In this case, you really want a generator function, and use yield. Generator functions return information in chunks; you can ask a generator for the next chunk one by one, and that is exactly what map() would do. Change the function to:
def split_up_into_sixteen_chars(some_string):
while len(some_string) > 0:
v = some_string[:16]
yield v
some_string = some_string[16:]
or even:
def split_up_into_sixteen_chars(some_string):
while some_string:
yield some_string[:16]
some_string = some_string[16:]
because an empty string is 'false-y' when it comes to boolean tests as used by while and if.
As your map(Decrypt.get, ...) stands, if split_up_into_sixteen_chars() yields anything that is not present as a key in Dycrypt, a None is produced (the default value for dict.get() if the key is not there), and ''.join() won't like that. The latter method can only handle strings.
One option would be to return a string default instead:
''.join(map(lambda chunk: Decrypt.get(chunk, ''), split_up_into_sixteen_chars(x_str)))
Now '', the empty string, is returned for chunks that are not present in Decrypt. This makes the whole script work for whatever string input you have:
>>> x_str='Hello world!'
>>> ''.join(map(lambda chunk: Decrypt.get(chunk, ''), split_up_into_sixteen_chars(x_str)))
''
>>> x_str = '1s25FF5ML10IF7aC'
>>> ''.join(map(lambda chunk: Decrypt.get(chunk, ''), split_up_into_sixteen_chars(x_str)))
'A'

Categories

Resources