Skip to content

Instantly share code, notes, and snippets.

@gridhead
Last active July 8, 2022 02:09
Show Gist options
  • Save gridhead/f5a4f5d69e72aef5547e1dcc6a2786ef to your computer and use it in GitHub Desktop.
Save gridhead/f5a4f5d69e72aef5547e1dcc6a2786ef to your computer and use it in GitHub Desktop.
Answer for CPE role
"""
This program runs an API server on a local address on port 5000, for users to
connect to it and have their local time converted into UTC using parameterized
GET requests by making use of Falcon, PyTZ and Werkzeug
"""
import datetime
from json import dumps
from sys import exit
from os import path
import falcon
import pytz
from werkzeug import serving
main = falcon.API()
class receive_and_transmit(object):
def convert_to_other_timezone(self, hour:int, mint:int, tzdt:str):
"""
Converts the given time (in hours and minutes) of the provided timezone
to UTC and returns a dictionary with "hour" and "mint" keys
"""
recvtime = datetime.datetime(
datetime.datetime.now().year,
datetime.datetime.now().month,
datetime.datetime.now().day,
hour,
mint
)
curttmzn = pytz.timezone(tzdt)
mdfdzone = pytz.timezone("UTC")
curtloca = curttmzn.localize(recvtime)
mdfdtime = curtloca.astimezone(mdfdzone)
hourtext = str(mdfdtime.hour)
minttext = str(mdfdtime.minute)
if mdfdtime.hour < 10:
hourtext = "0" + hourtext
if mdfdtime.minute < 10:
minttext = "0" + minttext
return {
"hour": hourtext,
"mint": minttext
}
def on_get(self, rqst, resp):
"""
Receive hour, minute, current timezone and return UTC hour and minute
If there are exceptions, return failure message
HTTP Method : GET
"""
try:
hour = rqst.get_param("hr")
mint = rqst.get_param("min")
tzdt = rqst.get_param("tz")
"""
If source timezone is not entered, this would make use of the
local timezone of the server
"""
if tzdt is None:
tzdt = "/".join(path.realpath("/etc/localtime").split("/")[-2:])
"""
If the time is not entered, the time at the local timezone of
the server would be considered
"""
if hour is None and mint is None:
hour = datetime.datetime.now().hour
mint = datetime.datetime.now().minute
retn = self.convert_to_other_timezone(int(hour), int(mint), str(tzdt))
except Exception as expt:
print("EXCEPTION", expt)
retn = {
"mesg": "FAIL",
"expt": str(expt)
}
resp.body = dumps(retn, ensure_ascii=False)
resp.set_header("Access-Control-Allow-Origin", "*")
resp.status = falcon.HTTP_200
def mainfunc():
"""
Assign the "/" endpoint to the object
Start serving the WSGI object on IP 127.0.0.1 and port 5000
"""
recvtran = receive_and_transmit()
main.add_route("/", recvtran)
serving.run_simple("127.0.0.1", 5000, main)
if __name__ == "__main__":
"""
Executable part of the code
[Ctrl+C] to exit
"""
try:
mainfunc()
except KeyboardInterrupt:
exit()

Answers to the questions

1. Development

Following are the usage instructions for the attached code.

  1. Create a virtual environment by executing virtualenv venv and activate it by executing source venv/bin/activate.
  2. Download the requirements.txt and install the dependencies by running pip3 install -r requirements.txt.
  3. Download the main.py file and run it using python3 main.py.
  4. On another terminal, type in curl "http://127.0.0.1:5000/?tz=Europe/Paris&hr=10&min=5".
  5. You should get the output {"hour": "08", "mint": "05"}.
  6. If a source timezone is not entered, this would make use of the local timezone of the server. So for curl "http://127.0.0.1:5000/?hr=10&min=6" command...
  7. You should get the output {"hour": "04", "mint": "36"}. (Local timezone being IST = UTC +05:30)
  8. If no parameters are passed, this would make use of the local time and the local timezone of the server. So for curl "http://127.0.0.1:5000" command...
  9. You should get a variable output {"hour": "02", "mint": "47"}. (Local timezone being IST = UTC +05:30, Local time being 08:17 at the time of executing this)

2. Working with existing Python code

The following are the steps I took in order to perform the mentioned tasks.

  1. Created an empty repository on GitHub under my own username namespace with the following settings.
    1. Repository has been named pythview.
    2. Repository description has been set to Random repository here - Please ignore if you have run into it by mistake.
    3. Visibility of the repository has been set to Public.
    4. No README.md file was added automatically.
    5. No .gitignore file was added automatically.
    6. No default license was chosen from the repository.
  2. Cloned the repository locally by executing git clone https://github.com/Zlopez/python_interview.git.
  3. Removed the existing upstream by executing git remote remove origin.
  4. Added a new remote origin location for the repository by executing git remote add origin https://github.com/t0xic0der/pythview.git.
  5. Displayed the name of all available branches locally by executing git branch --all.
  6. With main being the only branch present, executed git branch -M main as the remote has no branches with the name main available.
  7. Pushed the code of the current main branch to the new remote location by executing git push -u origin main.
  8. Executed the code python test.py.
    [t0xic0der@fedorable python_interview]$ python test.py 
    Traceback (most recent call last):
      File "/home/t0xic0der/Projects/python_interview/test.py", line 41, in <module>
        no_dup_list = remove_duplicates(unsorted_list)
      File "/home/t0xic0der/Projects/python_interview/test.py", line 18, in remove_duplicates
        return no_dup_dct
    NameError: name 'no_dup_dct' is not defined
    
  9. There seemed to be a typographical mistake on line #18. Changed variable name no_dup_dct to no_dup_dict.
  10. Executed the code again python test.py.
    [t0xic0der@fedorable python_interview]$ python3 test.py 
    Traceback (most recent call last):
      File "/home/t0xic0der/Projects/python_interview/test.py", line 44, in <module>
        assert no_dup_list == [1, 2, 5, 3, 20, 15]
    AssertionError
    
  11. An assertion error occurred as the first comparison resulted False. Made some changes in the remove_duplicates function in order for it to function properly and executed it again python3 test.py.
    [t0xic0der@fedorable python_interview]$ python3 test.py
    Traceback (most recent call last):
      File "/home/t0xic0der/Projects/python_interview/test.py", line 53, in <module>
        assert sorted_list == [1, 2, 3, 5, 15, 20]
    AssertionError
    
  12. Another assertion error occurred as the second comparison resulted False. Made some changes in the sort_list function in order for it to function properly and executed it again python3 test.py.
    [t0xic0der@fedorable python_interview]$ python3 test.py
    
  13. The program executed just fine. Then, the changes were committed and pushed to new branch called miscellaneous-fixes by executing the following commands in succession.
    [t0xic0der@fedorable python_interview]$ git branch add miscellaneous-fixes
    
    [t0xic0der@fedorable python_interview]$ git checkout miscellaneous-fixes
    
    [t0xic0der@fedorable python_interview]$ git add test.py
    
    [t0xic0der@fedorable python_interview]$ git commit -m "Fixed the function definitions"
    [miscellaneous-fixes 4028b0d] Fixed the function definitions
    
    [t0xic0der@fedorable python_interview]$ git push --set-upstream origin miscellaneous-fixes
     1 file changed, 6 insertions(+), 2 deletions(-)
    Enumerating objects: 5, done.
    Counting objects: 100% (5/5), done.
    Delta compression using up to 4 threads
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (3/3), 387 bytes | 387.00 KiB/s, done.
    Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
    remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
    remote: 
    remote: Create a pull request for 'miscellaneous-fixes' on GitHub by visiting:
    remote:      https://github.com/t0xic0der/pythview/pull/new/miscellaneous-fixes
    remote: 
    To https://github.com/t0xic0der/pythview.git
    * [new branch]      miscellaneous-fixes -> miscellaneous-fixes
    Branch 'miscellaneous-fixes' set up to track remote branch 'miscellaneous-fixes' from 'origin'.
    
  14. The code can be found here at https://github.com/t0xic0der/pythview and the changes made by me can be found at https://github.com/t0xic0der/pythview/tree/miscellaneous-fixes.

3. Troubleshooting

The following are the steps that I would take in order to troubleshoot the situation when the connection to internet is down on my machine.

  1. Try opening up different websites on browser to confirm if there is a total outage or an inability to connect to certain services only. (Firefox or any such browser)
  2. Toggle connection from my machine to my Wifi router off and on to see if that helps to restore the connection and brings back online. (GNOME settings)
  3. Visit the Wifi router management page http://192.168.0.1/admin/index.html#/home to check on ingress-egress activity on the WAN connection. (DLink router page on Firefox or any such browser)
  4. Check if there is an excessive usage of bandwidth by any of the locally connected device - that results in unavailability on my machine. (DLink router page on Firefox or any such browser)
  5. Confirm if there any active firewalls running which disallows connections or if any VPN service is enabled to allow for certain traffic conditions only. (firewalld if installed or GNOME settings)
  6. Substantiate DNS, gateways and route configurations and verify if they have not been changed inexplicably by any misbehaving applications. (GNOME settings - Wifi page)
  7. If all else fails, reach out to the internet service provider to inquire about downtimes and of estimated time of service getting back online. (Phone)

4. Git

In order to update my fork with the upstream changes on a specific branch (here, master), the following steps were performed.

  1. The project forge was forked from AstroSonic's namespace (i.e. https://github.com/astrosonic/forge) to my namespace (i.e. https://github.com/t0xic0der/forge).
  2. The upstream repo was cloned locally and changes were made to the requirements.txt file in order to make sure that the dependencies do not point to a specific version.
  3. The changes were committed to a branch called non-specific-requirements (https://github.com/astrosonic/forge/tree/non-specific-requirements), pushed (https://github.com/astrosonic/forge/pull/42/commits/5d1eecdf3f4962ae08dc98e33308c5626db719f3), a PR was created (astrosonic/forge#42) and merged to master.
  4. Now, the fork from my namespace is cloned locally and the following commands were executed in succession.
    [t0xic0der@fedorable forge]$ git remote add upstream https://github.com/astrosonic/forge.git
    
    [t0xic0der@fedorable forge]$ git fetch upstream
    remote: Enumerating objects: 6, done.
    remote: Counting objects: 100% (6/6), done.
    remote: Compressing objects: 100% (3/3), done.
    remote: Total 4 (delta 2), reused 2 (delta 1), pack-reused 0
    Unpacking objects: 100% (4/4), 888 bytes | 888.00 KiB/s, done.
    From https://github.com/astrosonic/forge
    * [new branch]      electron-application      -> upstream/electron-application
    * [new branch]      legacy-layout             -> upstream/legacy-layout
    * [new branch]      master                    -> upstream/master
    * [new branch]      modern-layout             -> upstream/modern-layout
    * [new branch]      non-specific-requirements -> upstream/non-specific-requirements
    
    [t0xic0der@fedorable forge]$ git rebase upstream/master
    Successfully rebased and updated refs/heads/master.
    
    [t0xic0der@fedorable forge]$ git push origin master
    Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
    To https://github.com/t0xic0der/forge
       48f679f..8673de6  master -> master
    
  5. This happened seamlessly here because there were no changes made to the fork, which were disjoint from those of the upstream. In a way, it can be said that the commits in the fork were a subset of that of the upstream. But if there are changes made to the fork which do not exist in the upstream - these changes would be divergent and in such cases, a normal push may be rejected due to disjoint changes. Then, one can either merge the changes from the upstream to the fork to have both of the changes or force-push the rebase. Discretion is advised with using the latter as that would end up overwriting the changes made on the fork in the favor of retaining those of the upstream.
falcon>=3.0.1
pytz>=2021.1
Werkzeug>=2.0.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment