LinuxProgrammingPython

Writing a command line dictionary and thesaurus using Python

Many times when I’m searching for a definition for a word, or want to find synonyms, I find myself reaching for my browser and defining the word on Google. This often frustrated me as it seemed a clunky way of simply getting a few lines of text explaining what a word meant and what its synonyms were. The solution? A command line dictionary written in Python which can be easily queried using a single command.

Fetching definitions from Google

Google used to have a define API which allowed direct querying of their dictionary. Although this has been deprecated, fortunately a kind person has provided an unofficial Google Dictionary API with the code and examples of its usage on GitHub.

Using an idea for a command line dictionary by GitHub user jyoo, I adapted this project to make use of the unofficial Google Dictionary API and add a few convenience features, such as limiting the output and properly outputting all the different definitions for a word.

To begin with, we need to fetch the data from the API using the requests module built in to Python. It returns a JSON formatted object which we can parse using Python’s in-built json module. I wrote a DictionarySearch class to contain the main behaviour in just a few lines of code.

class DictionarySearch:
    """The main definition class. Parses the google search output for the important elements."""

    def __init__(self, keyword, more=False):
        self.text = None
        self.keyword = keyword
        self.more = more
        self.interpretations = []

    def get_request(self):
        """
        Gets a request from an unofficial google dictionary api of the set keyword.
        """
        for site in ["https://mydictionaryapi.appspot.com/", "https://googledictionaryapi.eu-gb.mybluemix.net/"]:
            try:
                req = requests.get(site, params={"define": str(self.keyword)},
                                   timeout=10)
                if req.status_code == requests.codes.ok:
                    self.text = req.text
                    req.close()
                    break
            except requests.exceptions.RequestException:
                pass
        if self.text is None:
            raise IOError("Could not get query form unofficial google dictionary api.")

    def parse_text(self):
        """Parses the text into json."""
        j = json.loads(self.text)
        if not isinstance(j, list):
            j = [j]
        for each in j:
            self.interpretations.append(Interpretation(self.keyword, self.more, each.get("word", self.keyword),
                                                       each.get("phonetic", ""),
                                                       each.get("meaning")))

    def output(self):
        """Write all interpretations to the console."""
        for interpretation in self.interpretations:
            interpretation.output()

The   get_request() function attempts calls to each of the API’s hosts, storing the returned data string in the text attribute. parse_text() loads the JSON and creates a list of intepretations which correspond to a particular definition for a word. For example the word “cat” also means “to raise an anchor” or “Computer Assisted Testing” in addition to a small furry domestic animal. Each interpretation is held in the Interpretation class, which is created using the keyword (e.g. “cat”), the phonetic description of the word and the meaning from the Google dictionary. I also provide a more flag which, if true, basically tells the parser to output more definitions and synonyms for the word; this option can be set by the user from the command line.

The Interpretation class is also very simple.

class Interpretation:
    def __init__(self, keyword, more, word, phonetic, meanings):
        """Contains a single interpretation of the a particular word"""
        self.keyword = keyword
        self.more = more
        self.word = word
        self.phonetic = phonetic
        self.meanings = meanings

    def output(self):
        """Outputs the stored word, meanings and phonetics to the terminal."""
        head = "{} . {} . {}".format(self.keyword, self.word, self.phonetic)
        print("{}{}{}".format(TerminalColours.HEADER, head, TerminalColours.ENDC))
        for k, type in self.meanings.items():
            print("{}{}{}".format(TerminalColours.HEADER, k, TerminalColours.ENDC))
            for i, meaning in enumerate(type):
                print()
                # Only output the first 2 definitions for each group, unless more is provided.
                if i > 1 and not self.more:
                    break
                for base_colour, group in [(TerminalColours.OKGREEN, "definition"),
                                           (TerminalColours.OKBLUE, "synonyms")
                                           (TerminalColours.OKBLUE, "antonyms")]:
                    if group in meaning.keys():
                        vals = meaning.get(group, "")
                        if isinstance(vals, list):
                            # Just output the first 5 arguments
                            if not self.more:
                                vals = vals[:5]
                            vals = ", ".join(vals)
                        print("{} - {}: {}{}".format(base_colour, group, vals, TerminalColours.ENDC))
            print()

output() writes the phonetics, definitions and synonyms to the terminal, with some pretty colouring.

Usage

We want to be able to call our script from the command line. In Python we use the argparse module.

parser = argparse.ArgumentParser()
parser.add_argument("search", nargs="+", help="type the word you want to search here")
parser.add_argument(
    "--more",
    dest="more",
    action="store_true",
    required=False,
    default=False,
    help="Get more synonyms and antonyms.",
)
args = parser.parse_args()
searchword = " ".join(args.search)
d = DictionarySearch(searchword, args.more)
d.get_request()
d.parse_text()
d.output()
if not args.more:
    print("Find more synonyms and antonyms by running with --more.")

To provide a convenient wrapper for this script (named google_define.py) which can be called for everywhere, add the following to your .bashrc.

dict(){
	python /path/to/DictionaryCLI/google_define.py $@
}

And that’s it! We can lookup the word “cat” using dict cat or get more definitions dict cat --more.

The output looks something like the below.

Leave a Reply

Your email address will not be published. Required fields are marked *