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>

enter image description here
How to fix?

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.

Asked By: James Grey

||

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)
Answered By: Alec Cureau

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.

Answered By: tdelaney

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

Answered By: Dude Eclair

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
Answered By: James Grey
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.