0

I created a method which splits a sentence into words and returns the first word of the sentence (you could use NLTK tokenizer or argparse for this, but as this is a class project meant for learning Python, I created a simple tokenizer from scratch) The method also has a useful 'help' argument, in which passing -h or --help will bring up help text. However I want the function to output the help text then 'break' or 'pass' if the user passes -h or --help. Here's my method:

class example_method(object):
    def __init__(self):
        self.data = []

    def parse(self, message):
        if(("-h" or "--help") in message): 
            print("This is a helpful message")
        else:
            self.data = [x.strip() for x in message.split(' ')]
            return self.data

If the user input a regular message, the method works. Let me illustrate:

example = example_method()
input_message = "Hello there how are you?"
print(example.parse(input_message)[0])

The above works well. However, if the user inputs -h or --help, the method returns an error:

example = example_method()
input_message = "--help"
print(example.parse(input_message)[0])

The above will return: TypeError: 'NoneType' object is not subscriptable I realize that a possible solution is:

try: print(example.parse(input_message)[0])
except: pass

But is there a way to return pass from within the method like this?

    def parse(self, message):
        if(("-h" or "--help") in message): 
            print("This is a helpful message")
            return pass
        else:
            self.data = [x.strip() for x in message.split(' ')]
            return self.data

My aim is that I do not want an error message as this method is part of a bigger program and an error will just make the output look ugly. It would look far more professional if the method outputs help text and then exits without an error.

Code Monkey
  • 800
  • 1
  • 9
  • 27
  • 5
    `pass` is syntax for doing nothing in an indented block. It has no value that you could return. – timgeb Jan 03 '19 at 11:52
  • simply return a list that contains your help message as well? You classname is ... far from good. returning the help message is just a hack .. if the consumer of your parse methods does it like you do `print(example.parse(input_message)[0])`, he will get an error for an empty result as well because of indexing into it without checking. – Patrick Artner Jan 03 '19 at 11:54

5 Answers5

2

maybe just arrange for your parse function to return None, then the calling function can check for this case and handle it…

for example:

class example_method(object):
    # …
    def parse(self, message):
        if message in {"-h", "--help"}:
            print("This is a helpful message")
            return  # implicitly returns None

        self.data = [x.strip() for x in message.split(' ')]
        return self.data

res = example.parse(input_message)
if res is None:
    return

print(res[0])
Sam Mason
  • 15,216
  • 1
  • 41
  • 60
  • or just have `return self.data` in the `if` block? – Andrew Jan 03 '19 at 11:56
  • But, your solution is no different from mine - try: print(example.parse(input_message)[0]) except: pass which is something I wished to avoid as I wanted everything 'compact' within the function. Regardless, you sir are a genius too! Thank you for your help! – Code Monkey Jan 03 '19 at 12:22
  • @CodeMonkey that will mask a whole bucket load of unrelated errors/mistakes. e.g. https://stackoverflow.com/q/14797375/1358308 – Sam Mason Jan 03 '19 at 12:25
1

You can use exit() to immediately stop program execution.

def parse(self, message):
    if(("-h" or "--help") in message): 
        print("This is a helpful message")
        exit()
    else:
        self.data = [x.strip() for x in message.split(' ')]
        return self.data
Yossi
  • 11,778
  • 2
  • 53
  • 66
  • You sir, are a friggin genius! I salute you! – Code Monkey Jan 03 '19 at 11:59
  • 1
    @CodeMonkey you could also just use `argparse`. – timgeb Jan 03 '19 at 12:00
  • 1
    I don't like methods that shut down my code at all .. if I call `parse` on a text that contains `-h` for whatever reason my script dies? Bad idea. Think about ppl that use your code as part of something ... and you shut down the whole script on some (user)input? @CodeMonkey – Patrick Artner Jan 03 '19 at 12:04
  • @PatrickArtner it's pretty convenient for most people. you can always add `add_help=False` if you don't want it to do that… – Sam Mason Jan 03 '19 at 12:06
  • @SamMason if I import some module and use a `parse` method somewhere in my 250 lines of code that parses lines from 20 files want to `parse` by supplying them line by line to this method (to do whatever with the parsed stuff) ...and in some cases this code simply _stops_ after outputting some text ... that is bad design and not "convenient". Do you know how long it takes to track down such "features"? – Patrick Artner Jan 03 '19 at 12:11
  • @PatrickArtner any arbitrary code anywhere can call `exit()` it's not just parse… you could catch `SystemExit` and display a traceback to see where it's coming from next time – Sam Mason Jan 03 '19 at 12:16
  • Ignoring the reasons for avoiding hard quits in general, I'll point out that `exit()` is explicitly discouraged; it's for interactive use, not for general programmatic use (it's not even guaranteed to exist, and when it does, it's sometimes replaced by third party programs), per [the docs](https://docs.python.org/3/library/constants.html#exit): "[These constants] are useful for the interactive interpreter shell and should not be used in programs." Properly written programs should be calling `sys.exit()` (or better, raising normal exceptions, not quitting from utility methods). – ShadowRanger Jan 03 '19 at 22:47
1

Consider using argparse in order to automatically generate the -h and --help flags and the help text.

Low effort demo:

script.py

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-p', help='This will be printed')
args = parser.parse_args()

print(args.p)

usage:

$ python3 script.py -p hello
hello
$ python3 script.py -h
usage: script.py [-h] [-p P]

optional arguments:
  -h, --help  show this help message and exit
  -p P        This will be printed

As you can see, using -h (or --help) displays the help message and does not execute any other code (by default).

timgeb
  • 76,762
  • 20
  • 123
  • 145
0

You should overthink your design ... add a

def help(self): 
    print("Cool description")

method and remove the "help switch parsing" from def parse(self, message).

You are crippling the capabilities of parser ... think about parsing this totally contrieved message:

"Paris is a cool town-however you travel it: by foot, by bike or by parachute." 

See SRP (Single responsibility principle) - parse should not print help messages.


You can also use documentation to provide help():

class well_documented_example_class(object):
    """Totally well documented class"""

    def parse(self, message):
        """This method does coool things with your 'message'

        'message' : a string with text in it to be parsed"""
        self.data = [x.strip() for x in message.split(' ')]
        return self.data

You get help by issuing:

print(help(well_documented_example_class))

to get:

class well_documented_example_class(builtins.object)
 |  Totally well documented class
 |  
 |  Methods defined here:
 |  
 |  parse(self, message)
 |      This method does coool things with your 'message'
 |      
 |      'message' : a string with text in it to be parsed
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
0

Thanks to all your suggestions, I created my own command parsing module to solve this problem. You can find it on GitHub: https://github.com/MonkeyBot2020/comparse

Here are some examples of its usage:

from comparse import comparse
query = comparse(False)
query.add_argument("log_channel", "str", "logs.txt", "Logs the channel in specified file. DEFAULT ARGUMENT(S): log_channel 'logs.txt'")
query.add_argument("content_filter", "str", "None", "Filter log by content. DEFAULT ARGUMENT(S): content_filter 'None'")
query.add_argument("log_attachments", "bool", True, "Logs attachments. DEFAULT ARGUMENT(S): log_attachments 'True'")
query.add_argument("log_author", "bool", False, "Logs author of message. DEFAULT ARGUMENT(S): log_author=False")
query.add_argument("exclude_content", "str", "None", "Exclude content from log. DEFAULT ARGUMENT(S): exclude_content='None'")

#FIRST EXAMPLE
message = "log_channel --h"
file_name = query.parse(message)
try: print(file_name['exclude_content'][0])
except: print(query.parse("--help"))

#SECOND EXAMPLE
message = "log_channel=example.txt, content_filter=posted, log_attachments=True, log_author=True, exclude_content='apple, pear, orange'"
file_name = query.parse(message)
try: print(file_name)
except: print(query.parse("--help"))

#THIRD EXAMPLE
message = "log_channel, exclude_content='apple, pear'"
file_name = query.parse(message)
try: print(file_name['exclude_content'])
except: print(query.parse("--help"))

#FOURTH EXAMPLE
message = "i made a booboo"
file_name = query.parse(message)
try: print(file_name['mistaken_content'][0])
except: print(query.parse("--help"))

Hope this is useful :)

Code Monkey
  • 800
  • 1
  • 9
  • 27