Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get file path from user to then pass into functions (argparse)

I am writing a program that performs different functions on the contents of a file. At the moment the file is stored in a variable and passed to each of the functions as such:

file = "path/to/file"

What I want to do is allow the user to enter the path using the command line function I have setup and have it passed to my functions.

However I am unsure on how to implement this into the command line file I have here

cli.py

import os, argparse
from . import parse


def validate_file(filename):
    if not os.path.exists(filename):
        raise argparse.ArgumentTypeError("{0} does not exist".format(filename))
    return filename


def dump(filename):
    for record in parse.uniprot_records(filename):
        print(record)

...
(more function definitions)
...

def cli():
    # Create a new parser
    parser = argparse.ArgumentParser(description="UniProt Analysis")

    # Input file
    parser.add_argument("-i", "--input", dest="filename", type=validate_file, required=True, help="enter input file", metavar="FILE")

    subparsers = parser.add_subparsers(help="Enter one of the arguments to run function")

    # Add subparsers
    subparsers.add_parser("dump", help="prints all records").set_defaults(func=dump)

    # Parse the command line
    args = parser.parse_args()
    print(type(args.filename))

    # Take the func argument, which points to our function and call it
    args.func(args)

So I want to be able to pass the file and also have the function I want to perform on it in the command line e.g. pipenv run python program.py path/to/file dump

Edit: Have added an argument to the parser to get the user's input file. This file is then passed into the dumpfunction, which passes the file into this function:

parse.py

import gzip
from Bio import SeqIO


def uniprot_records(f):
    records = []

    handle = gzip.open(f)
    for record in SeqIO.parse(handle, "uniprot-xml"):
        records.append(record)
    return records

My main function is in a separate module where it simply calls the cli function. When I try to run this by doing pipenv run python uniplot.py -i path/to/file dump it gives me the following error:

File "/Users/john/workspace/practical-2/uniplot/parse.py", line 24, in uniprot_records handle = gzip.open(file_location)

File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/gzip.py", line 57, in open raise TypeError("filename must be a str or bytes object, or a file")

TypeError: filename must be a str or bytes object, or a file

dump should simply print out the entire contents of the given file after it has been unzipped using gzip.

like image 236
Johnboy Avatar asked Dec 17 '25 16:12

Johnboy


2 Answers

Please use below syntax.

import argparse, os
from argparse import ArgumentParser


def validate_file(f):
    if not os.path.exists(f):
        # Argparse uses the ArgumentTypeError to give a rejection message like:
        # error: argument input: x does not exist
        raise argparse.ArgumentTypeError("{0} does not exist".format(f))
    return f


if __name__ == "__main__":

    parser = ArgumentParser(description="Read file form Command line.")
    parser.add_argument("-i", "--input", dest="filename", required=True, type=validate_file,
                        help="input file", metavar="FILE")
    args = parser.parse_args()
    print(args.filename)
like image 114
sanjusci Avatar answered Dec 20 '25 05:12

sanjusci


You can add arguments to the parser using parser.add_argument. These will be passed as a Namespace object to the called function:

import argparse

def dump(args):
    print(args.path)


def cli():
    # Create a new parser
    parser = argparse.ArgumentParser()

    subparsers = parser.add_subparsers()

    parser.add_argument("path")

    # Add subparsers
    subparsers.add_parser("dump").set_defaults(func=dump)

    # Parse the command line
    args = parser.parse_args()

    # Take the func argument, which points to the function and call it
    args.func(args)

cli()

The command would look like:

python cli.py dump some/file

As for the recommended way of doing this, that will depend on your use-case. Passing all arguments to the script through the command-line will allow you to run the script more easily in some automated fashion than through interactive inputs. It will also allow you to rerun the same task more easily in a terminal. If that's not relevant for you than this is mostly a matter of personal preference.

like image 22
DavyCats Avatar answered Dec 20 '25 04:12

DavyCats



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!