Everyone knows about comments at this point, but did you know that PyCharm can help you write them?
Let’s go to our __init__
constructor and put an empty line between the def line and first line of code:
def __init__(self, hostname: str, api_key: str = '', ver: str = 'v1', ssl_verify: bool = True, logger: logging.Logger = None):
self._logger = logger or logging.getLogger(__name__)
Now type 3 double-quotes """
and hit the Enter
key and PyCharm should auto-create comments like so:
"""
:param hostname:
:param api_key:
:param ver:
:param ssl_verify:
:param logger:
"""
Now we can fill them in with useful information, like this:
"""
Constructor for RestAdapter
:param hostname: Normally, api.thecatapi.com
:param api_key: (optional) string used for authentication when POSTing or DELETEing
:param ver: always v1
:param ssl_verify: Normally set to True, but if having SSL/TLS cert validation issues, can turn off with False
:param logger: (optional) If your app has a logger, pass it in here.
"""
Come to think of it, we can tighten up our constructor a little bit by making api.thecatapi.com
the default hostname
:
def __init__(self, hostname: str = 'api.thecatapi.com', api_key: str = '', ver: str = 'v1', ssl_verify: bool = True, logger: logging.Logger = None):
Lookin’ good. Try doing the same for the _do()
method.
What else? The _do()
method could use some less formal comments. Comments aren’t just documentation, they can be notes to anyone else who uses your code (or your future self) about what you think you were doing.
That’s right. Comments should NOT necessarily describe WHAT you are doing step-by-step. The code should already be pretty clear about what it is doing.
What comments should describe is:
- What you THINK you are trying to do
- WHY you are doing it (if it isn’t abundantly clear why)
- HOW you are trying to do it (if what you are doing is rather complex)
The reason why it is “what you THINK you are trying to do” is because the lines that you program may NOT actually do what you think you are doing. And you (or a co-worker) may come back later to debug a section of code, and you (or your co-worker) may stare at that section of code and say “well, no wonder this doesn’t work! This code doesn’t do what the comment says it is supposed to be doing.”
And if you didn’t have that comment there, then it’s much harder to figure out what was supposed to be happening.
Similarly, commenting on the reason WHY is also useful. Sometimes you may write code that does a thing and then come back later and wonder why you did it this way. Commenting on WHY can also be important.
Lastly, writing HOW you are doing something can be helpful as well. As was mentioned previously, your code should already be pretty clear as to what it is doing. So no need to explain HOW some section of code works if it is fairly simple. Though if the code is moderately complex, it is still helpful to explain (broadly) HOW you are doing something.
Let’s add a few more comments:
# Log HTTP params and perform an HTTP request, catching and re-raising any exceptions
try:
self._logger.debug(msg=log_line_pre)
response = requests.request(method=http_method, url=full_url, verify=self._ssl_verify,
headers=headers, params=ep_params, json=data)
except requests.exceptions.RequestException as e:
self._logger.error(msg=(str(e)))
raise TheCatApiException("Request failed") from e
That’s good, let’s try another:
# Deserialize JSON output to Python object, or return failed Result on exception
try:
data_out = response.json()
except (ValueError, JSONDecodeError) as e:
self._logger.error(msg=log_line_post.format(False, None, e))
raise TheCatApiException("Bad JSON in response") from e
And one more:
# If status_code in 200-299 range, return success Result with data, otherwise raise exception
is_success = 299 >= response.status_code >= 200 # 200 to 299 is OK
log_line = log_line_post.format(is_success, response.status_code, response.reason)
if is_success:
self._logger.debug(msg=log_line)
return Result(response.status_code, message=response.reason, data=data_out)
self._logger.error(msg=log_line)
raise TheCatApiException(f"{response.status_code}: {response.reason}")
All that’s left is adding formal ("""
) parameter comments for get()
, post()
, delete()
and the Result
__init__()
methods. Try it yourself!
Step 8: Creating strong data models.
Source code: https://github.com/PretzelLogix/py-cat-api/tree/07_add_comments