join() argument must be str, bytes, or os.PathLike object, not 'NoneType'

1.2k Views Asked by At

I am making a CLI tool using python and click. I have a command called ext that has two options --type and --path and then another command ext. The function organizes the files in the specified path based on the extension specified in the given type. This is the command and the error I get:

Categorize ext --type image --path C:\Users\ACERq\Pictures\Screenshots ext
join() argument must be str, bytes, or os.PathLike object, not 'NoneType'

I have another similar command which takes just one path option, that function works properly with the same path

import click
from src.services.ext_functions import *

class Context:
    def __init__(self, type, path):
        self.type = type
        self.path = path

@click.group()
@click.option("-t", "--type", type=str, help = "Type of extension", required=False, default="media")
@click.option("-p", "--path", type=str, help = "Path to organize", required=False, default=os.getcwd())
@click.pass_context
def main(ctx, type, path):
    """Organize files based on extension"""
    ctx.obj = Context(type, path)
    pass

@main.command()
@click.pass_context
def ext(ctx):
    """Organize files based on specified extension types"""
    extension = ctx.obj.type
    folder_to_track = ctx.obj.path
    click.echo(extension_category(extension, folder_to_track))

@main.command()
@click.pass_context
def all(ctx):
    """Organize all files based on extension types"""
    folder_to_track = ctx.obj.path
    click.echo(all_extensions_category(folder_to_track))

Full traceback

Traceback (most recent call last):
  File "D:\Python-projects\Categorize-CLI\.venv\Scripts\Categorize-script.py", line 33, in <module>
    sys.exit(load_entry_point('Categorize-CLI', 'console_scripts', 'Categorize')())
  File "D:\Python-projects\Categorize-CLI\.venv\lib\site-packages\click\core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "D:\Python-projects\Categorize-CLI\.venv\lib\site-packages\click\core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "D:\Python-projects\Categorize-CLI\.venv\lib\site-packages\click\core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "D:\Python-projects\Categorize-CLI\.venv\lib\site-packages\click\core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "D:\Python-projects\Categorize-CLI\.venv\lib\site-packages\click\core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "D:\Python-projects\Categorize-CLI\.venv\lib\site-packages\click\core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "D:\Python-projects\Categorize-CLI\.venv\lib\site-packages\click\decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "d:\python-projects\categorize-cli\src\commands\ext.py", line 23, in ext
    click.echo(extension_category(extension, folder_to_track))
  File "d:\python-projects\categorize-cli\src\services\ext_functions.py", line 82, in extension_category
    folder_path = os.path.join(folder_to_track, folder_name)
  File "C:\Users\ACERq\AppData\Local\Programs\Python\Python310\lib\ntpath.py", line 117, in join
    genericpath._check_arg_types('join', path, *paths)
  File "C:\Users\ACERq\AppData\Local\Programs\Python\Python310\lib\genericpath.py", line 152, in _check_arg_types
    raise TypeError(f'{funcname}() argument must be str, bytes, or '
TypeError: join() argument must be str, bytes, or os.PathLike object, not 'NoneType'

extension_category()

def extension_category(extension, folder_to_track):
    start_time = time.monotonic()
    movedFiles = False
    count = 0
    if check_files(folder_to_track):
        for file in os.listdir(folder_to_track):
            if not os.path.isdir(os.path.join(folder_to_track, file)):
                try:
                    file_mappings = collections.defaultdict()
                    for filename in os.listdir(folder_to_track):
                        for value in extension:
                            if not os.path.isdir(os.path.join(folder_to_track, filename)) and any(
                                    filename.endswith(value) for filename in os.listdir(folder_to_track)) == True:
                                file_mappings.setdefault(get_key(extension), []).append(filename)

                    for folder_name, folder_items in file_mappings.items():
                        folder_path = os.path.join(folder_to_track, folder_name)
                        folder_exists = os.path.exists(folder_path)
                        if not folder_exists:
                            os.mkdir(folder_path)

                            for filename in os.listdir(folder_to_track):
                                for value in extension:
                                    if not os.path.isdir(os.path.join(folder_to_track, filename)) and filename.endswith(
                                            value):
                                        count = count + 1
                                        source = os.path.join(folder_to_track, filename)
                                        destination = os.path.join(folder_path, filename)
                                        moveIncrementing(source,destination)  # move all files containing sub_file_name in their filenames
                                        movedFiles = True

                        if folder_exists:
                            for filename in os.listdir(folder_to_track):
                                for value in extension:
                                    if not os.path.isdir(os.path.join(folder_to_track, filename)) and filename.endswith(
                                            value):
                                        count = count + 1
                                        source = os.path.join(folder_to_track, filename)
                                        destination = os.path.join(folder_path, filename)
                                        moveIncrementing(source,
                                                         destination)  # move all files containing sub_file_name in their filenames
                                        movedFiles = True

                    end_time = time.monotonic()

                    displayProgressbar(count)

                    if movedFiles:
                        if count == 1:
                            return f"Successfully moved {count} file{os.linesep}Time taken: {timedelta(seconds=end_time - start_time)}"
                        else:
                            return f"Successfully moved {count} files{os.linesep}Time taken: {timedelta(seconds=end_time - start_time)}"
                    else:
                        return "Files with that extension do not exist in {}".format(folder_to_track)

                except Exception as e:
                    print(e)
                    return f'{folder_to_track}: is either empty or not organizable'

    else:
        return f'{folder_to_track}: is either empty or not organizable'

If I call the function like this: extension_category(image, r"C:\Users\ACERq\Pictures\Screenshots") it works

Update I managed to make it work but then I encountered a new problem

enter image description here

When I just check if the inputted value is equal to the extension then it works but when I add some more modifications it doesn't work

enter image description here

1

There are 1 best solutions below

0
On BEST ANSWER

I finally fixed the problem, I thought the problem was due to the parameter folder_to_track but it was actually the second parameter extension that was causing the issue. The function took the parameter as the value of the extensions-dict and not the key. So instead of image as the extension, it should be [".png", ".jpg"] etc

import click
from src.services.ext_functions import *

class Context:
    def __init__(self, type, path):
        self.type = type
        self.path = path

@click.command()
@click.option("-t", "--type", type=str, help = "Type of extension", required=True)
@click.option("-p", "--path", type=str, help = "Path to organize", required=False, default=os.getcwd())
@click.pass_context
def main(ctx, type, path):
    """Organize files based on extension"""
    ctx.obj = Context(type, path)
    extension = ctx.obj.type
    folder_to_track = ctx.obj.path
    
    categories = [key for key, value in extensions.items()]
    if extension in categories and os.path.exists(folder_to_track):
        click.echo(extension_category(extensions[extension], folder_to_track))
    elif not extension in categories:
        click.echo("{} is not one of the types of extensions".format(extension))
    elif not os.path.exists(folder_to_track):
        click.echo("{}: does not exist".format(folder_to_track))