How to open a file passed in the command line arguments - python

I have my config encoded here:
#staticmethod
def getConfig(env):
pwd=os.getcwd()
if "win" in (platform.system().lower()):
f = open(pwd+"\config_"+env.lower()+"_data2.json")
else:
f = open(pwd+"/config_"+env.lower()+"_data2.json")
config = json.load(f)
f.close()
return config
#staticmethod
def isWin():
if "win" in (platform.system().lower()):
return True
else:
return False
I have 2 JSON files I want my script to read, but the way it's written above it only reads 1 of them. I want to know how to change it to something like:
f = open(pwd+"\config_"+env.lower()+"_data_f'{}'.json")
so it can read either dataset1.config or dataset2.config. I'm not sure if this is possible, but I want to do that so I can specify which file to run in the command line: python datascript.py -f dataset1.config or python datascript.py -f dataset2.config. Do I assign that entire open() call to a variable?

All you need to do is parse sys.argv to get the argument of the -f flag, then concatenate the strings and pass the result to open(). Try this:
import sys
### ... more code ...
#staticmethod
def getConfig(env):
pwd = os.getcwd()
file = None
try:
file = sys.argv[sys.argv.index('-f')+1]
except ValueError:
file = "data2.json"
if "win" in (platform.system().lower()):
f = open(pwd+"\config_"+env.lower()+"_" + file)
else:
f = open(pwd+"/config_"+env.lower()+"_" + file)
config = json.load(f)
f.close()
return config
sys.argv.index('-f') gives the index of -f in the command line arguments, so the argument must be filename. The try-except statement will provide a default value if no -f argument is given.

Related

How do I pass arguments from command line to the python script to read and update values of certain keys present in a json file

I have certain data in a json file (say, example.json),
example.json
data = {
'name' : 'Williams',
'working': False,
'college': ['NYU','SU','OU'],
'NYU' : {
'student' : True,
'professor': False,
'years' : {
'fresher' : '1',
'sophomore': '2',
'final' : '3'
}
}
}
I wish to write a code wherein I can give the arguments on Command line, i.e. suppose if a script is saved in a file 'script.py', then,
In the terminal: If I enter *$ python3* script.py --get name --get NYU.student Then it outputs name=Williams
NYU.student=True
If I enter *$ python3* script.py' --set name=Tom --set NYU.student=False
Then, it updates name and NYU.student keys in the dictionay to Tom and False and outputs NYU.student=Tom and NYU.student=False on the command line.
I have tried the following code for the python script (i.e. script.py)
script.py
import json
import pprint
import argparse
if __name__== "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--get", help="first command")
parser.add_argument("--set", help="second command")
args=parser.parse_args()
with open('example.json','r') as read_file:
data=json.load(read_file)
if args.set == None:
key = ' '.join(args.get[:])
path = key.split('.')
now = data
for k in path:
if k in now:
now = now[k]
else:
print('Error: Invalid Key')
print(now)
elif args.get == Null:
key, value = ' '.join(args.set[:]).split('=')
path = key.split('.')
now = data
for k in path[:-1]:
if k in now:
now = now[k]
else:
print('Error: Invalid Key')
now[path[-1]] = value
with open('example.json','w') as write_file: #To write the updated data back to the same file
json.dump(data,write_file,indent=2)
However, my script is not working as I expect it to? Kindly, help me with the script
Your code has the following issues:
When joining the argument values in line number 23 and 35, you use a space. This leads to the "Error key" value. Removing the space will solve the issue.
key = ''.join(arg[:])
You defined the arguments to only pass one value. Not multiple. Therefore even if you pass multiple --get or --set values, the script only gets one value. Adding action="append" to line number 9 and 10 will solve the issue.
parser.add_argument("--get", help="first command", action="append")
parser.add_argument("--set", help="second command", action="append")
Full code:
import json
import pprint
import argparse
if __name__== "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--get", help="first command", action="append")
parser.add_argument("--set", help="second command", action="append")
args=parser.parse_args()
try:
with open('example.json','r') as read_file:
data=json.load(read_file)
except IOError:
print("ERROR: File not found")
exit()
if args.set == None:
for arg in args.get:
key = ''.join(arg[:])
path = key.split('.')
now = data
for k in path:
if k in now:
now = now[k]
else:
print('Error: Invalid Key')
print(f"{arg} = {now}")
elif args.get == None:
for arg in args.set:
key, value = ''.join(arg[:]).split('=')
path = key.split('.')
now = data
for k in path[:-1]:
if k in now:
now = now[k]
else:
print('Error: Invalid Key')
print(f"{arg}")
now[path[-1]] = value
with open('example.json','w') as write_file: #To write the updated data back to the same file
json.dump(data,write_file,indent=2)
here is the get part of the question, I hope that you can continue the set part of your assignment. good luck
python test.py --get name NYU.student
import json
import pprint
import argparse
def match(data: dict, filter: str):
current = data
for f in filter.split("."):
if f not in current:
return False
current = current[f]
return current == True
if __name__== "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--get", nargs="*", help="first command")
args = parser.parse_args()
with open('example.json','r') as f:
data = json.loads(f.read())
if args.get is not None and len(args.get) == 2:
attr_name = args.get[0]
if match(data, args.get[1]):
print("{}={}".format(attr_name, data[attr_name]))
In order to pass arguments using command line make use of sys module in python3. The sys module reads the command line arguments as a list of strings. The first element in the list is always the name of the file and subsequent elements are arg1, arg2 ..... so on.
Hope the following example helps to understand the usage of sys module.
Example Command :
python filename.py 1 thisisargument2 4
The corresponding code
import sys
# Note that all the command line args will be treated as strings
# Thus type casting will be needed for proper usage
print(sys.argv[0])
print(sys.argv[1])
print(sys.argv[2])
print(sys.argv[3])
Corresponding Output
filename.py
1
thisisargument2
4
Also please make a thorough google search before posting a question on stackoverflow.

How to pass arguments to a file in command line and change string inside file using python?

I have a file requirement.txt file. the following text are below.How to change the value for django and flask and update the file by passing as command line argument
requirement.txt
numpy=1.14
pandas=1.4
django=1.6
flask=1.4
my python file.py is below
import sys
import re
program_name = sys.argv[0]
arguments = sys.argv[1:]
print (arguments[0])
print (arguments[1])
with open('requirement.txt ', 'r') as fr:
data = fr.readlines()
with open('requirement.txt ', 'a') as fw:
fw.write(....)
python file.py django=2.1 flask=2.0
output of requirement.txt
numpy=1.14
pandas=1.4
django=2.1
flask=2.0
import re
import sys
arguments = dict(i.split("=") for i in sys.argv[1:]) #CMD line Arguments.
with open('requirement.txt', 'r') as fr: #Read content
data = fr.read()
for k, v in arguments.items():
data = re.sub(r"{}=(.*)".format(k), "{}={}".format(k,v), data) #Update content
with open(filename, 'w') as fr: #Write back data.
fr.write(data)
I think you might wanna check out argparse:
https://docs.python.org/2/library/argparse.html
Otherwise, you can go about it this way:
import sys
requirements = {}
# Save a list of requirements
with open('requirement.txt', 'r') as file:
for line in file:
line = line.strip("\n").split("=")
requirements[line[0]] = line[1]
# Change requirements values
for command in sys.argv[1:]:
command = command.split("=")
requirements[command[0]] = command[1]
# Write requirements back to file
with open('requirement.txt', 'w') as file:
for r, v in requirements.items():
line = "{}={}\n".format(r, v)
file.write(line)
With convenient fileintput module - editing in one pass:
import sys
import fileinput
program_name = sys.argv[0]
args = sys.argv[1:]
if not args: # ensuring replacement items were passed
sys.exit('No items to replace')
args_dict = dict(arg.split('=') for arg in args)
keys_tuple = tuple(args_dict.keys())
for line in fileinput.input(files='requirements.txt', inplace=True):
if line.startswith(keys_tuple):
name, version = line.split('=')
line = line.replace(version, args_dict[name])
print(line.strip())
The final requirements.txt file contents:
numpy=1.14
pandas=1.4
django=2.1
flask=2.0
Using 'a' means you will have two requirements of the same type, like this:
numpy=1.14
pandas=1.4
django=1.6
flask=1.4
django=2.1
flask=2.0
Instead, you should overwrite the file with an updated list of requirements.
First, load the data and put it in a dictionary:
fr=open('requirement.txt ', 'r')
L=fr.read().split("\n") #Better than .readlines(), since it removes '\n'
fr.close() #Very important, since you're going to write back into it.
D=dict()
for e in L:
E=e.split("=")
if len(E)<2:
continue
D[E[0]]=E[1]
Then, apply the arguments to the dictionary:
D[arguments[0]]=arguments[1]
Finally, put the dictionary data back into a string and overwrite the file:
result="\n".join([e+"="+D[e] for e in D])
fw=open('requirement.txt ', 'a')
fw.write(result)
fw.close()
which should give the desired result.
Additionally, you should keep track of order of keys in a list if you wish to preserve it.

Check for empty argument Python

I'm having two problems with arguments in my program, the first problem is that I'm trying to print an error if no arguments are passed to the program and also I'm trying to instead having to use -n which stands for 'no argument' to actually not have to pass any argument to load the file into the program, I want it to just run like python3 program.py file file2 file3 instead of using python3 -n file file2 file3 etc.. I have commented out what I tried to check for the argument if the argument is just the program file [0] to exit
def main():
script = sys.argv[0]
action = sys.argv[1]
noargfile = sys.argv[1:]
filenames = sys.argv[2:]
OutContent = filenames or noargfile
#Load files with arguments -d & --default
print("Loading Files....", sys.argv[1:])
for arg in filenames:
try:
myfile = open(arg, "r")
fileContent = myfile.readlines()
myfile.close()
OutContent = OutContent + fileContent
#if len(sys.argv) == script:
#print("No Argument")
#sys.exit(0)
if action == '--default':
counter = 0 # set a counter to 0
for line in OutContent: #for each line in load if the " 200 " is found add 1 to the counter and repeat until done.
if re.findall(r"\s\b200\b\s", line):
counter += 1
print("\nTotal of (Status Code) 200 request:", counter)
elif action == '-d':
counter = 0 # set a counter to 0
for line in OutContent: #for each line in load if the " 200 " is found add 1 to the counter and repeat until done.
if re.findall(r"\s\b200\b\s", line):
counter += 1
print("\nTotal of (Status Code) 200 request:", counter)
elif action == '-n':
menu(arg, OutContent)
except OSError:
print("File could not be opened " + filenames)
if __name__ == "__main__":
main()
I get an index out of range error, I don't understand why
File "program.py", line 161, in main
action = sys.argv[1]
IndexError: list index out of range
Add this to be first line in function main:
if len(sys.argv)==1: sys.exit("error here")
You shouldn't doing argument parsing yourself when there are already very good argument parses out there (there are probably 100 on pypy)
This little example uses argparse module. It takes n number of files and stores it as a list of strings in the variable files
import argparse
parser = argparse.ArgumentParser(description='Load some files')
parser.add_argument('-f','--files', dest='files', nargs='+', help='<Required> Set flag', required=True)
args = parser.parse_args()
print args.files
Usage:
python myscript -f test1.txt test2.txt test3.txt
Here are more details on how to add more functionalities like help pages or make required|optional fields. https://docs.python.org/2/library/argparse.html

Can I configure python to have matlab like print?

Can I configure python to have matlab like print, so that when I just have a function
returnObject()
that it simply prints that object without me having to type print around it? I assume this is not easy, but something like if an object does not get bound by some other var it should get printed, so that this would work.
a = 5 #prints nothing
b = getObject() #prints nothing
a #prints 5
b #prints getObject()
getObject() #prints the object
If you use an ipython notebook individual cells work like this. But you can only view one object per cell by typing the objects name. To see multiple objects you'd need to call print, or use lots of cells.
You could write a script to modify the original script based on a set of rules that define what to print, then run the modified script.
A basic script to do this would be:
f = open('main.py', 'r')
p = open('modified.py', 'w')
p.write('def main(): \n')
for line in f:
temp = line
if len(temp) == 1:
temp = 'print(' + line + ')'
p.write('\t' + temp)
p.close()
from modified import main
main()
The script main.py would then look like this:
x = 236
x
output:
236
Idea is as follows: parse AST of Python code, replace every expression with call to print and content of expression as argument and then run the modified version. I'm not sure whether it works with every code, but you might try. Save it as matlab.py and run your code as python3 -m matlab file.py.
#!/usr/bin/env python3
import ast
import os
import sys
class PrintAdder(ast.NodeTransformer):
def add_print(self, node):
print_func = ast.Name("print", ast.Load())
print_call = ast.Call(print_func, [node.value], [])
print_statement = ast.Expr(print_call)
return print_statement
def visit_Expr(self, node):
if isinstance(node.value, ast.Call) and node.value.func.id == 'print':
return node
return self.add_print(node)
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
args = parser.parse_args()
with args.infile as infile:
code = infile.read()
file_name = args.infile.name
tree = ast.parse(code, file_name, 'exec')
tree = PrintAdder().visit(tree)
tree = ast.fix_missing_locations(tree)
bytecode = compile(tree, file_name, 'exec')
exec(bytecode)
if __name__ == '__main__':
main()

Return value help Python

Im having trouble printing the return value of one of my functions
def readfile(filename):
'''
Reads the entire contents of a file into a single string using
the read() method.
Parameter: the name of the file to read (as a string)
Returns: the text in the file as a large, possibly multi-line, string
'''
try:
infile = open(filename, "r") # open file for reading
# Use Python's file read function to read the file contents
filetext = infile.read()
infile.close() # close the file
return filetext # the text of the file, as a single string
except IOError:
()
def main():
''' Read and print a file's contents. '''
file = input(str('Name of file? '))
readfile(file)
How do I save readfile's value into a different variable then print the value of the variable where you saved readfile's return value?
This is the simplest way, I wont recommend adding a try block in the function because you will have to use it anyways after or return a empty value which is a bad thing
def readFile(FileName):
return open(FileName).read()
def main():
try:
File_String = readFile(raw_input("File name: "))
print File_String
except IOError:
print("File not found.")
if __name__ == "__main__":
main()
Have you tried:
def main():
''' Read and print a file's contents. '''
file = input(str('Name of file? '))
read_contents = readfile(file)
print read_contents
def main():
''' Read and print a file's contents. '''
file = input(str('Name of file? '))
text = readfile(file)
print text
this should do it, just assign the functions call to a variable.
But in case when the exception is raised you're returning nothing, so the function will return None.
def main():
''' Read and print a file's contents. '''
file = input('Name of file? ') #no need of str() here
foo=readfile(file)
print foo
and use with statement when handling files, it takes care of the closing of the file:
def readfile(filename):
try:
with open(filename) as infile :
filetext = infile.read()
return filetext
except IOError:
pass
#return something here too

Categories