How to dynamic call class instance attribute? - python-3.x

I am doing some parse work with hl7apy parse, and i occurred with one problem.
I use hl7apy to parse hl7 message, which can be parse:
from hl7apy.parser import parse_message
message = "MSH|^~\&|HIS|HIS|MediII|MediII|20170902141711||ORM^O01^ORM_O01|15b 37e7132504a0b95ade4654b596dc5|P|2.4\r"
msg = parse_message(message, find_groups=False)
print(msg.msh.msh_3.msh_3_1.value)
output:
'HIS'
so, how can i get field value dynamically according to field config?
for example, the msh field config :
{
"field": "msh",
"field_index": [3,1]
}
so the value can be find with:
msg.msh.msh_3.msh_3_1.value
and if config change to:
{
"field": "pid",
"field_index": [2,4]
}
the get field line will be:
msg.pid.pid_2.pid_2_4.value

You could combine a few list comprehensions and use getattr recursively.
# recursively get the methods from a list of names
def get_method(method, names):
if names:
return get_method(getattr(method, names[0]), names[1:])
return method
field_config = {
'field': 'msh',
'field_index': [3, 1]
}
# just get the field
field = field_config['field']
# get a list of the indexes as string. ['3', '1']
indexes = [str(i) for i in field_config['field_index']]
# join the indexes with a '_' starting with nothing
# and put it in a list of names. ['msh', 'msh_3', 'msh_3_1']
names = ['_'.join([field] + indexes[:i]) for i in range(len(indexes) + 1)]
# get the method from the recursive function
method = get_method(msg, names)
print(method.value)
As a disclaimer, I had no way of testing it so it may not work exactly as you expect it. But this should be a good starting point.

Related

Boto3 different outputs

I am trying to get the instance id of ec2 that I created. But I get 2 different outputs, why? Please check the print outputs.
print (a)
i-0ae514dcs36chb154
print (instance)
ec2.Instance(id='i-0ae514dcs36chb154')
ec=ec2.create_instances(
ImageId=ami,
InstanceType=type,
MinCount=size,
MaxCount=size,
KeyName=keyname,
SecurityGroupIds=[sg],
TagSpecifications=[
{
'ResourceType': 'instance',
'Tags': [
{
'Key': 'Name',
'Value': name,
},
],
},
],
)
a= ec[0].id
print (a) # Output: i-0ae514dcs36chb154
instance = ec2.Instance(a)
print (instance) # Output : ec2.Instance(id='i-0ae514dcs36chb154')
Thansks.
As seen here:
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.ServiceResource.create_instances
When you call create_instances() it returns a list of ec2.Instance() which is an object with an attribute id.
When you write,
a = ec[0].id # Create a variable called "a" that points to the value of the "id" attribute of the first element in the list
print(a) # print the id
When you write,
a = ec[0].id # Create a variable called "a" that points to the value of the "id" attribute of the first element in the list
print(ec2.Instance(a)) # Create a new instance of ec2.Instance() with id equal to the value at a, then call the .__str__ method, and print
^ this is actually redundant.
Calling print(ec[0]) should yield ec2.Instance(id='i-0ae514dcs36chb154')
So, the reason they are different is that in the first you are printing the value of the attribute id of the ec2.Instance() object. In the second you are printing the ec2.Instance() object itself, which will call the private method __str__ on the ec2.Instance() object in order to produce a string to print.

Reading and writing to a dictionary dynamically

I am trying to read value from dictionary and then write to a different one.
The following works, but is hardcoded
this_application['bounces'] = {}
this_application['bounces']['month'] = {}
this_application['bounces']['month']['summary'] = {}
try:
got_value = application.ga_data['ga:bounces']['ga:month']['summary']['recent']
except:
got_value = ""
this_application['bounces']['month']['summary']['recent'] = got_value
What I want to do though, is pass in a from and to list (as I will have lots of these).
I was imagining the input would be something like this
{"ga_data": [{"from": "ga:bounces.ga:month.summary.recent", "to": "bounces.month.summary.recent"},{"from": "ga:sessions.ga:month.summary.recent", "to": "sessions.month.summary.recent"}]}
In which case it would do the above twice (with checking for existing dictionaries etc). I am fine on the checking etc., it is how to use the above that I am stuck on.
Any help would be appreciated
Thanks
You can use defaultdict but there are some special things to consider when doing it. If you read a value that does not exist it will add an empty value to the dict.
import collections
nested_dict = lambda: collections.defaultdict(nested_dict)
d = nested_dict()
d[1][2][3] = 'Hello, dictionary!'
print(d[2]) # I read the value and thus added the key to the dict
print(d[1][2][3]) # Prints Hello, dictionary!
print(d.keys()) # Shows that [1, 2] are keys
Credit To: How can I get Python to automatically create missing key/value pairs in a dictionary?

How to loop through a map and display only one row if there is matching values

I have a map with differnt keys and multiple values.If there is any matching job among different keys,I have to display only one row and grouping code values.
def data = ['Test1':[[name:'John',dob:'02/20/1970',job:'Testing',code:51],[name:'X',dob:'03/21/1974',job:'QA',code:52]],
'Test2':[name:'Michael',dob:'04/01/1973',job:'Testing',code:52]]
for (Map.Entry<String, List<String>> entry : data.entrySet()) {
String key = entry.getKey();
List<String> values = entry.getValue();
values.eachWithIndex{itr,index->
println("key is:"+key);
println("itr values are:"+itr);
}
}
Expected Result : [job:Testing,code:[51,52]]
First flatten all the relevant maps, so whe just have a flat list of all of them, then basically the same as the others suggested: group by the job and just keep the codes (via the spread operator)
def data = ['Test1':[[name:'John',dob:'02/20/1970',job:'Testing',code:51],[name:'X',dob:'03/21/1974',job:'QA',code:52]], 'Test2':[name:'Michael',dob:'04/01/1973',job:'Testing',code:52]]
assert data.values().flatten().groupBy{it.job}.collectEntries{ [it.key, it.value*.code] } == [Testing: [51, 52], QA: [52]]
Note: the question will be changed according to the comments from the other answers.
Above code will give you the jobs and and their codes.
As of now, it's not clear, what the new expected output should be.
You can use the groovy's collection methods.
First you need to extract the lists, since you dont need the key of the top level element
def jobs = data.values()
Then you can use the groupBy method to group by the key "job"
def groupedJobs = jobs.groupBy { it.job }
The above code will produce the following result with your example
[Testing:[[name:John, dob:02/20/1970, job:Testing, code:51], [name:Michael, dob:04/01/1973, job:Testing, code:52]]]
Now you can get only the codes as values and do appropriate changes to make key as job by the following collect function
def result = groupedJobs.collect {key, value ->
[job: key, code: value.code]
}
The following code (which uses your sample data set):
def data = ['Test1':[name:'John', dob:'02/20/1970', job:'Testing', code:51],
'Test2':[name:'Michael', dob:'04/01/1973', job:'Testing', code:52]]
def matchFor = 'Testing'
def result = [job: matchFor, code: data.findResults { _, m ->
m.job == matchFor ? m.code : null
}]
println result
results in:
~> groovy solution.groovy
[job:Testing, code:[51, 52]]
~>
when run. It uses the groovy Map.findResults method to collect the codes from the matching jobs.

How do I build a string of variable names?

I'm trying to build a string that contains all attributes of a class-object. The object name is jsonData and it has a few attributes, some of them being
jsonData.Serial,
jsonData.InstrumentSerial,
jsonData.Country
I'd like to build a string that has those attribute names in the format of this:
'Serial InstrumentSerial Country'
End goal is to define a schema for a Spark dataframe.
I'm open to alternatives, as long as I know order of the string/object because I need to map the schema to appropriate values.
You'll have to be careful about filtering out unwanted attributes, but try this:
' '.join([x for x in dir(jsonData) if '__' not in x])
That filters out all the "magic methods" like __init__ or __new__.
To include those, do
' '.join(dir(jsonData))
These take advantage of Python's dir method, which returns a list of all attributes of an object.
I don't quite understand why you want to group the attribute names in a single string.
You could simply have a list of attribute names as the order of a python list is persist.
attribute_names = [x for x in dir(jsonData) if '__' not in x]
From there you can create your dataframe. If you don't need to specify the SparkTypes, you can just to:
df = SparkContext.createDataFrame(data, schema = attribute_names)
You could also create a StructType and specify the types in your schema.
I guess that you are going to have a list of jsonData records that you want to consider as Rows.
Let's considered it as a list of objects, but the logic would still be the same.
You can do that as followed:
my_object_list = [
jsonDataClass(Serial = 1, InstrumentSerial = 'TDD', Country = 'France'),
jsonDataClass(Serial = 2, InstrumentSerial = 'TDI', Country = 'Suisse'),
jsonDataClass(Serial = 3, InstrumentSerial = 'TDD', Country = 'Grece')]
def build_record(obj, attr_names):
from operator import attrgetter
return attrgetter(*attr_names)(obj)
So the data attribute referred previously would be constructed as:
data = [build_record(x, attribute_names) for x in my_object_list]

Nested dictionaries in Python: how to make them and how to use them?

I'm still trying to figure it out how nested dictionaries in python really works.
I know that when you're using [] it's a list, () it's a tuple and {} a dict.
But when you want to make a nested dictionaries like this structure (that's what a i want) :
{KeyA :
{ValueA :
[KeyB : ValueB],
[Keyc : ValueC],
[KeyD : ValueD]},
{ValueA for each ValueD]}}
For now I have a dict like:
{KeyA : {KeyB : [ValueB],
KeyC : [ValueC],
KeyD : [ValueD]}}
Here's my code:
json_file = importation()
dict_guy = {}
for key, value in json_file['clients'].items():
n_customerID = normalization(value['shortname'])
if n_customerID not in dict_guy:
dict_guy[n_customerID] = {
'clientsName':[],
'company':[],
'contacts':[], }
dict_guy[n_customerID]['clientsName'].append(n_customerID)
dict_guy[n_customerID]['company'].append(normalization(value['name']))
dict_guy[n_customerID]['contacts'].extend([norma_email(item) for item in v\
alue['contacts']])
Can someone please, give me more informations or really explain to me how a nested dict works?
So, I hope I get it right from our conversation in the comments :)
json_file = importation()
dict_guy = {}
for key, value in json_file['clients'].items():
n_customerID = normalization(value['shortname'])
if n_customerID not in dict_guy:
dict_guy[n_customerID] = {
'clientsName':[],
'company':[],
'contacts':{}, } # Assign empty dict, not list
dict_guy[n_customerID]['clientsName'].append(n_customerID)
dict_guy[n_customerID]['company'].append(normalization(value['name']))
for item in value['contacts']:
normalized_email = norma_email(item)
# Use the contacts dictionary like every other dictionary
dict_guy[n_customerID]['contacts'][normalized_email] = n_customerID
There is no problem to simply assign a dictionary to a key inside another dictionary. That's what I do in this code sample. You can create dictionaries nested as deep as you wish.
How that this helped you. If not, we'll work on it further :)
EDIT:
About list/dict comprehensions. You are almost right that:
I know that when you're using [] it's a list, () it's a tuple and {} a dict.
The {} brackets are a little tricky in Python 3. They can be used to create a dictionary as well as a set!
a = {} # a becomes an empty dictionary
a = set() # a becomes an empty set
a = {1,2,3} # a becomes a set with 3 values
a = {1: 1, 2: 4, 3: 9} # a becomes a dictionary with 3 keys
a = {x for x in range(10)} # a becomes a set with 10 elements
a = {x: x*x for x in range(10)} # a becomes a dictionary with 10 keys
Your line dict_guy[n_customerID] = { {'clientsName':[], 'company':[], 'contacts':[]}} tried to create a set with a single dictionary in it and because dictionaries are not hashable, you got the TypeError exception informing you that something is not hashable :) (sets can store only ements that are hashable)
Check out this page.
example = {'app_url': '', 'models': [{'perms': {'add': True, 'change': True,
'delete': True}, 'add_url': '/admin/cms/news/add/', 'admin_url': '/admin/cms/news/',
'name': ''}], 'has_module_perms': True, 'name': u'CMS'}

Resources