-1

i want to pass a txt file by command line argument using the argparse module and read the file with open() function but first thing i've encountred was this error :

AttributeError: 'dict' object has no attribute 's'

Here is my code

import argparse
parser = argparse.ArgumentParser(description="My program!", formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-s", type=argparse.FileType('r'), help="Filename/path to be passed")
args = vars(parser.parse_args())
subfile = (open(args.s, "r")).read()
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • `subfile = (open(args['s'], "r")).read()` ? if `args` is a `dict`, you can't do `args.s` like calling a method `s` from an object `args`. Use the syntax `dict[key]` instead if you want to obtain the value of the key in the dict. – FObersteiner Sep 08 '19 at 15:48
  • @MrFuppes thank you for your help but it gave me a type error : TypeError: expected str, bytes or os.PathLike object, not NoneType – toxicpr0xy Sep 08 '19 at 15:52
  • seems like you called the script without a filename specified (parameter -s). Added an answer to clarify. – FObersteiner Sep 08 '19 at 16:10
  • 1
    Why do you do `args = vars(parser.parse_args())` instead of `args = parser.parse_args()`? – wjandrea Sep 08 '19 at 16:14
  • 1
    @wjandrea: I guess without calling `vars()`, `args.s` would have worked in the first place – FObersteiner Sep 08 '19 at 16:39
  • @MrFuppes Exactly, yeah, that's why I ask – wjandrea Sep 08 '19 at 16:40
  • @MrFuppes yes its true i was giving the wrong file path – toxicpr0xy Sep 08 '19 at 20:16
  • I noted that it it's not possible to `.close()` an io.textwrapper created by `argparse.FileType('r')` (see [here](https://stackoverflow.com/a/13736862/10197418)). So the code shoud be fine if you just open a few files, but might cause problems if many files. Then it seems to be better to just pass the filename string and open the file in a `with` statement as shown [here](https://stackoverflow.com/a/18863004/10197418). – FObersteiner Sep 09 '19 at 10:13

2 Answers2

1

you can directly read from args['s'], since type=argparse.FileType('r'). No open() needed:

import argparse
parser = argparse.ArgumentParser(description="My program!", formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-s", type=argparse.FileType('r'), help="Filename/path to be passed")
args = vars(parser.parse_args())
data = args['s'].readlines()
print(data)

now you can call the script from the command prompt, e.g. as python .\test.py -s'D:/test.txt' with test.txt containing two lines with letters 'abc':

# prints ['abc\n', 'abc\n']

edit - you can simplify the code to

parser = argparse.ArgumentParser(description="My program!", formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-f", type=argparse.FileType('r', encoding='UTF-8'), help="path/filename of file to be passed")
data = parser.parse_args().f.readlines()

changes:

  • changed the parameter name to f which I find better-suited for a filename input
  • added and encoding to type=argparse.FileType('r') - otherwise, it will take the OS default (e.g. on Windows: cp1252). I'd consider it better practice to explicitly specify the encoding.
  • directly accessed the io.TextIOWrapper with parser.parse_args().f instead of creating a dict object first with vars()
FObersteiner
  • 22,500
  • 8
  • 42
  • 72
  • just a little notice why when i changed the argument to -w and and args to args["w"] it throw a key error – toxicpr0xy Sep 08 '19 at 20:03
  • did you also change parser.add_argument("-s" ... to `parser.add_argument("-w" ...`? btw. I'd use something more intuitive, like -f, for the filepath argument. – FObersteiner Sep 08 '19 at 20:54
  • okey i will change it to -f most important it doesnt throw this key error thing – toxicpr0xy Sep 09 '19 at 00:41
  • @toxicpr0xy: you can access the parsed `f` argument directly by calling `parser.parse_args().f` - no need to use `vars()`. Made an edit to clarify. This definitely avoids a `KeyError` ;-) Instead, you will get an `AttributeError` if you try to call an argument that wasn't specified, like here e.g. `c` in `parser.parse_args().c` -> gives `AttributeError: 'Namespace' object has no attribute 'c'` – FObersteiner Sep 09 '19 at 10:00
  • 1
    rules here prevent saying thanks but i cant remain silent with that much of help so thanks so much this is my first script ^^ – toxicpr0xy Sep 10 '19 at 00:04
  • Glad I could help! It's fine in the comments I'd say. Anyway, happy coding. – FObersteiner Sep 10 '19 at 06:41
0

Replace the last line:

subfile = (open(args.s, "r")).read()

with:

with open( args['s'] ) as fin :
    subfile = fin.read()

Things magically start to work and you don't have an open file hanging around for no particular reason.

lenik
  • 23,228
  • 4
  • 34
  • 43