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.