Python API JSON dictionary loop - python

My code is working, but I know there has to be a more efficient way to accomplish it and better exception handling.
API data format per item:
{
u'logEnd':False,
u'logBegin':True,
u'links':{
u'self': u'https://192.168.15.140/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/policy/accesspolicies/00505689-7E52-0ed3-0000-184683643989/accessrules/00505689-7E52-0ed3-0000-000268439552'
},
'sourceNetworks':'any-src',
u'name':u'Peer-to-Peer Blocking',
'sourceZones':'any-src-zn',
u'enabled':True,
'sourcePorts':'any-src-port',
u'logFiles':False,
u'vlanTags':{ },
u'applications':{
u'applications':[
{
u'type':u'Application',
u'id':u'61',
u'name':u'BitTorrent'
},
{
u'type':u'Application',
u'id':u'571',
u'name':u'BitTorrent tracker'
},
{
u'type':u'Application',
u'id':u'1214',
u'name':u'ExtraTorrent'
}
]
},
u'sendEventsToFMC':True,
u'action':u'BLOCK',
'destinationPorts':'any-dest-port',
'destinationNetworks':'any-dest',
u'variableSet':{
u'type':u'VariableSet',
u'name':u'Default Set',
u'id':u'76fa83ea-c972-11e2-8be8-8e45bb1343c0'
},
u'type':u'AccessRule',
u'id':u'00505689-7E52-0ed3-0000-000268439552',
'destinationZones':'any-dst-zn',
u'metadata':{
u'category':u'--Undefined--',
u'accessPolicy':{
u'type':u'AccessPolicy',
u'name':u'PVmain1-ACPolicy-201610251131',
u'id':u'00505689-7E52-0ed3-0000-184683643989'
},
u'section':u'Mandatory',
u'domain':{
u'type':u'Domain',
u'name':u'Global',
u'id':u'e276abec-e0f2-11e3-8169-6d9ed49b625f'
},
u'timestamp':1482339574186
}
}
Working Python Script
for i in results:
response = requests.request("GET", i, headers=headers, verify=False)
raw=response.json()
raw.setdefault('name', "noname_rule")
raw.setdefault('action', "no_action")
raw.setdefault('sourceNetworks', "any-src")
raw.setdefault('destinationNetworks', "any-dest")
raw.setdefault('sourcePorts', "any-src-port")
raw.setdefault('destinationPorts', "any-dest-port")
raw.setdefault('sourceZones', "any-src-zn")
raw.setdefault('destinationZones', "any-dst-zn")
interesting_keys = ('name', 'action','sourceZones', 'sourceNetworks', 'sourcePorts', 'destinationZones', 'destinationNetworks', 'destinationPorts' )
subdict = {x: raw.get(x, "any") for x in interesting_keys if x in raw}
if 'objects' in subdict['sourceZones']:
srczn = subdict['sourceZones']['objects'][0]['name']
elif 'literals' in subdict['sourceZones']:
srczn = subdict['sourceZones']['literals'][0]['port']
else :
srczn = subdict['sourceZones']
if 'objects' in subdict['sourceNetworks']:
srcnet = subdict['sourceNetworks']['objects'][0]['name']
elif 'literals' in subdict['sourceNetworks']:
srcnet = subdict['sourceNetworks']['literals'][0]['value']
else :
srcnet = subdict['sourceNetworks']
if 'objects' in subdict['sourcePorts']:
srcprt = subdict['sourcePorts']['objects'][0]['name']
elif 'literals' in subdict['sourcePorts']:
srcprt = subdict['sourcePorts']['literals'][0]['port']
else :
srcprt = subdict['sourcePorts']
if 'objects' in subdict['destinationZones']:
dstzn = subdict['destinationZones']['objects'][0]['name']
elif 'literals' in subdict['destinationZones']:
dstzn = subdict['destinationZones']['literals'][0]['port']
else :
dstzn = subdict['destinationZones']
if 'objects' in subdict['destinationNetworks']:
dstnet = subdict['destinationNetworks']['objects'][0]['name']
elif 'literals' in subdict['destinationNetworks']:
dstnet = subdict['destinationNetworks']['literals'][0]['value']
else :
dstnet = subdict['destinationNetworks']
if 'objects' in subdict['destinationPorts']:
dstprt = subdict['destinationPorts']['objects'][0]['name']
elif 'literals' in subdict['destinationPorts']:
try:
dstprt = subdict['destinationPorts']['literals'][0]['port']
except KeyError:
dstprt = "0"
else :
dstprt = subdict['destinationPorts']
#print >> target, "%d,%s,%s,%s,%s,%s,%s,%s,%s" %(number, subdict['name'],subdict['action'],srczn,srcnet,srcprt,dstzn,dstnet,dstprt)
#print "%d,%s,%s,%s,%s,%s,%s,%s,%s" %(number, subdict['name'],subdict['action'],srczn,srcnet,srcprt,dstzn,dstnet,dstprt)
number+=1
time.sleep(.5)
print raw
Can you suggest other ways that would improve error handling, performance, readability, etc?

Whenever you see repeated code, perhaps it could be collapsed into one function that can reused over and over? Refactoring the code this way probably doesn't make it faster, but it does make it easier to read and understand.
def getSubdictData(subdict, fieldname, prop2):
if 'objects' in subdict[fieldname]:
return subdict[fieldname]['objects'][0]['name']
elif 'literals' in subdict[fieldname]:
if prop2 in subdict[fieldname]['literals'][0]
return subdict[fieldname]['literals'][0][prop2]
else:
return "0"
else :
return subdict[fieldname]
for i in results:
...
srczn = getSubdictData(subdict, 'sourceZones', 'port')
srcnet = getSubdictData(subdict, 'sourceNetworks', 'value')
srcprt = getSubdictData(subdict, 'sourcePorts', 'port')
dstzn = getSubdictData(subdict, 'destinationZones', 'port')
dstnet = getSubdictData(subdict, 'destinationNetworks', 'value')
dstnet = getSubdictData(subdict, 'destinationPorts', 'port')
...
Also note that I removed the try-catch you were using to detect if a field existed or not. If the object/code provides a way for you to determine that this field existed or not, we should use that instead of relying on a sloppy try catch to perform our logical operations. Try catches used like this are hard to read and perform badly. In this case it wouldn't matter, but its good practice not to abuse try catches like this.

Related

Making dictionary more functional

how can i change the code, to make it more functional (change the for loop for the same result only to make it shorter in 2 sentences)?
def get_language_from_text():
"""
Simply return an array with the predicted languages.
"""
resultSet = []
inputdata = request.data
#print(inputdata)
inputdataparsed = json.loads(request.data)
array_of_sentences = inputdataparsed['inputdata']
for obj_in_array in array_of_sentences:
obj_in_array_tmp = obj_in_array
sentence = obj_in_array['TEXT']
obj_type = obj_in_array['TYPE']
obj_lang = obj_in_array['LANGUAGE']
prediction = detect(sentence)
result_to_safe = {"TEXT":sentence,
"TYPE": obj_type,
"LANGUAGE":obj_lang,
"PREDICTED_LANGUAGE": prediction}
resultSet.append(result_to_safe)
break
print(resultSet)
Your code is fine, it could use a bit of cleaning but that's okay.
You can shorten your loop to:
def make_dict(sentence_dict):
return {
"TEXT": sentence_dict["TEXT"],
"TYPE": sentence_dict["TYPE"],
"LANGUAGE": sentence_dict["LANGUAGE"],
"PREDICTED_LANGUAGE": detect(sentence_dict["TEXT"])
}
result_set = [ make_dict(sentence_dict) for sentence_dict in array_of_sentences ]
You can make this more functional by mapping make_dict over array_of_sentences as follows:
result_set = list(map(make_dict, array_of_sentences))

Best way to refactor nested 'with patch' statements

I am trying to patch out the Azure Digital Twin API in my code. Currently I have achieved a way which works but is probably not the most Pythonic by nesting with patch statements.
What is the best way to rewrite this such that I can use it in multiple test functions and change the return values if needed?
def test_create_digital_twin(self):
with patch("endpoints.digital_twin.ClientSecretCredential"):
with patch("azure_digital_twin.create_digital_twin.DigitalTwinsClient.query_twins",) as mock_query:
with patch("azure_digital_twin.create_digital_twin.DigitalTwinsClient.upsert_digital_twin") as mock_upsert_twin:
with patch("azure_digital_twin.create_digital_twin.DigitalTwinsClient.upsert_relationship") as mock_upsert_relationship:
mock_query.return_value = []
mock_upsert_twin.return_value = {
"$dtId":"spc-1",
"$etag":"random",
"$model":"dtmi:digitaltwins:rec_3_3:core:Asset;1"
}
mock_upsert_relationship.return_value = {
"$relationshipId":"spc-1-hasPart-spc-2",
"$sourceId":"spc-1",
"$targetId" : "spc-2",
"$relationshipName":"hasPart"
}
response = self.client.post(
endpoint,
params={"node" : "spc-1"},
)
assert response.status_code == status.HTTP_201_CREATED
You might use an ExitStack from the contextlib module.
from contextlib import ExitStack
def test_create_digital_twin(self):
with ExitStack() as es:
def make_azure_patch(x):
return es.enter_context(patch(f'azure_digital_twin.create_digital_twin.DigitalTwinsClient.{x}'))
es.enter_context("endpoints.digital_twin.ClientSecretCredential"))
mock_query = make_patch("query_twins")
mock_upsert_twin = make_patch("upsert_digital_twin")
mock_upsert_relationship = make_patch("upsert_relationship")
mock_query.return_value = []
mock_upsert_twin.return_value = {
"$dtId":"spc-1",
"$etag":"random",
"$model":"dtmi:digitaltwins:rec_3_3:core:Asset;1"
}
mock_upsert_relationship.return_value = {
"$relationshipId":"spc-1-hasPart-spc-2",
"$sourceId":"spc-1",
"$targetId" : "spc-2",
"$relationshipName":"hasPart"
}
response = self.client.post(
endpoint,
params={"node" : "spc-1"},
)
assert response.status_code == status.HTTP_201_CREATED
make_azure_patch is just a helper function to reduce the length of the lines creating three of the individual patches.

How to check each key separately from a list in a loop without creating multiple loops. Which may have a KeyError etc

I wrote a code that takes 9 keys from API.
The authors, isbn_one, isbn_two, thumbinail, page_count fields may not always be retrievable, and if any of them are missing, I would like it to be None. Unfortunately, if, or even nested, doesn't work. Because that leads to a lot of loops. I also tried try and except KeyError etc. because each key has a different error and it is not known which to assign none to. Here is an example of logic when a photo is missing:
th = result['volumeInfo'].get('imageLinks')
if th is not None:
book_exists_thumbinail = {
'thumbinail': result['volumeInfo']['imageLinks']['thumbnail']
}
dnew = {**book_data, **book_exists_thumbinail}
book_import.append(dnew)
else:
book_exists_thumbinail_n = {
'thumbinail': None
}
dnew_none = {**book_data, **book_exists_thumbinail_n}
book_import.append(dnew_none)
When I use logic, you know when one condition is met, e.g. for thumbinail, the rest is not even checked.
When I use try and except, it's similar. There's also an ISBN in the keys, but there's a list in the dictionary over there, and I need to use something like this:
isbn_zer = result['volumeInfo']['industryIdentifiers']
dic = collections.defaultdict(list)
for d in isbn_zer:
for k, v in d.items():
dic[k].append(v)
Output data: [{'type': 'ISBN_10', 'identifier': '8320717507'}, {'type': 'ISBN_13', 'identifier': '9788320717501'}]
I don't know what to use anymore to check each key separately and in the case of its absence or lack of one ISBN (identifier) assign the value None. I have already tried many ideas.
The rest of the code:
book_import = []
if request.method == 'POST':
filter_ch = BookFilterForm(request.POST)
if filter_ch.is_valid():
cd = filter_ch.cleaned_data
filter_choice = cd['choose_v']
filter_search = cd['search']
search_url = "https://www.googleapis.com/books/v1/volumes?"
params = {
'q': '{}{}'.format(filter_choice, filter_search),
'key': settings.BOOK_DATA_API_KEY,
'maxResults': 2,
'printType': 'books'
}
r = requests.get(search_url, params=params)
results = r.json()['items']
for result in results:
book_data = {
'title': result['volumeInfo']['title'],
'authors': result['volumeInfo']['authors'][0],
'publish_date': result['volumeInfo']['publishedDate'],
'isbn_one': result['volumeInfo']['industryIdentifiers'][0]['identifier'],
'isbn_two': result['volumeInfo']['industryIdentifiers'][1]['identifier'],
'page_count': result['volumeInfo']['pageCount'],
'thumbnail': result['volumeInfo']['imageLinks']['thumbnail'],
'country': result['saleInfo']['country']
}
book_import.append(book_data)
else:
filter_ch = BookFilterForm()
return render(request, "BookApp/book_import.html", {'book_import': book_import,
'filter_ch': filter_ch})```

when passed a dictionary into jinja2 template single apostrophe(') is converted into "'"

JavaScript is throwing an error 'Uncaught Syntax Error: Unexpected token '&''
when debugged in Views.py I got he data with proper Apostrophes.
def newEntry(request):
assert isinstance(request, HttpRequest)
i = 1
for x in lines:
for line in x:
cursor.execute("select distinct regionn FROM [XYZ].[dbo].[Errors] where [Linne] like '%" +line+ "%'")
region[i] = cursor.fetchall()
i = i+1
return render(
request,
'app/newEntry.html',
{
'title': 'New Entry',
'year':datetime.now().year,
'lines': lines,
'regions': region,
}
)
and here is my JS code
var Regions= {{regions}}
function changecat(value) {
if (value.length == 0) document.getElementById("category").innerHTML = "<option>default option here</option>";
else {
var catOptions = "";
for (categoryId in Regions[value]) {
catOptions += "<option>" + categoryId+ "</option>";
}
document.getElementById("category").innerHTML = catOptions;
}
}
Thanks in advance, if this is not a best practice to carry data, suggest me some best process which fills my requirement

Python utility for parsing blocks?

I have a file that starts something like:
databaseCons = {
main = {
database = "readable_name",
hostname = "hostdb1.serv.com",
instances= {
slaves = {
conns = "8"
}
}
maxconns = "5",
user = "user",
pass = "pass"
}
}
So, what I'd like to do is parse this out into a dict of sub-dicts, something like:
{'main': {'database': 'readable_name', 'hostname': 'hostdb1.serv.com', 'maxconns': '5', 'instances': {'slave': {'maxCount': '8'}}, 'user': 'user', 'pass': 'pass'}}
I think the above makes sense... but please feel free to edit this if it doesn't. Basically I want the equivalent of:
conns = '8'
slave = dict()
slave['maxCount'] = conns
instances = dict()
instances['slave'] = slave
database = 'readable_name'
hostname = 'hostdb1.serv.com'
maxconns = '5'
user = 'user'
pas = 'pass'
main = dict()
main['database'] = database
main['hostname'] = hostname
main['instances'] = instances
main['maxconns'] = maxconns
main['user'] = user
main['pass'] = pas
databaseCons = dict()
databaseCons['main'] = main
Are there any modules out there that can handle this sort of parsing? Even what I've suggested above looks messy.. there's got to be a better way I'd imagine.
Here is a pyparsing parser for your config file:
from pyparsing import *
def to_dict(t):
return {k:v for k,v in t}
series = Forward()
struct = Suppress('{') + series + Suppress('}')
value = quotedString.setParseAction(removeQuotes) | struct
token = Word(alphanums)
assignment = Group(token + Suppress('=') + value + Suppress(Optional(",")))
series << ZeroOrMore(assignment).setParseAction(to_dict)
language = series + stringEnd
def config_file_to_dict(filename):
return language.parseFile(filename)[0]
if __name__=="__main__":
from pprint import pprint
pprint(config_file_to_dict('config.txt'))

Categories

Resources