View Source

An Overview of Python Tools

Python provides many lightweight and easy to implement approaches to creating tools to aid in a project. This page will provide a highlevel peek into a few of these tools.

Command Line Tools

It is very easy to create tools in Python, with simple text interfaces that can be launched from any command line.

1. Input() functions

userChoice = input(“What would you like to do? “)
print("You have selected:",userChoice)

2. Cmd Module

The cmd module lets you create input classes that have streamlined handling for common input features.
  • Consistent prompt display: Universal text display for the input prompt can be defined, to create a consistent user interface, or one that leverages variables to keep the user informed.

  • Built-in Commands: do_ functions that automatically trigger when a user type the string specified after do_

  • Argument Handling: do_ commands automatically capture all text the user inputs after the first word and passes it to the function as arg variable.

  • Layered Command Classes: It is also possible to create cmd classes that inherit other cmd classes. In this way you can create areas of the interface that have specific commands, while also continuing to provide the “global” command options of the inherited class.

  • And much more: Many additional features are not used in this example, such as universal logic that happens right before a command processes, or after it processes. Look up the cmd module’s docs to learn more.

import cmd

class prompt(cmd.Cmd):
"""This class creates a general prompt interface with commands and behaviors that we define"""

# The default prompt text
prompt = "\n (Type <help> to see available commands)\n: "

def emptyline(self):
"""When a user presses enter without typing anything, do nothing."""
return False

def do_greet(self, arg="uh, you there"):
"""Any function within this class with the prefix do_ is a command function. If the user inputs 'greet' then this is triggered."""
# arg is any text the user input after 'greet'. We set it to a default value in case they only put 'greet'
print("Hello",arg)

if name == '__main__':
running True
while running:
"""Always loop so the user can take various actions at their own pace, and an interface does not have to be linear"""
prompt().cmdloop() # launch the prompt class

API Calls

Basic API Calls

import requests # API module for python
spaceRequest = requests.get("http://api.open-notify.org/iss-now.json")
print("Request Status Code:",spaceRequest.status_code)
# Use .json() to extract the response JSON as a dictionary
print("Request Response:",spaceRequest.json())

API Calls with authentication

import requests # API module for python
username = "your@email.com"
password = "your testrail api key here"
params = "/get_users"
session = requests.Session() # create a session request instance
session.auth = (username, password) # set auth for the session instance
testrailRequest = session.request(
"get",
"https://ultratesting.testrail.net/index.php?api/v2"+params,
headers={'Content-type': 'application/json'},
json={}
)
print("All Testrail Users:",testrailRequest.json())

Working with JSONs

Python provides a few useful tools for handling JSONs. JSONs are very common, especially in APIs. They also can be used as an external data file, that is very easy to Python to use, after it has been converted into a dictionary.

Converting between JSON and Python Dictionary

JSONs and python dictionaries use basically the same structure, so once you convert them and can use Python dictionary logic you have a lot of tools at your disposal.
  • Bracket Notation: You can call items from a JSON with bracket notation after it has been converted into a dictionary.

  • For Loops: Yeah you can use for loops on JSONs after it has been converted to a dictionary.

  • Create JSONs: You can also create your own JSONs from a dictionary, for saving locally or for sending with API requests etc

  • Notes to Keep in Mind:

    • API Responses: When handling an API response, using .json() on the response automatically converts the response to a dictionary. So json.loads() is not necessary.

    • Pretty Printing JSONs/Dictionaries: Using json.dumps(dict_or_json, indent=4) will insert newlines and indentations and can be used on either JSONs or dictionaries.

import json
# Example JSON:
spaceJson = '{"timestamp": 1591892387, "iss_position": {"longitude": "-62.1486", "latitude": "49.4040"}, "message": "success"}'

# Convert the JSON into a dictionary
spaceDict = json.loads(spaceJson)
# Call items in the dictionary with bracket syntax
print("Call specific item within the JSON with dictionary's bracket syntax:",spaceDict["message"])
# Convert a dictionary back into a JSON, for like saving locally or sending in an API request or whatever
outputJson = json.dumps(spaceDict)
# Convert a dictionary back into a JSON, but include human readable newlines and indentations
outputJson = json.dumps(spaceDict, indent=4)
print(outputJson)

Working with Local Files

Referencing Sensitive Data (Creds, auth, etc)

When working with code that requires sensitive data it is important to store such things outside of your code, so that it is not captured in the Github Repo or whatever equivalent approach you use to sharing and backing up your code.
IMPORTANT: Exclude files with sensitive data from version control. If using Github this is accomplished by placing the filename within the .gitignore file.
  • Examples of sensitive data:

    • usernames

    • passwords

    • api keys

    • authentication

"""External Storage of Sensitive Data"""
# 1. Store credentials in this folder in a file named .env
import os
from dotenv import load_dotenv
project_folder = os.path.expanduser('') # local path
load_dotenv(os.path.join(project_folder, '.env'))
# 2. Grab credentials as needed: os.getenv("varname")

Referencing Non-sensitive Data (Environmentals)

This approach is also useful for storing environmentals that may need to be referenced by multiple files. Just remember that the sensitive stuff needs to be excluded from any sharing/backup approach, but non-sensitive environmentals can be placed in a file that is saved/shared.

Saving to File

saveStuff = "Stuff that is going to be saved in a file"
# Define filename to save
filename = "untitled.txt"
# Create (or open an existing) file named filename
savingFile = open(filename, "w")
# Fill (or overwrite) the file contents with saveStuff
savingFile.write(saveStuff)
# Finish up
savingFile.close()

Unique Filenames (avoiding overwriting files)

In order to avoid overwriting files when saving stuff, I like to use datetime in the filenames, so they are always unique.

from datetime import datetime
time = datetime.today().strftime('%Y-%m-%d-HELPM%S')
filename = "newfile"+"_"+time

Saving Files in Subfolders

If you are saving files then there is a good chance we don’t want to be saving the files into the same place our main code is. Saving into subfolders is easy, but keep in mind:
  • You can save into a folder simply by including it in the filename string folderName/fileName.txt

  • Folders have to exist before you can save into them

  • # Make the "subfolder/" folder if it doesn't exist
    import os
    os.mkdir(subfolder) if not os.path.exists(subfolder) else False

Local JSON Files

By combining our knowledge of dictionaries and JSONs, with our knowledge of saving files, we can build dictionaries and save them as JSON files in a local folder. We can also load local JSON files and interpret them as dictionaries.
This approach means that we can create external JSON files full of variables to be interpreted by our code. This empowers us to create customized executions of our code, useful for creating testcases for example.

Loading Local JSONs

import json with open("untitled.json") as json_file: grabbedFile = json.load(json_file)

Saving Local JSONs</pre>

import json
# Convert JSON to a dictionary
saveStuff = json.loads(grabbedFile)

# Save dictionary as a local JSON file
filename = "untitled.json"
savingFile = open(filename, "w")
json.dump(saveStuff, savingFile, indent = 4)
savingFile.close()
Topic revision: r1 - 16 Jun 2020, DonnyNavarro
© 2020 Ultranauts - 75 Broad Street, 2nd Floor, Suite 206, New York, NY 10004 - info@ultranauts.co