TypeError: listdir: path should be string, bytes, os.PathLike or None, not Namespace
Question:
I am using Python 3.9, PyCharm 2022.
My purpose (Ultimate goal of this question): create a command line application receive 2 parameters:
- Path of directory
- Extension of files
then get size of files (Per file size, not sum of files size).
import os
import argparse
from os import listdir
from os.path import isfile, join
def main():
parser = argparse.ArgumentParser()
parser.add_argument("path", help="Path of directory.")
parser.add_argument("ext", help="Extension of files (for example: jpg, png, exe, mp4, etc.")
args1 = parser.parse_args()
args2 = parser.parse_args()
print(args1)
arr = os.listdir(args1)
print(arr)
# os.path.getsize(args.path)
# bytes_size = os.path.getsize(args1.path)
# mb_size = int(bytes_size / 1024 / 1024)
# print(mb_size, "MB")
if __name__ == '__main__':
main()
My command and according error:
(base) PS C:UsersdonhuPycharmProjectspythonProject4> python size.py 'D:' 'jpg'
Traceback (most recent call last):
File "C:UsersdonhuPycharmProjectspythonProject4size.py", line 22, in <module>
(base) PS C:UsersdonhuPycharmProjectspythonProject4> python size.py 'D:' 'jpg'
Namespace(path='D:', ext='jpg')
Traceback (most recent call last):
File "C:UsersdonhuPycharmProjectspythonProject4size.py", line 23, in <module>
main()
File "C:UsersdonhuPycharmProjectspythonProject4size.py", line 13, in main
arr = os.listdir(args1)
TypeError: listdir: path should be string, bytes, os.PathLike or None, not Namespace
(base) PS C:UsersdonhuPycharmProjectspythonProject4>
Update, I tried something
import os
import argparse
from os import listdir
from os.path import isfile, join
from pathlib import *
def main():
parser = argparse.ArgumentParser()
parser.add_argument("path", help="Đường dẫn của thư mục")
parser.add_argument("ext", help="Định dạng tập tin cần liệt kê kích thước.")
args1 = parser.parse_args()
args2 = parser.parse_args()
foo = args1.path
# arr = os.listdir('D:/')
files = [x for x in foo.iterdir() if x.is_file()]
print(files)
# os.path.getsize(args.path)
# bytes_size = os.path.getsize(args1.path)
# mb_size = int(bytes_size / 1024 / 1024)
# print(mb_size, "MB")
if __name__ == '__main__':
main()
but not work.
Answers:
Argparse’s parse_args()
function returns a Namespace
object. I believe your goal was to pass the path
argument, you have to access it as an attribute.
os.listdir(args1.path)
The os
module holds the traditional interface into the file system. It closely follows the Clib interface so you’ll see functions like listdir
and stat
. pathlib
is a new object oriented "pythonic" interface to the file system. One can argue whether its better, but I use it, so its gotta be, right?
It looks like you are mixing "old" and "new" ways of doing things, which gets confusing. If you want to use pathlib
, try to use it for everything.
Here is your script re-imagined for pathlib. You only need to parse the command line once and then build a Path
object for the directory of interest.
import argparse
from pathlib import Path
def main():
parser = argparse.ArgumentParser()
parser.add_argument("path", help="Đường dẫn của thư mục")
parser.add_argument("ext", help="Định dạng tập tin cần liệt kê kích thước.")
args = parser.parse_args()
foo = Path(args.path)
if not foo.is_dir():
print("Error: Must be a directory")
exit(1)
files = [x for x in foo.iterdir() if x.is_file()]
print(files)
# os.path.getsize(args.path)
bytes_size = sum(file.stat().st_size for file in files)
print("total bytes", bytes_size)
# mb_size = int(bytes_size / 1024 / 1024)
# print(mb_size, "MB")
if __name__ == '__main__':
main()
If you want to use the ext
parameter, you would change from iterdir
to glob.
files = [x for x in foo.glob(f"*.{args.ext}") if x.is_file()]
or
files = [x for x in foo.glob(f"**/*.{args.ext}") if x.is_file()]
depending on whether you want just the directory or its subtree.
Your two command line arguments are being returned as a single object of the argparse.Namespace class, both stored identically in your args1 and (the superfluous) args2 variables.
Inserting the following line after your calls to parse_args() and commenting out the subsequent code would illuminate this a little more:
print(type(args1))
To access the values you named in your calls to add_argument(), use this syntax:
args1.path
args1.ext
such as
arr = os.listdir(args1.path)
For further discussion, see this answer: Accessing argument values for argparse in Python
Program
import os
import argparse
from pathlib import Path
def main():
parser = argparse.ArgumentParser()
parser.add_argument("path", help="Path of directory/folder")
parser.add_argument("ext", help="Extension of file what need get size.")
args = parser.parse_args()
foo = Path(args.path)
files = [x for x in foo.glob(f"*.{args.ext}") if x.is_file()]
for file in files:
print(file.__str__(), os.path.getsize(file))
if __name__ == '__main__':
main()
# python size.py "D:" 'jpg'
# (base) PS C:UsersdonhuPycharmProjectspythonProject4> python size.py "D:" 'jpg'
# D:1496231_10152440570407564_3432420_o.jpg 241439
# D:15002366_278058419262140_505451777021235_o.jpg 598063
# D:1958485_703442046353041_1444502_n.jpg 63839
# D:277522952_5065319530178162_680264454398630_n.jpg 335423
I am using Python 3.9, PyCharm 2022.
My purpose (Ultimate goal of this question): create a command line application receive 2 parameters:
- Path of directory
- Extension of files
then get size of files (Per file size, not sum of files size).
import os
import argparse
from os import listdir
from os.path import isfile, join
def main():
parser = argparse.ArgumentParser()
parser.add_argument("path", help="Path of directory.")
parser.add_argument("ext", help="Extension of files (for example: jpg, png, exe, mp4, etc.")
args1 = parser.parse_args()
args2 = parser.parse_args()
print(args1)
arr = os.listdir(args1)
print(arr)
# os.path.getsize(args.path)
# bytes_size = os.path.getsize(args1.path)
# mb_size = int(bytes_size / 1024 / 1024)
# print(mb_size, "MB")
if __name__ == '__main__':
main()
My command and according error:
(base) PS C:UsersdonhuPycharmProjectspythonProject4> python size.py 'D:' 'jpg'
Traceback (most recent call last):
File "C:UsersdonhuPycharmProjectspythonProject4size.py", line 22, in <module>
(base) PS C:UsersdonhuPycharmProjectspythonProject4> python size.py 'D:' 'jpg'
Namespace(path='D:', ext='jpg')
Traceback (most recent call last):
File "C:UsersdonhuPycharmProjectspythonProject4size.py", line 23, in <module>
main()
File "C:UsersdonhuPycharmProjectspythonProject4size.py", line 13, in main
arr = os.listdir(args1)
TypeError: listdir: path should be string, bytes, os.PathLike or None, not Namespace
(base) PS C:UsersdonhuPycharmProjectspythonProject4>
Update, I tried something
import os
import argparse
from os import listdir
from os.path import isfile, join
from pathlib import *
def main():
parser = argparse.ArgumentParser()
parser.add_argument("path", help="Đường dẫn của thư mục")
parser.add_argument("ext", help="Định dạng tập tin cần liệt kê kích thước.")
args1 = parser.parse_args()
args2 = parser.parse_args()
foo = args1.path
# arr = os.listdir('D:/')
files = [x for x in foo.iterdir() if x.is_file()]
print(files)
# os.path.getsize(args.path)
# bytes_size = os.path.getsize(args1.path)
# mb_size = int(bytes_size / 1024 / 1024)
# print(mb_size, "MB")
if __name__ == '__main__':
main()
but not work.
Argparse’s parse_args()
function returns a Namespace
object. I believe your goal was to pass the path
argument, you have to access it as an attribute.
os.listdir(args1.path)
The os
module holds the traditional interface into the file system. It closely follows the Clib interface so you’ll see functions like listdir
and stat
. pathlib
is a new object oriented "pythonic" interface to the file system. One can argue whether its better, but I use it, so its gotta be, right?
It looks like you are mixing "old" and "new" ways of doing things, which gets confusing. If you want to use pathlib
, try to use it for everything.
Here is your script re-imagined for pathlib. You only need to parse the command line once and then build a Path
object for the directory of interest.
import argparse
from pathlib import Path
def main():
parser = argparse.ArgumentParser()
parser.add_argument("path", help="Đường dẫn của thư mục")
parser.add_argument("ext", help="Định dạng tập tin cần liệt kê kích thước.")
args = parser.parse_args()
foo = Path(args.path)
if not foo.is_dir():
print("Error: Must be a directory")
exit(1)
files = [x for x in foo.iterdir() if x.is_file()]
print(files)
# os.path.getsize(args.path)
bytes_size = sum(file.stat().st_size for file in files)
print("total bytes", bytes_size)
# mb_size = int(bytes_size / 1024 / 1024)
# print(mb_size, "MB")
if __name__ == '__main__':
main()
If you want to use the ext
parameter, you would change from iterdir
to glob.
files = [x for x in foo.glob(f"*.{args.ext}") if x.is_file()]
or
files = [x for x in foo.glob(f"**/*.{args.ext}") if x.is_file()]
depending on whether you want just the directory or its subtree.
Your two command line arguments are being returned as a single object of the argparse.Namespace class, both stored identically in your args1 and (the superfluous) args2 variables.
Inserting the following line after your calls to parse_args() and commenting out the subsequent code would illuminate this a little more:
print(type(args1))
To access the values you named in your calls to add_argument(), use this syntax:
args1.path
args1.ext
such as
arr = os.listdir(args1.path)
For further discussion, see this answer: Accessing argument values for argparse in Python
Program
import os
import argparse
from pathlib import Path
def main():
parser = argparse.ArgumentParser()
parser.add_argument("path", help="Path of directory/folder")
parser.add_argument("ext", help="Extension of file what need get size.")
args = parser.parse_args()
foo = Path(args.path)
files = [x for x in foo.glob(f"*.{args.ext}") if x.is_file()]
for file in files:
print(file.__str__(), os.path.getsize(file))
if __name__ == '__main__':
main()
# python size.py "D:" 'jpg'
# (base) PS C:UsersdonhuPycharmProjectspythonProject4> python size.py "D:" 'jpg'
# D:1496231_10152440570407564_3432420_o.jpg 241439
# D:15002366_278058419262140_505451777021235_o.jpg 598063
# D:1958485_703442046353041_1444502_n.jpg 63839
# D:277522952_5065319530178162_680264454398630_n.jpg 335423