Home > Mobile >  format os.scandir() output string, add resource type
format os.scandir() output string, add resource type

Time:09-26

The following code arose through a discovery phase, but its problems were never resolved, as it wasn't needed at the time.

On rediscovering its problems, however, it seemed like a decent example for more experienced developers to use as a launch point for schooling in one or more best practices using os.scandir(), the 'newer', or more generally acceptable method over os.listdir(). As an aside to the questions below, if you can explain why one is preferred over the other, or how they are or are not complementary, your views are welcome.

Some commented code remains, showing another attempt at inserting the node type at the beginning of the string. The while loop did not work out so well, but it does function. How to explain the why of it not working and what should replace its replacement, if anything more than greater fluency of the presently used functions, will go a long way to helping iron this out.

Main concerns are listed below with the core questions I have about making this monstrosity work for me in the development of more refined Python skills.

Thanks in advance.

import os
import time
basedir = os.path.dirname(__file__)

def scandir_list(basedir):

    entries = os.scandir(basedir)
    # print(entries)
    # <posix.ScandirIterator object at 0x7f5f7d0fe5e0>

    # The ScandirIterator points to all the entries in the current directory.
    # Loop the iterator and print out the content.

    with os.scandir(basedir) as entries:
        for entry in entries:
            def filetype(entry):
                # result = ""
                # while result == "" or result == None:
                print('dir ' if os.path.isdir(entry) else '' , end="")
                print('file ' if os.path.isfile(entry) else '' , end="")
                print('link ' if os.path.islink(entry) else '' , end="")
                print('.. ' if os.path.ismount(entry) else '' , end="")
                    # result = 'dir ' if os.path.isdir(entry) else '' #, end="")
                    # result = 'file ' if os.path.isfile(entry) else '' #, end="")
                    # result = 'link ' if os.path.islink(entry) else ' ' #, end=""
                    # result = '.. ' if os.path.ismount(entry) else ' ' #, end="")
                # print('result: ', result)
                # return result
            resourcetype = filetype(entry)
            size = round(float(os.path.getsize(entry)/1024), 2) # does .2f formatting demonstrate presentation layer bias?
            lastmodified = time.ctime(os.path.getmtime(entry))
            # print(f"{resourcetype}: {entry.name} \t\t\t\t\t Size: {os.path.getsize(entry)/1024:.2f} \t \t \t Last Modified: {time.ctime(os.path.getmtime(entry))}")
            print("{}: Size: {} kb, Last Modified: {}, Name: {}".format(resourcetype, size, lastmodified, entry.name))

scandir_list(basedir)

Renders output like so:

file None: Size: 5.76 kb, Last Modified: Sat Sep 25 07:07:28 2021, Name: app.py
dir None: Size: 4.0 kb, Last Modified: Fri Sep 24 23:59:23 2021, Name: test
dir None: Size: 4.0 kb, Last Modified: Sat Sep 25 04:15:51 2021, Name: views

The Problems:

(Just to be clear, the code here is about testing limits, so the method may simply present a wrong way to start...)

1.) Because the resource name is of variable length, and tabs (\t) inserted into the string format are relative (without stops), the resource name has been tacked on to the end. The desired outcome is to place the resource name in the second slot. How can resource name be put into the second slot and the string formatted in such as way as to avoid jagged edges, with minimal code -- whatever the refactor requires in terms of reorganization, or an altogether different approach?

2.) The first slot, resource name, is accompanied by None, but the cause (other print statements inline to the formation of the string) is not well known. What is your explanation and workaround?

UPDATE:

The code originally presented is intact, for all of its having tons of commented statements, mainly, it was thought, for the alternates to be reconstructed.

One way to get rid of None is below. The code is a bit cleaner, too, but the function and its call which have been 'flattened' out remain just in case...

import os
import time
basedir = os.path.dirname(__file__)

def scandir_list(basedir):
    with os.scandir(basedir) as entries:
        for entry in entries:
            resdict = dict() # easy declaration, as single key will be added on update and subsequent values overwritten
            # def filetype(entry): # flattened
            resdict.update({'res': 'dir'}) if os.path.isdir(entry) else ''
            resdict.update({'res': 'file'}) if os.path.isfile(entry) else ''
            resdict.update({'res': 'link'}) if os.path.islink(entry) else ''
            resdict.update({'res': '..'}) if os.path.ismount(entry) else ''
            # resourcetype = filetype(entry) # flattened
            resourcetype = resdict['res']
            # print("resdict: ", resdict) # what's it look like?
            size = round(float(os.path.getsize(entry)/1024), 2)
            lastmodified = time.ctime(os.path.getmtime(entry))
            print("{}: Size: {} kb, Last Modified: {}, Name: {}".format(resourcetype, size, lastmodified, entry.name))
            # del resdict # not really necessary

if __name__ == "__main__":
    scandir_list(basedir)

CodePudding user response:

Try this code: Your error is that your function return 'None', because you don t have return in it. Don t confuse a print and a return.

Please find bellow your code with best practices:

import os
import time

def filetype(entry):
    for filetype in ['dir', 'file', 'mount', 'link']:
        if getattr(os.path, f"is{filetype}")(entry):
            return filetype
    else:
        return "Unknow"

def scandir_list(dir_path):
    for entry in os.scandir(dir_path):
        print(f"""{
                filetype(entry)
            }\tSize: {
                round(float(os.path.getsize(entry)/1024), 2)
            }kb\tLast Modified: {
                time.ctime(os.path.getmtime(entry))
            }\tName: {entry.name}""")

if __name__ == "__main__":
    scandir_list(os.path.dirname(__file__))

Here my output:

dir     Size: 16.0kb  Last Modified: Fri Sep 24 10:17:24 2021     Name: xxx
dir     Size: 28.0kb  Last Modified: Tue Sep  7 12:15:40 2021     Name: yyy
dir     Size: 4.0kb   Last Modified: Fri Sep 24 11:00:04 2021     Name: zzz
dir     Size: 28.0kb  Last Modified: Tue Jun 15 22:16:15 2021     Name: aaa
dir     Size: 4.0kb   Last Modified: Thu Mar 18 14:54:12 2021     Name: bbb
dir     Size: 4.0kb   Last Modified: Tue Jul 28 22:12:35 2020     Name: ccc
file    Size: 2.22kb  Last Modified: Thu Jul 22 15:44:15 2021     Name: ddd.py
  • Related