allowing the user to input two parameters - python

i want to allow the user to be able to type {misc} of {nation} and specific information will be displayed based on the input. i have tired several different ways but seem to never find a way to make it work. any help is appreciated thanks!
(Sorry about title didnt really know what to title it)
def part1():
txt = "{} of {}"
info = input('''What do you want to know?: ''')
if info == "{} of {}":
print(txt.format(misc.get(info), nations.get(info)))
else:
print("i dont know what your talking about")
nations = {
'fiji': {
'location': 'Oceana',
'capital_city': 'Suva'},
'france': {
'location': 'Europe',
'capital_city': 'Paris'},
}
misc = {'population': {'fiji': '847,706',
'france': '60,495,540'},
'location': {'fiji': 'Oceana',
'france': 'Europe'},
}
part1()

Not sure exactly what you're trying to do, but there are a few issues with your code, try something like this:
def part1():
txt = "{} of {}"
info = input('''What do you want to know?: ''')
if ' of ' in info:
params = info.split(' of ')
else:
print("i dont know what your talking about")
return
print(params[0])
print(misc.get(params[0]).get(params[1]))
nations = {
'fiji': {
'location': 'Oceana',
'capital_city': 'Suva'},
'france': {
'location': 'Europe',
'capital_city': 'Paris'},
}
misc = {'population': {'fiji': '847,706',
'france': '60,495,540'},
'location': {'fiji': 'Oceana',
'france': 'Europe'},
}
part1()
Currently with this code there isnt really a way to know which object you're targeting (nations or misc). To remedy this I would ask the user an initial question to determine which type of info they want.
Additional improvements could be checking the data you're getting from the dictionaries. In the case you get nothing from the dictionaries (.get returns None) you could notify the user the info you have available).

A quick and dirty way to do this if you are not using much data, is to just put the info directly into the if statements and call the function. For instance:
def part1():
info = input("What do you want to know?: ")
if info == "location of fiji":
print("Oceana:")
elif info == "capital_city of fiji":
print("Suva")
elif info == "location of France":
print("Europe")
elif info == "capital_city of France":
print("Paris")
else:
print("i dont know what your talking about")
part1()
If you are using a lot of data points, then it is probably better to have a list/database like you have though. Here's the quick and dirty fix if you want it though.
(Also, if you use this method, you can convert the user input string into all lowercase using .lower I believe. This way, capitalization does not matter when inputting).

A good way to do this would be if else/elif statements that way the program can check for multiple inputs rather then trying to check for 2 different inputs at once.
Viktor Basharkevich has pretty much the right idea on what to do

You could also try a split method
input().split(x, y)
x, y = input("What do you want to know?").split()
This might work
Or you could try a list

Related

Python parse JSON object and ask for selection of values

I am new to programming in general. I am trying to make a Python script that helps with making part numbers. Here, for an example, computer memory modules.
I have a python script that needs to read the bmt object from a JSON file. Then ask the user to select from it then append the value to a string.
{"common": {
"bmt": {
"DR1": "DDR",
"DR2": "DDR2",
"DR3": "DDR3",
"DR4": "DDR4",
"DR5": "DDR5",
"DR6": "DDR6",
"FER": "FeRAM",
"GD1": "GDDR",
"GD2": "GDDR2",
"GD3": "GDDR3",
"GD4": "GDDR4",
"GD5": "GDDR5",
"GX5": "GDDR5X",
"GD6": "GDDR6",
"GX6": "GDDR6X",
"LP1": "LPDDR",
"LP2": "LPDDR2",
"LP3": "LPDDR3",
"LP4": "LPDDR4",
"LX4": "LPDDR4X",
"LP5": "LPDDR5",
"MLP": "mDDR",
"OPX": "Intel Optane/Micron 3D XPoint",
"SRM": "SRAM",
"WRM": "WRAM"
},
"modtype": {
"CM": "Custom Module",
"DD": "DIMM",
"MD": "MicroDIMM",
"SD": "SODIMM",
"SM": "SIMM",
"SP": "SIPP",
"UD": "UniDIMM"
}
}}
Example: There is a string called "code" that already has the value "MMD". The script asks the user what to select from the listed values, (e.g. "DR1"). If a selection is made (user enters "DR1", it appends that value to the string, the new value would be "MMDDR1".
This code is to print the JSON. This is how far I have gotten
def enc(code):
memdjson = json.loads("memd.json")
print(memdjson)
How do I do this?
Repo with the rest of the code is here: https://github.com/CrazyblocksTechnologies/PyCIPN
Try:
import json
def enc(code):
memdjson = json.load(open("memd.json"))["common"]["bmt"]
selected = input("Select a value from the following: \n{}\n\n".format(' '.join(memdjson.keys())))
return code+memdjson[selected]
import json
import inquirer
with open(path_to_json_file) as f:
file = json.load(f)
code = "MMD"
questions = [
inquirer.List('input',
message="Select one of the following:",
choices=list(file["common"]["bmt"].keys()),
),
]
answer = inquirer.prompt(questions)
code += answer

Should I assert the same values in every test?

I have simple class with the public build method I want to test. Currently I assert all values it returns in every test. Is it a good practice or I should write one test for static values and in other tests only check values which change depending on input?
Implementation
class FiltersAttachment:
TYPE_OPTIONS = [
{"text": "All types", "value": "all"},
{"text": ":link: Webpages", "value": "web_pages"}
]
STATUS_OPTIONS = [
{"text": "Available / Unavailable", "value": "all"},
{"text": ":white_circle: Available", "value": "available"},
{"text": ":red_circle: Unavailable", "value": "unavailable"}
]
#classmethod
def _filter_options(cls, options, selected):
return list(filter(lambda t: t['value'] == selected, options))
#classmethod
def build(cls, check_type='', status=''):
return {
'fallback': 'Filters',
'callback_id': 'resource_filters',
'color': '#d2dde1',
'mrkdwn_in': ['text'],
'actions': [
{
'name': 'resource_type',
'text': 'Type',
'type': 'select',
'options': cls.TYPE_OPTIONS,
'selected_options': cls._filter_options(
cls.TYPE_OPTIONS, check_type)
},
{
'name': 'resource_status',
'text': 'Status',
'type': 'select',
'options': cls.STATUS_OPTIONS,
'selected_options': cls._filter_options(
cls.STATUS_OPTIONS, status)
}
]
}
Tests
class TestFiltersAttachment(TestCase):
def assert_attachment(self, attachment):
self.assertEqual(attachment['fallback'], 'Filters')
self.assertEqual(attachment['callback_id'], 'resource_filters')
self.assertEqual(attachment['color'], '#d2dde1')
self.assertEqual(attachment['mrkdwn_in'], ['text'])
type_action = attachment['actions'][0]
self.assertEqual(type_action['name'], 'resource_type')
self.assertEqual(type_action['text'], 'Type')
self.assertEqual(type_action['type'], 'select')
self.assertEqual(type_action['options'][0]['text'], 'All types')
self.assertEqual(type_action['options'][0]['value'], 'all')
self.assertEqual(type_action['options'][1]['text'], ':link: Webpages')
self.assertEqual(type_action['options'][1]['value'], 'web_pages')
status_action = attachment['actions'][1]
self.assertEqual(status_action['name'], 'resource_status')
self.assertEqual(status_action['text'], 'Status')
self.assertEqual(status_action['type'], 'select')
self.assertEqual(status_action['options'][0]['text'], 'Available / Unavailable')
self.assertEqual(status_action['options'][0]['value'], 'all')
self.assertEqual(status_action['options'][1]['text'], ':white_circle: Available')
self.assertEqual(status_action['options'][1]['value'], 'available')
self.assertEqual(status_action['options'][2]['text'], ':red_circle: Unavailable')
self.assertEqual(status_action['options'][2]['value'], 'unavailable')
def test_all_type_selected(self):
attachment = FiltersAttachment.build(check_type='all')
self.assert_attachment(attachment)
selected_type = attachment['actions'][0]['selected_options'][0]
self.assertEqual(selected_type['text'], 'All types')
self.assertEqual(selected_type['value'], 'all')
def test_all_status_selected(self):
attachment = FiltersAttachment.build(status='all')
self.assert_attachment(attachment)
selected_status = attachment['actions'][1]['selected_options'][0]
self.assertEqual(selected_status['text'], 'Available / Unavailable')
self.assertEqual(selected_status['value'], 'all')
...
One of the criteria for the quality of a test suite is, how well the test suite supports you in case of test failures to identify the problem. Ideally, you should be able to identify the problem alone by looking at which tests failed and which did not. You should not need to use a debugger to find out what actually went wrong.
The way you have written your tests will not give you the best possible support. You have packed many assertions in one test function. Therefore, the test functions will fail for many different reasons, and when you see one of the functions fail, you will have to do a detailed analysis or use debugging to find out for which reason it failed. When making your tests check aspects redundantly (as you have asked in your question), you make them even less specific, which makes the problem worse.
Therefore, each test should check one specific aspect, such that a failure of a test gives the most specific information. This is achieved by the combination of the following two principles:
Each test should verify one specific aspect.
There should not be redundant tests for the same aspect.
Turning each assertion into a test of its own can be done conveniently with the help of so called parameterized tests. Some hints for Python can be found at this question: How do you generate dynamic (parameterized) unit tests in python?

Attendees in Google Calendar not always in the same order

So I've just started using the google calendar api and I've had good results so far. I add attendees with their name and email in the events dictionary, like so
events = {
# other stuff here and then this
'items': [
# lots of stuff here, followed by
'attendees': [
{
'email': email1,
'displayName': name1
},
{
'email': email2,
'displayName': name2
},
],
###
]
}
Adding them goes fine, but when I access them, I'm never guaranteed of their order. I thought I could just access the emails like this
for event in events['items']:
print "email1 = " + str(event['attendees'][0]['email'])
print "email2 = " + str(event['attendees'][1]['email'])
and I can. And I've learned that lists in python always have their order preserved, which is convenient because I wanted to access the dictionaries inside the list with the index of the list. But what I've learned is that sometimes the 0 index refers to email1 and sometimes it refers to email2. Why the inconsistency? Is it inherent to the google calendar api or is there something about having dictionary objects within a python list that relaxes the order preservation assumption? Or is it something else I'm missing?
So, as #Colonel Thirty Two pointed out, while lists preserve order, how google return data into a list may not be in the same order as it was submitted to them. This order inconsistency with attendees is inconvenient if you are wanting to count on that order for the retrieval of attendees with something like
for event in events['items']:
print "email1 = " + str(event['attendees'][0]['email'])
print "email2 = " + str(event['attendees'][1]['email'])
What's more is that very few fields are writable with the google calendar api. What is writable, however, is comments. So, I added a value to that field to make the attendees identifiable. Like so
'attendees': [
{
'email': agent_email,
'displayName': agent_name,
'comment': 'agent'
},
{
'email': event_attendee_email,
'displayName': event_attendee_name,
'comment': 'client'
},
Using comment as an identifier helped me in retrieving the email and displayName of each attendee with a simple if-statement.
for i in range(len(event['attendees'])):
if event['attendees'][i]['comment'] == 'client':
event['attendees'][i]['displayName'] = event_attendee_name
event['attendees'][i]['email'] = event_attendee_email
Now it doesn't matter that the google calendar api submits my attendees back to me in a different order than the one in which I added them. I can now retrieve the attendees so I can change them. Problem solved.

Checking if epic issue exists and if not, make a new epic issue

So the problem is an IndexError, which makes sense considering there isn't supposed to be any results for that jql query.
epic_search = 'project = "EXM" and type = Epic and summary ~ "summaryx" '
esearch = jira.search_issues(epic_search)
if esearch[0].key == None:
epic_dict = {
'project': {'key': 'EXM'},
'customfield_12345': 'summaryx',
'summary': 'summaryx',
'issuetype': {'name': 'Epic'},
}
new_epic = jira.create_issue(fields=epic_dict)
print (new_epic.key)
Is there a way I can check the jql results and if empty, create an epic?
Probably something like
if (count(esearch) > 0):
I assume this is python. I don't do python but there must be something like a count() or maybe esearch.length to tell you how many items are in there.

List in a dictionary, looping in Python

I have the following code:
TYPES = {'hotmail':{'type':'hotmail', 'lookup':'mixed', 'dkim': 'no', 'signatures':['|S|Return-Path: postmaster#hotmail.com','|R|^Return-Path:\s*[^#]+#(?:hot|msn)','^Received: from .*hotmail.com$']},
'gmail':{'type':'gmail', 'lookup':'mixed', 'dkim': 'yes', 'signatures':['|S|Subject: unsubscribe','','','']}
}
for type_key, type in TYPES.iteritems():
for sub_type_key, sub_type in type.iteritems():
for sig in sub_type['signatures']:
if ("|S|" in sig):
#String based matching
clean_sig = sig[3:len(sig)]
if (clean_sig in file_contents):
sig_match += 1
elif ("|R|" in sig):
clean_sig = sig[3:len(sig)]
#REGMATCH later
if (sig_match == sig.count):
return sub_type['type']
return None
However, it generates the error:
for sig in sub_type['signatures']:
TypeError: string indices must be integers, not str
I assume that it would see the list being pulled from dictionary element, and allow me to loop over that?
Python newbie is a newbie :(
for type_key, type in TYPES.iteritems():
for sub_type_key, sub_type in type.iteritems():
for sig in sub_type['signatures']:
should be:
for type_key, type in TYPES.iteritems():
for sig in type['signatures']:
But 'type' is a poor name choice in this case... you don't want to shadow a builtin.
Essentially, 'type_key' has the name (either 'hotmail' or 'gmail'), and 'type' has the dictionary that is the value associated with that key. So type['signatures'] is what you're wanting.
Also, you may not need to have 'gmail' inside the nested dictionary; just return 'type_key' instead of type['type'].
Bringing it all together, maybe this will work better: (Warning: untested)
providers = {
'hotmail':{
'type':'hotmail',
'lookup':'mixed',
'dkim': 'no',
'signatures':[
'|S|Return-Path: postmaster#hotmail.com',
'|R|^Return-Path:\s*[^#]+#(?:hot|msn)',
'^Received: from .*hotmail.com$']
},
'gmail':{
'type':'gmail',
'lookup':'mixed',
'dkim': 'yes',
'signatures':['|S|Subject: unsubscribe','','','']
}
}
for provider, provider_info in providers.iteritems():
for sig in provicer_info['signatures']:
if ("|S|" in sig):
#String based matching
clean_sig = sig[3:len(sig)]
if (clean_sig in file_contents):
sig_match += 1
elif ("|R|" in sig):
clean_sig = sig[3:len(sig)]
#REGMATCH later
if (sig_match == sig.count):
return provider
return None
[Posted as an answer instead of a comment because retracile beat me to the answer, but the formatting is still a point worth making.]
Laying out the data helps to visualize it:
TYPES = {
'hotmail': {
'type': 'hotmail',
'lookup': 'mixed',
'dkim': 'no',
'signatures': ['|S|Return-Path: postmaster#hotmail.com',
'|R|^Return-Path:\s*[^#]+#(?:hot|msn)',
'^Received: from .*hotmail.com$'],
},
'gmail': {
'type': 'gmail',
'lookup': 'mixed',
'dkim': 'yes',
'signatures': ['|S|Subject: unsubscribe', '', '', ''],
},
}
Note: You can have an ending comma after the last item in a dict, list, or tuple (used above only for the dicts—it's not always more clear), and you don't have to worry about screwing around with that comma, which is a Good Thing™.

Categories

Resources