python raise exception where there looks not exception? - python

I have a problem that:
when testing on flask there is not exception
after put online by gunicorn+gevent, they raise an exception at following code
-
try:
req_dict = request.args.to_dict()
req_desc = copy.copy(req_dict)
temp_card_pwd = str(req_desc['cardpwd'])
req_desc['cardpwd'] = temp_card_pwd.replace(temp_card_pwd[5:9], "****")
log.info('接收到一条请求信息(charge_in##) %s' % req_desc)
request_type = str(req_dict['command'])
charge_acct = str(req_dict['telephone'])
card_pwd = str(req_dict['cardpwd'])
res_dict = req_validate(request_type, card_pwd, charge_acct)
if res_dict['errcode'] == 0:
log.info('准备充值(charge_begin##)...%s '% req_desc)
time_start = time.time()
acct_charge = True
charge_res = charge(req_desc, card_pwd, charge_acct)
res_dict['body'] = charge_res
log.info('充值结果(charge_end##):请求:%s, 结果:%s 耗时:%s' % (req_desc, res_dict,
int((time.time() - time_start)*1000)))
else:
log.warning('返回异常请求结果(charge_out##):请求:%s 结果:%s' % (req_desc, res_dict))
except Exception as e:
if acct_charge:
code = 1007
msg = '充值异常!%s' % e
else:
code = 1006
msg = '传入参数错误! %s' % e
res_dict = {'errcode': code, 'msg': msg, 'body': None}
log.warning('返回异常请求结果(charge_exception##):请求参数异常!请核对后再发!%s' % res_dict)
the exception is
2017-08-04 06:47:50,441 yidongserver.py[line:49] WARNING: [channel_name:yidongApp] 返回异常请求结果(charge_exception##):请求参数异常!请核对后再发!{'errcode': 1006, 'msg': '传入参数错误', 'body': None}
2017-08-04 06:47:50,445 yidongserver.py[line:25] INFO: [channel_name:yidongApp] 接收到一条请求信息(charge_in##) {'request_id': 'HF111708041450260032', 'card_id': '17356104229493840', 'telephone': '152***94608', 'cardpwd': '42381****349361850', 'money': '100', 'callbackurl': '', 'command': 'charge', 'channel_id': 'LTAppRY'}
Although raise this exception, this charge request still SUCCESS in charge, and return ONCE
pls help to solve this warning exception! thanks!

Related

Comparing id betwen config value and API output

I want to check if the fields 'id' and 'folder_id' of api_response equal certain values (here, respectively 25 and 17). If it does, return true, else return false. My problem is that my script returns false when it should return true because the fields id and folder_id are correct.
Here is my code:
SendInBlueAPI = config.get('Config','SendInBlueAPI')
SendInBlueFolderID = config.get('Config','SendInBlueFolderID')
SendInBlueListID = config.get('Config','SendInBlueListID')
## Checking if list exists in SendInBlue
configuration = sib_api_v3_sdk.Configuration()
configuration.api_key['api-key'] = '%s' % (SendInBlueAPI)
api_instance = sib_api_v3_sdk.ListsApi(sib_api_v3_sdk.ApiClient(configuration))
list_id = SendInBlueListID
try:
api_response = api_instance.get_list(list_id)
if api_response.id == SendInBlueListID and api_response.folder_id == SendInBlueFolderID:
print(True)
else:
print(False)
except ApiException as e:
print("Exception when calling ListsApi->get_list: %s\n" % e)
This is the output of api_response:
{'campaign_stats': None,
'created_at': '2023-01-16T10:07:47.000+01:00',
'dynamic_list': False,
'folder_id': 17,
'id': 25,
'name': 'My list',
'total_blacklisted': 2,
'total_subscribers': 244,
'unique_subscribers': 246}
And here is my config file :
[Config]
SendInBlueAPI = MY_API_KEY
SendInBlueFolderID = 17
SendInBlueListID = 25

Python concurrent.future not running in Parallel

I am writing code for querying CMDB data from ServiceNow through REST API calls using python. To gain results faster I am using concurrent.future module of python to allow parallel query executions.
Below is the code and output:
import requests
import os
import base64
import threading
import concurrent.futures
import datetime
class ServiceNowAPI:
__ServiceNowUserName = os.environ.get('ServiceNow_USERNAME')
__ServiceNowPassword = None
__ServiceNowPasswordProd = None
__BASE_URL = None
__WSI_URL = 'https://esiocecr.contoso.com:9443/rsrv_servicenow-outbound/'
__ServiceNow_Cert_Path = 'C:\Certificates\OSMCert.pem'
# ServiceNow API URL paths
__GET_CI_DETAILS = "/api/now/table/cmdb_ci_circuit?sysparm_query=u_port_circuit_idLIKE__CINAME__^ORnameLIKE__CINAME__&sysparam_fields=*"
def __init__(self, ServiceNowEnvironment):
self.ServiceNowEnvironment = ServiceNowEnvironment
self.__ServiceNowPassword = os.environ.get('ServiceNow_PROD_PWD') if ServiceNowEnvironment.lower() == "prod" or ServiceNowEnvironment.lower() == "production" else os.environ.get('ServiceNow_EAGLE_PWD')
self.__BASE_URL = "https://contososervicenow.service-now.com" if ServiceNowEnvironment.lower() == "prod" or ServiceNowEnvironment.lower() == "production" else "https://contosoeagle.service-now.com"
CredsPair = "{0}:{1}".format(self.__ServiceNowUserName, self.__ServiceNowPassword)
CredBytes = CredsPair.encode('ascii')
Base64Creds = base64.b64encode(CredBytes).decode('utf-8')
self.__Authorization = "Basic {0}".format(Base64Creds)
def _GetRouterName(self, RouterLink):
RouterName = ''
with requests.Session() as ServiceNowCall:
ServiceNowCall.headers.update({ 'Authorization': self.__Authorization, 'content-type': 'application/json', 'DP_EXTERNAL_URL': RouterLink})
ServiceNowCall.cert = self.__ServiceNow_Cert_Path
ServiceNowCall.verify = self.__ServiceNow_Cert_Path
with ServiceNowCall.get(self.__WSI_URL) as ResponseObject:
ResponseJSON = ResponseObject.json()
Results = ResponseJSON['result']
RouterName = Results['name']
return RouterName
def _GetCircuitCIDetails(self, CircuitID):
print('Started for ' + CircuitID + ' at ' + datetime.datetime.now().strftime("%d-%b-%Y %H:%M:%S.%f"))
ResponseJSON = ''
URL = "{0}{1}".format(self.__BASE_URL, self.__GET_CI_DETAILS.replace('__CINAME__', CircuitID))
with requests.Session() as ServiceNowCall:
ServiceNowCall.headers.update({ 'Authorization': self.__Authorization, 'content-type': 'application/json', 'DP_EXTERNAL_URL': URL})
ServiceNowCall.cert = self.__ServiceNow_Cert_Path
ServiceNowCall.verify = self.__ServiceNow_Cert_Path
with ServiceNowCall.get(self.__WSI_URL) as ResponseObject:
ResponseJSON = ResponseObject.json()
AllRecords = list(ResponseJSON['result'])
ActiveRecord = [rec for rec in AllRecords if rec['u_lifecycle_status'] != 'end of life'][0]
Router_Name = self._GetRouterName(ActiveRecord['u_router_name']['link'])
Results = {
'Name': ActiveRecord['name'],
'CarrierName': ActiveRecord['u_carrier_name'],
'NetworkType': ActiveRecord['u_network_type'],
'NetworkSubType': ActiveRecord['u_network_sub_type'],
'RouterName': Router_Name,
'PortCircuitID': ActiveRecord['name'],
'AccessCircuitID': ActiveRecord['u_port_circuit_id']
}
print('Finished ' + CircuitID + ' at ' + datetime.datetime.now().strftime("%d-%b-%Y %H:%M:%S.%f"))
yield Results
def GetCIDetails(self, CICSV):
CircuitDetails = []
CircuitIDList = [Circuit.strip() for Circuit in CICSV.split(',')]
CircuitDetails = []
with concurrent.futures.ThreadPoolExecutor() as executor:
CIDetailsResult = { executor.submit(self._GetCircuitCIDetails, CircuitID): CircuitID for CircuitID in CircuitIDList }
for future in concurrent.futures.as_completed(CIDetailsResult):
CircuitCI = CIDetailsResult[future]
try:
CurrentResult = future.result()
except Exception as exc:
ErrorResult = dict({ 'Name': CircuitCI, 'CarrierName': 'NA', 'NetworkType': 'NA', 'NetworkSubType': 'NA', 'RouterName': 'NA', 'PortCircuitID': 'Error', 'AccessCircuitID': 'Error'})
CircuitDetails.extend(ErrorResult)
else:
CircuitDetails.extend(CurrentResult)
return CircuitDetails
if __name__ == "__main__":
ServiceNowAPIClass = ServiceNowAPI('NONPROD')
CIDetails = ServiceNowAPIClass.GetCIDetails('Circuit1,Circuit2')
print(CIDetails)
Output:
Started for Circuit1 at 30-Apr-2022 13:40:06.784841
Finished Circuit1 at 30-Apr-2022 13:40:09.749164
Started for Circuit2 at 30-Apr-2022 13:40:09.751166
Finished Circuit2 at 30-Apr-2022 13:40:12.479171
[{'Name': 'Circuit1', 'CarrierName': 'CenturyLink', 'NetworkType': 'EU-BTM', 'NetworkSubType': 'N/A', 'RouterName': 'RT1234ABCD03', 'PortCircuitID': 'Circuit1', 'AccessCircuitID': 'Circuit1'}, {'Name': 'Circuit2', 'CarrierName': 'Verizon', 'NetworkType': 'DPS-NA', 'NetworkSubType': 'N/A', 'RouterName': 'RT12345678ABC', 'PortCircuitID': 'Circuit2', 'AccessCircuitID': 'Circuit2'}]
However, as you can see the executions are not happening in Parallel. It is finishing the queries for each circuit one after another.
How can I fix this to run the _GetCircuitCIDetails(self, CircuitID) function against all CircuitIDs in parallel?

Tally integration on odoo

How can I export tax analysis in invoice in tally to xml request?
url1 = "http://localhost:9000"
xml = "<ENVELOPE><HEADER><VERSION>1</VERSION><TALLYREQUEST>EXPORT</TALLYREQUEST><TYPE>DATA</TYPE>"
xml += "<ID>VoucherRegister</ID></HEADER><BODY><DESC><STATICVARIABLES>"
xml += "<EXPLODEVNUM>Yes</EXPLODEVNUM><ISVATDUTYPAID>Yes</ISVATDUTYPAID><DBINVEXPLODEFLAG>Yes</DBINVEXPLODEFLAG>"
xml+="<DBBILLEXPLODEFLAG>Yes</DBBILLEXPLODEFLAG><SVEXPORTFORMAT>$$SysName:XML</SVEXPORTFORMAT><SVFROMDATE Type='DATE'>"+self.startdate+"</SVFROMDATE><SVTODATE Type='DATE'>"+self.enddate+"</SVTODATE><VOUCHERTYPENAME>"+self.sale_name+"</VOUCHERTYPENAME><EXPLODEFLAG>Yes</EXPLODEFLAG><REPORTNAME>Ledger Cost Breakup</REPORTNAME></STATICVARIABLES>"
xml += "<TDL><TDLMESSAGE><COLLECTION><FETCH>GSTDetails.LIST</FETCH></COLLECTION></TDLMESSAGE></TDL></DESC></BODY></ENVELOPE>"
req = requests.post(url = url1,data=xml)
# res = req.text.decode("UTF-8")
response = req.text.strip().replace("&","&")
# scrubbedXML = re.sub('&.+[0-9]+;', '', response)
# print(response)
responseXML = Et.fromstring(response)
values=database.data()
print(values)
url_odoo=values['urls']
db_odoo=values['database']
email_odoo=values['email']
password_odoo=values['password']
print(url_odoo)
url=url_odoo
db=db_odoo
username=email_odoo
password=password_odoo
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url),allow_none=True)
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url),allow_none=True)
for vch in responseXML.findall("./BODY/DATA/TALLYMESSAGE/VOUCHER"):
mylist=[]
mylist2=[]
myliist3=[]
stockslist=[]
amountlist=[]
quantitylist=[]
roundofflist=[]
discountlist=[]
try:
if len(vch.findall('INVENTORYENTRIES.LIST'))>=0:
try:
# stk = vch.findall("INVENTORYENTRIES.LIST").__getitem__(0).find("STOCKITEMNAME").text
for stockss in vch.findall("INVENTORYENTRIES.LIST"):
stks=stockss.find('STOCKITEMNAME').text
# print(stks)
stockslist.append(stks)
except:
stk='na'
pass
try:
for discoun in vch.findall("INVENTORYENTRIES.LIST"):
disc=float(discoun.find('DISCOUNT').text)
print(disc)
discountlist.append(disc)
# stockslist.append(stks)
except:
disc=0
discountlist.append(disc)
pass
try:
# rt = vch.findall("INVENTORYENTRIES.LIST").__getitem__(0).find("RATE").text
for rates in vch.findall('INVENTORYENTRIES.LIST'):
perrattes=rates.find('RATE').text
ratee=(re.findall(r'-?\d+\.?\d*', perrattes))
for s in ratee:
perrate=float(s)
# print(perrate)
amountlist.append(perrate)
except:
perrate=0
# print(perrate)
pass
try:
# Ktk = vch.findall("INVENTORYENTRIES.LIST").__getitem__(0).find("BILLEDQTY").text
for ktks in vch.findall('INVENTORYENTRIES.LIST'):
ktk= ktks.find('BILLEDQTY').text
billedqu=(re.findall(r'-?\d+\.?\d*', ktk))
for b in billedqu:
quan=float(b)
# print(quan)
quantitylist.append(quan)
except:
quan=1.0
quantitylist.append(quan)
# print(quan)
except:
continue
if len(vch.findall("LEDGERENTRIES.LIST"))>=0:
try:
for ro in vch.findall("LEDGERENTRIES.LIST"):
roundoff=ro.find('AMOUNT').text
round=float(roundoff)
if round>0 and round<1.0 or round< 0 and round>-1.0:
roff=float(round)
roundofflist.append(roff)
for items in vch.findall("LEDGERENTRIES.LIST"):
vall=items.find('LEDGERNAME').text
mylist.append(vall)
print(mylist)
except:
amount=0
toname='na'
# print(toname)
pass
else:
try:
amount = vch.findall("ALLLEDGERENTRIES.LIST").__getitem__(0).find("LEDGERNAME").text
except:
amount='na'
pass
try:
vch_dt=vch.find("DATE").text
vch_date=self.change_date_format(vch_dt)
except:
vch_date='na'
pass
try:
vch_led= vch.find("VOUCHERTYPENAME").text
print(vch_led)
except:
vch_led='na'
pass
try:
vch_type= vch.find("VOUCHERNUMBER").text
print(vch_type)
except:
vch_type='na'
pass
try:
vch_no= vch.find("PARTYLEDGERNAME").text
except:
vch_no= 'na'
pass
print(mylist)
try:
del mylist[0]
except:
pass
for valll in mylist:
pid=models.execute_kw(db, uid, password, 'account.tax','search',[[['name', '=',valll]]])
print(pid)
mylist2.append(pid)
# del mylist2[0]
print(mylist2,'check')
for value1 in mylist2:
try:
val2=value1[0]
except:
pass
try:
myliist3.append(val2)
print(myliist3)
except:
pass
xid=models.execute_kw(db, uid, password, 'account.invoice','search_count',[[['origin', '=', vch_type]]])
# print(xid)
lid=models.execute_kw(db, uid, password, 'account.invoice','search',[[['origin', '=', vch_type]]])
try:
sid=models.execute_kw(db,uid, password, 'res.partner','search',[[['name', '=', vch_no]]])
print(sid)
except:
continue
# print(sid)
# print(mid)
print(stockslist)
print(amountlist)
print(quantitylist)
for vill in sid:
if xid>=1:
continue
else:
rslt =models.execute_kw(db, uid, password, 'account.invoice','create',[{'partner_id': vill,
'date_invoice':vch_date,'date_due':vch_date,'journal_id':1,'state':'draft','origin':vch_type}])
print(rslt)
for st,ratt,quant,discon in zip(stockslist,amountlist,quantitylist,discountlist):
# rateval=calculate_rate(ratt,quant)
ratevals=float(ratt)
mid=models.execute_kw(db,uid, password, 'product.product','search',[[['name', '=', st]]])
print(mid,'bye')
for stockna in mid:
stock=stockna
va=models.execute_kw(db, uid, password,'product.product', 'read',[mid], {'fields': [ 'taxes_id']})
print(va)
for taxed in va:
taxfv=taxed['taxes_id']
print(taxfv,'hi')
if taxfv==[]:
taxfv=myliist3
# Oid=models.execute_kw(db, uid, password, 'account.tax','search',[[['name', '=','CGST'],['type_tax_use','=','sale']]])
# Otd=models.execute_kw(db, uid, password, 'account.tax','search',[[['name', '=','SGST'],['type_tax_use','=','sale']]])
# Oid=Oid+Otd
# taxfv=Oidk
# print(Oid)
else:
taxfv==taxfv
print(taxfv,'final')
res=models.execute_kw(db, uid, password, 'account.invoice','write',[[rslt],{'invoice_line_ids':
[(0,4, {'name': st,
'origin': vch_type,
'account_id':31,
'price_unit': ratevals,
'quantity': quant,
'is_rounding_line': True,
'discount':discon,
'uom_id': 1,
'product_id': stock,
'invoice_line_tax_ids': [[6,True, taxfv]]
}
)
]
}
]
)
res=models.execute_kw(db, uid, password, 'account.invoice','compute_taxes',[rslt])
# print(roundofflist)
for ron in roundofflist:
round=models.execute_kw(db, uid, password, 'account.invoice','write',[[rslt],{'invoice_line_ids':[(0,4, {'name': 'Rounded off',
'account_id': 284,
'price_unit': ron,
'quantity': 1})]}])
vali=models.execute_kw(db, uid, password, 'account.invoice','action_invoice_open',[rslt])

Tidying up series of try... except statements?

I've written a script to pipe through data from the Kustomer API to our database, and although it works fine its a bit messy, was wondering if there's a more elegant solution to this. I'm defining the row of results im pushing through as a dictionary then pushing to MySQL, but the messy part comes when some of these values aren't available in the JSON all the time.
This has resulted in a try / except statements for each data point that may or may not be missing.
Is there a better way of doing this? Code below.
try:
record_data = {
'id': record['id'],
'created_at': str(datetime.strptime(record['attributes']['createdAt'], '%Y-%m-%dT%H:%M:%S.%fZ'))[:-7],
'last_activity_at': str(datetime.strptime(record['attributes']['lastActivityAt'], '%Y-%m-%dT%H:%M:%S.%fZ'))[:-7],
'first_marked_done': None,
'last_marked_done': None,
'assigned_team': record['attributes']['assignedTeams'][0] if record['attributes']['assignedTeams'] != [] else None,
'conversation_type': None,
'conversation_category': None,
'conversation_subcategory': None,
'message_count': record['attributes']['messageCount'],
'note_count': record['attributes']['noteCount'],
'satisfaction': record['attributes']['satisfaction'],
'status': None,
'email': 1 if len(list(filter(lambda x: x == 'email', record['attributes']['channels']))) > 0 else 0,
'chat': 1 if len(list(filter(lambda x: x == 'chat', record['attributes']['channels']))) > 0 else 0,
'priority': record['attributes']['priority'],
'direction': 'outbound' if record['attributes']['direction'] == 'out' else 'in',
'nlp_score': None,
'nlp_sentiment': None,
'waiting_for': None,
'sla_breach': None,
'sla_status': None,
'breached_sla': None,
'breached_at': None
}
try:
record_data['status'] = record['attributes']['status']
except KeyError:
pass
try:
record_data['conversation_type'] = record['attributes']['custom']['typeStr']
record_data['conversation_category'] = str(record['attributes']['custom']['categoryTree']).split('.')[0]
record_data['conversation_subcategory'] = str(record['attributes']['custom']['categoryTree']).split('.')[1] if len(str(record['attributes']['custom']['categoryTree']).split('.')) > 1 else None
except KeyError:
pass
try:
record_data['waiting_for'] = record['attributes']['custom']['typeStr']
except KeyError:
pass
try:
record_data['first_marked_done'] = str(datetime.strptime(record['attributes']['firstDone']['createdAt'], '%Y-%m-%dT%H:%M:%S.%fZ'))[:-7]
record_data['last_marked_done'] = str(datetime.strptime(record['attributes']['lastDone']['createdAt'], '%Y-%m-%dT%H:%M:%S.%fZ'))[:-7]
except KeyError:
pass
try:
record_data['sla_breach'] = 0 if record['attributes']['sla']['breached'] is False else 1
record_data['sla_status'] = record['attributes']['sla']['status']
if record_data['sla_breach'] == 1:
try:
record_data['breached_sla'] = record['attributes']['sla']['breach']['metric']
record_data['breached_at'] = record['attributes']['sla']['breach']['at']
except KeyError:
for m in record['attributes']['sla']['metrics']:
try:
if record['attributes']['sla']['metrics'][m]['breachAt'] == record['attributes']['sla']['summary']['firstBreachAt']:
record_data['breached_sla'] = m
record_data['breached_at'] = str(datetime.strptime(record['attributes']['sla']['summary']['firstBreachAt'], '%Y-%m-%dT%H:%M:%S.%fZ'))[:-7]
except KeyError:
pass
except KeyError:
record_data['sla_breach'] = 0
print(record_data)
self.db.insert_update(KustomerConversations(**record_data))
except KeyError:
pass
First you should try, where possible, to use dict.get with a default value specified. Next you can consider contextmanager to make your code significantly cleaner. Consider this:
try:
record_data['status'] = record['attributes']['status']
except KeyError:
pass
try:
record_data['conversation_type'] = record['attributes']['custom']['typeStr']
except KeyError:
pass
try:
record_data['waiting_for'] = record['attributes']['custom']['typeStr']
except KeyError:
pass
try:
record_data['first_marked_done'] = record['attributes']['firstDone']['createdAt']
except KeyError:
pass
Now rewritten, you can ensure consistent error handling without repeating logic:
from contextlib import contextmanager
#contextmanager
def error_handling():
try:
yield
except KeyError:
pass
with error_handling():
record_data['status'] = record['attributes']['status']
with error_handling():
record_data['conversation_type'] = record['attributes']['custom']['typeStr']
with error_handling():
record_data['waiting_for'] = record['attributes']['custom']['typeStr']
with error_handling():
record_data['first_marked_done'] = record['attributes']['firstDone']['createdAt']
You can define an arbitrary number of functions like error_handling for various rules you wish to apply.
You can use function, that give you element from nested dicts, and doesn't raise an exception, if it doesnt' exists.
Like this quick draft:
def get_nested_dict_value(src_dict, *nested_keys, **kwargs):
"""
Get value of some nested dict by series of keys with default value.
Example:
instead of:
x = data['a']['b']['c']['d']
use
x = get_nested_dict_value(data, 'a', 'b', 'c', 'd')
or, if you need some non-None default value, add default=xxx kwarg:
x = get_nested_dict_value(data, 'a', 'b', 'c', 'd', default=0)
"""
default = kwargs.get("default", None)
pointer = src_dict
i = 0
for key in nested_keys:
i += 1
if key in pointer:
pointer = pointer[key]
if i == len(nested_keys):
return pointer
else:
return default
So, instead of:
try:
record_data['conversation_type'] = record['attributes']['custom']['typeStr']
except Exception:
pass
You just type:
record_data['conversation_type'] = get_nested_dict_value(record, 'attributes', 'custom', 'typeStr')
The different naming conventions on the input and output sides make it hard to beat the clarity of explicit assignments. Preserving the exact semantics of your version (e.g., that it doesn't assign conversation_category in the absence of a typeStr even if categoryTree is available) excludes certain choices (like making a data structure to loop over with a try/except on each access); you might be able to do better with more assumptions about your input data.
Nonetheless, in addition to the dict.get already mentioned, you can use builtins (any, or, and dict) and introduce a helper function and a few temporary variables to make the code much more readable:
# this gives one digit of the hour for me...?
def ptime(s): return str(datetime.strptime(s,'%Y-%m-%dT%H:%M:%S.%fZ'))[:-7]
try:
attr=record['attributes']
cust=attr.get('custom',{}) # defer KeyErrors into the below
record_data = dict(
id = record['id'],
created_at = ptime(attr['createdAt']),
last_activity_at = ptime(attr['lastActivityAt']),
first_marked_done = None,
last_marked_done = None,
assigned_team = attr['assignedTeams'][0] or None,
conversation_type = None,
conversation_category = None,
conversation_subcategory = None,
message_count = attr['messageCount'],
note_count = attr['noteCount'],
satisfaction = attr['satisfaction'],
status = attr.get('status'),
email = int(any(x == 'email' for x in attr['channels'])),
chat = int(any(x == 'chat' for x in attr['channels'])),
priority = attr['priority'],
direction = 'outbound' if attr['direction'] == 'out' else 'in',
nlp_score = None,
nlp_sentiment = None,
waiting_for = cust.get('typeStr'),
sla_breach = 0,
sla_status = None,
breached_sla = None,
breached_at = None
)
try:
record_data['conversation_type'] = cust['typeStr']
cat=str(cust['categoryTree']).split('.')
record_data['conversation_category'] = cat[0]
record_data['conversation_subcategory'] = cat[1] if len(cat) > 1 else None
except KeyError: pass
try:
record_data['first_marked_done'] = ptime(attr['firstDone']['createdAt'])
record_data['last_marked_done'] = ptime(attr['lastDone']['createdAt'])
except KeyError: pass
try:
sla=attr['sla']
record_data['sla_breach'] = 0 if sla['breached'] is False else 1
record_data['sla_status'] = sla['status']
if record_data['sla_breach'] == 1:
try:
record_data['breached_sla'] = sla['breach']['metric']
record_data['breached_at'] = sla['breach']['at']
except KeyError:
for m,v in sla['metrics'].items():
try:
v=v['breachAt']
if v == sla['summary']['firstBreachAt']:
record_data['breached_sla'] = m
record_data['breached_at'] = ptime(v)
except KeyError: pass
except KeyError: pass
print(record_data)
self.db.insert_update(KustomerConversations(**record_data))
except KeyError: pass
While you might have a policy against it, in this case I recommend writing the remaining except KeyError: pass clauses on one line each: it helps the visual bracketing of the tentative code.

How to set vars into ansible inventory?

In playbook I'm using variable {{excluded_service}}. I want to run ansible playbook from python and provide this variable. And I can't use external inventory script to provide this variable.
I am using to create inventory:
hosts = ["127.0.0.1"]
inventory=ansible.inventory.Inventory(hosts)
but I don't understand where I can add value of variable?
My code, that works with external inventory script:
import sys
import os
import stat
import json
import ansible.playbook
import ansible.constants as C
import ansible.utils.template
from ansible import errors
from ansible import callbacks
from ansible import utils
from ansible.color import ANSIBLE_COLOR, stringc
from ansible.callbacks import display
playbook="/opt/RDE/3p/ansible/loop/testloop.yml"
inventory="/opt/RDE/3p/ansible/loop/lxc.py"
connection="local"
timeout=10
subset=None
options={'subset': None, 'ask_pass': False, 'sudo': False, 'private_key_file': None, 'syntax': None, 'skip_tags': None, 'diff': False, 'check': False, 'remote_user': 'root', 'listtasks': None, 'inventory': '/opt/RDE/3p/ansible/loop/lxc.py', 'forks': 5, 'listhosts': None, 'start_at': None, 'tags': 'all', 'step': None, 'sudo_user': None, 'ask_sudo_pass': False, 'extra_vars': [], 'connection': 'smart', 'timeout': 10, 'module_path': None}
sshpass = None
sudopass = None
extra_vars = {}
def colorize(lead, num, color):
""" Print 'lead' = 'num' in 'color' """
if num != 0 and ANSIBLE_COLOR and color is not None:
return "%s%s%-15s" % (stringc(lead, color), stringc("=", color), stringc(str(num), color))
else:
return "%s=%-4s" % (lead, str(num))
def hostcolor(host, stats, color=True):
if ANSIBLE_COLOR and color:
if stats['failures'] != 0 or stats['unreachable'] != 0:
return "%-37s" % stringc(host, 'red')
elif stats['changed'] != 0:
return "%-37s" % stringc(host, 'yellow')
else:
return "%-37s" % stringc(host, 'green')
return "%-26s" % host
inventory = ansible.inventory.Inventory(options['inventory'])
hosts = ["127.0.0.1"]
#inventory=ansible.inventory.Inventory(hosts)
inventory.subset(options['subset'])
if len(inventory.list_hosts()) == 0:
raise errors.AnsibleError("provided hosts list is empty")
inventory.set_playbook_basedir(os.path.dirname(playbook))
stats = callbacks.AggregateStats()
playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
if options['step']:
playbook_cb.step = options['step']
if options['start_at']:
playbook_cb.start_at = options['start_at']
runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
pb = ansible.playbook.PlayBook(
playbook=playbook,
module_path=None,
inventory=inventory,
forks=options['forks'],
remote_user=options['remote_user'],
remote_pass=sshpass,
callbacks=playbook_cb,
runner_callbacks=runner_cb,
stats=stats,
timeout=options['timeout'],
transport=options['connection'],
sudo=options['sudo'],
sudo_user=options['sudo_user'],
extra_vars=extra_vars,
private_key_file=options['private_key_file'],
check=options['check'],
diff=options['diff']
)
playnum = 0
failed_hosts = []
unreachable_hosts = []
try:
print pb.run()
hosts = sorted(pb.stats.processed.keys())
print hosts
display(callbacks.banner("PLAY RECAP"))
playbook_cb.on_stats(pb.stats)
for h in hosts:
t = pb.stats.summarize(h)
if t['failures'] > 0:
failed_hosts.append(h)
if t['unreachable'] > 0:
unreachable_hosts.append(h)
retries = failed_hosts + unreachable_hosts
if len(retries) > 0:
filename = pb.generate_retry_inventory(retries)
if filename:
display(" to retry, use: --limit #%s\n" % filename)
for h in hosts:
t = pb.stats.summarize(h)
display("%s : %s %s %s %s" % (
hostcolor(h, t),
colorize('ok', t['ok'], 'green'),
colorize('changed', t['changed'], 'yellow'),
colorize('unreachable', t['unreachable'], 'red'),
colorize('failed', t['failures'], 'red')),
screen_only=True
)
display("%s : %s %s %s %s" % (
hostcolor(h, t, False),
colorize('ok', t['ok'], None),
colorize('changed', t['changed'], None),
colorize('unreachable', t['unreachable'], None),
colorize('failed', t['failures'], None)),
log_only=True
)
except Exception as e:
print ("!!!!!!!ERROR: %s" % e)
Specify the vars in a host_vars file?
E.g. create a YAML file named /etc/ansible/host_vars/localhost with the vars you wanna put there.
I don't know, yet, how to specify it in Python code itself.
--- update ---
After a quick look the code, I don't think ansible supports specifying host variables when you specify hosts via host_list parameter. Hacks I can think of (if you must do this in python code) are:
[mis]use extra_vars parameter.
Write an inventory file (YAML or executable that just prints required JSON) from your python code and pass it's path as parameter inventory.
HTH

Categories

Resources