IP Challenge: Part 3-5

So far we have setup our empty class and have initialized our folders modules as a python package, so far so good. This challenge is going to cover:

Let’s jump right into it.


Class Creation and Initialization

Test Trigger:
pipenv run python -m unittest tests/test_challenge_3.py -f

Instructions

  • Import the package requests. Beware: It is more beneficial to load only the packages that you need, in this case you will need the method get from requests package.
  • Modify your IPInfo class inside ipinfo.py and define your initialization module. This initialization will require only one parameter of type string and will be called ip.
  • Create a Class Attribute named ip_data. This class attribute will requests a json response from the public API https://ipinfo.io/IP_NUMBER/json where IP_NUMBER is equal to the initialization parameter ip. To challenge yourself, try to make this JSON request in a single line.

Walkthrough

To make this work we will first import the requests package and modify our class IPInfo, we will add an initialization method that makes a GET request to a desired IP.

from requests import get as rget

class IPInfo():
def __init__(self, ip):
self.ip_data = rget(f'https://ipinfo.io/{ip}/json').json()
  • As you can see, we first imported the method get from the package requests and give it the alias of rget because “get” is too generic.
  • Then we write an initialization method in our class IPInfo and store the contents of the given requests into our variable ip_data

This is enough to make the challenge #3 pass.

.
----------------------------------------------------------------------
Ran 1 test in 0.543s

OK


Object Representation and Iteration

Test Trigger:
pipenv run python -m unittest tests/test_challenge_4.py -f

Instructions

  • Change the object representation of your class to return Geolocation information of IP_ADDR where IP_ADDR is equal to the IP address of the requested JSON data stored in self.ip_data
  • Create a iterable method that allows iteration in your class. For every key and value stored in the dictionary self.ip_data you should yield a (key, value) tuple, e.g: ('ip', '8.8.8.8'). This way you should be able to yield a generator.

Walkthrough

Let’s add the special module __repr__ to change the representation of our class, and an __iter__ module to enable iteration in our class.

class IPInfo():

...

def __repr__(self):
return f"Geolocation information of {self.ip_data['ip']}"

def __iter__(self):
for key, value in self.ip_data.items():
yield key, value

With this we have completed challenge 4.

..
----------------------------------------------------------------------
Ran 2 tests in 0.817s

OK

We can check how this works in the python interpreter.

>>> from modules import IPInfo
>>> ip_data = IPInfo('8.8.8.8')
>>> ip_data
Geolocation information of 8.8.8.8
>>> for data, value in ip_data:
... print(f'{data.capitalize()}: {value.capitalize()}')
...
Ip: 8.8.8.8
Hostname: Google-public-dns-a.google.com
City: Mountain view
Region: California
Country: Us
Loc: 37.3860,-122.0840
Postal: 94035
Phone: 650
Org: As15169 google llc

See how easy it was? Let’s move on to challenge 5.


Code Documentation

This is one of the easiest one, it’s all about documentation, we should document our code, modules, and packages with docstrings.

Test Trigger:
pipenv run python -m unittest tests/test_challenge_5.py -f

Instructions

  • You should always document your modules, classes and method definition with triple quoted strings, following the PEP8 recommendations on Docstrings. To see the modules, packages, and classes that you should document try running pydocstyle.

Walkthrough

If we run pydocstyle we will encounter the following errors:

modules/__init__.py:1 at module level:
D104: Missing docstring in public package
modules/ipinfo.py:1 at module level:
D100: Missing docstring in public module
modules/ipinfo.py:3 in public class `IPInfo`:
D101: Missing docstring in public class
modules/ipinfo.py:4 in public method `__init__`:
D107: Missing docstring in __init__
modules/ipinfo.py:7 in public method `__repr__`:
D105: Missing docstring in magic method
modules/ipinfo.py:10 in public method `__iter__`:
D105: Missing docstring in magic method

That means that we need to document these packages and modules, this is a very good practice that you have to maintain.

# __init__.py
"""Initialize modules folder as a package."""

from .ipinfo import IPInfo

__all__ = ['IPInfo']

Also we should document our ipinfo.py module, class and methods.

"""Module that handles IPInfo classes and methods."""

from requests import get as rget

class IPInfo():
"""Handles ipinfo.io communication and data."""

def __init__(self, ip):
"""Initialize IPInfo object into with geolocation data."""
self.ip_data = rget(f'https://ipinfo.io/{ip}/json').json()

def __repr__(self):
"""Return a representation of our object."""
return f"Geolocation information of {self.ip_data['ip']}"

def __iter__(self):
"""Return a key, value tuple of each data to enable iteration."""
for key, value in self.ip_data.items():
yield key, value

After we document our code, the test should pass now.

.
----------------------------------------------------------------------
Ran 1 test in 0.584s

OK

That’s it for this entry, we have learn how to initialize our class into a object, return a representation of our object, and we also enabled iteration in our class. See you next time.