Use Json data to initialize an object in python? - python

Here is what I got right now.
import urllib2
import json
from pprint import pprint
response = urllib2.urlopen('http://census.soe.com/get/ps2:v2/weapon_datasheet?c:start=0&c:limit=1&c:show=capacity,clip_size,damage,fire_rate_ms,item_id,reload_ms')
response1 = urllib2.urlopen('http://census.soe.com/get/ps2:v2/item?c:start=0&c:limit=1&c:show=name.en,description.en,item_id')
data = json.load(response)
data1 = json.load(response1)
pprint(data)
pprint(data1)
class Weapon(object):
"""Creates a PlanetSide2 Weapon"""
def __init__(self, capacity, clip_size, damage, fire_rate_ms, itemd_id,
reload_ms, description, name):
self.capacity = capacity
self.clip_size = clip_size
self.damage = damage
self.fire_rate_ms = fire_rate_ms
self.item_id = item_id
self.reload_ms = reload_ms
self.description = description
self.name = name
right now my data looks like this.
{u'returned': 1,
u'weapon_datasheet_list': [{u'capacity': u'210',
u'clip_size': u'30',
u'damage': u'143',
u'fire_rate_ms': u'75',
u'item_id': u'73',
u'reload_ms': u'2455'}]}
{u'item_list': [{u'description': {u'en': u"The New Conglomerate's Mag-Cutter features a powerful electromagnet capable of cutting through enemy body armor."},
u'item_id': u'1',
u'name': {u'en': u'Mag-Cutter'}}],
u'returned': 1}
Is there a way to use the data from the json to initialize a weapon object with the name of the weapon?
for example. Mag-Cutter = Weapon(data from json file)
How would I got about reading setting the Weapon class variables from the json file data?

Sure, use the first element of data['weapon_datasheet_list'] plus some data from the first element of data1['item_list']:
name = data1['item_list'][0]['name']['en']
description = data1['item_list'][0]['description']['en']
mag_cutter = Weapon(name=name, description=description,
**data['weapon_datasheet_list'][0])
This applies all of the first weapon_datasheet_list item as keyword arguments to the Weapon() constructor, matching keys from that dictionary to the argument names of the constructor. The remaining two items, name and description, I supplied manually.
This does mean you need to correct a typo in the Weapon.__init__ signature; itemd_id should be spelled item_id to match the JSON structure.
Demo:
>>> import urllib2
>>> import json
>>> from pprint import pprint
>>> response = urllib2.urlopen('http://census.soe.com/get/ps2:v2/weapon_datasheet?c:start=0&c:limit=1&c:show=capacity,clip_size,damage,fire_rate_ms,item_id,reload_ms')
>>> response1 = urllib2.urlopen('http://census.soe.com/get/ps2:v2/item?c:start=0&c:limit=1&c:show=name.en,description.en,item_id')
>>> data = json.load(response)
>>> data1 = json.load(response1)
>>> class Weapon(object):
... """Creates a PlanetSide2 Weapon"""
... def __init__(self, capacity, clip_size, damage, fire_rate_ms, item_id,
... reload_ms, description, name):
... self.capacity = capacity
... self.clip_size = clip_size
... self.damage = damage
... self.fire_rate_ms = fire_rate_ms
... self.item_id = item_id
... self.reload_ms = reload_ms
... self.description = description
... self.name = name
...
>>> name = data1['item_list'][0]['name']['en']
>>> description = data1['item_list'][0]['description']['en']
>>> mag_cutter = Weapon(name=name, description=description,
... **data['weapon_datasheet_list'][0])
>>> pprint(vars(mag_cutter))
{'capacity': u'210',
'clip_size': u'30',
'damage': u'143',
'description': u"The New Conglomerate's Mag-Cutter features a powerful electromagnet capable of cutting through enemy body armor.",
'fire_rate_ms': u'75',
'item_id': u'73',
'name': u'Mag-Cutter',
'reload_ms': u'2455'}

Related

How to access data from custom_export in Otree?

I am trying to use ExtraModel and custom_export to export data from live_pages. However, when I go on devserver and check the data tab, it is nowhere to be found. If I download the excel (bottom right of the page) the new variables are not included in the data.
Where can I find the data from the custom export? Or am I defining the function wrong? Any help greatly appreciated.
See MWE below
from otree.api import *
import random
doc = """
Your app description
"""
class C(BaseConstants):
NAME_IN_URL = 'mwe_export'
PLAYERS_PER_GROUP = None
NUM_ROUNDS = 1
NUM_EMPLOYERS = 3
class Subsession(BaseSubsession):
pass
class Group(BaseGroup):
pass
class Player(BasePlayer):
pass
class Offer(ExtraModel):
group = models.Link(Group)
sender = models.Link(Player)
wage = models.IntegerField()
effort = models.IntegerField()
job_id = models.IntegerField()
information_type = models.StringField()
# FUNCTIONS
def to_dict(offer: Offer):
return dict(sender=offer.sender.id_in_group,
wage=offer.wage,
effort=offer.effort,
job_id=offer.job_id,
information_type=offer.information_type)
# PAGES
class MyPage(Page):
#staticmethod
def js_vars(player: Player):
return dict(my_id=player.id_in_group)
#staticmethod
def live_method(player: Player, data):
print(data)
group = player.group
job_id = random.randint(1, 1000)
wage = data['wage']
effort = data['effort']
information_type = data['information_type']
if data['information_type'] == 'offer':
offer = Offer.create(group=group,
sender=player,
job_id=job_id,
wage=wage,
effort=effort,
information_type=information_type)
print(offer)
print(to_dict(offer))
return {0: to_dict(offer)}
page_sequence = [MyPage]
def custom_export(players):
yield ['session.code', 'participant_code', 'id_in_session']
offers = Offer.filter()
for offer in offers:
player = offer.sender
participant = player.participant
yield [participant.code, participant.id_in_session, offer.job_id, offer.wage, offer.effort]
In the menu at the top of the admin page there is also a "Data" item. The custom export for your app should be available there under the heading "Per-app".

How to print values instead of memory addresses for my hashtable? Python

I'm reading in package data from a csv to my hashtable and when I go to print the data to check if it's being inserted correctly, I'm getting the memory address of the values. It reads in the packageID and prints that piece correctly.
I apologize for formatting the entire project in one file currently. I'm new to Python and how the files work together. When I have them split to separate files in Pycharm I couldn't tell what was being executed since it's dropdown menu would run a single file at a time (my guess)?
import csv
import math
####################################################################################################################
class hashtable:
# Set initial capacity of the Hashtable to 40 and sets the buckets to empty.
def __init__(self, initial_capacity=40):
# initialize the hash table with empty bucket list entries.
self.table = []
for i in range(initial_capacity):
self.table.append([])
# Inserts new key:value pair into desired bucket.
def insert(self, key, item): # does both insert and update
# get the bucket list where this item will go.
bucket = hash(key) % len(self.table)
bucket_list = self.table[bucket]
key_value = [key, item]
bucket_list.append(key_value)
return True
# Searches for the package using its packageID as the key and returns it if found.
def search(self, key):
# get the bucket list where this key would be.
bucket = hash(key) % len(self.table)
bucket_list = self.table[bucket]
# print(bucket_list)
# search for the key in the bucket list
for kv in bucket_list:
# print (key_value)
if kv[0] == key:
return kv[1] # value
return None
# Removes a package with the matching key.
def remove(self, key):
# get the bucket list where this item will be removed from.
bucket = hash(key) % len(self.table)
bucket_list = self.table[bucket]
# remove the item from the bucket list if it is present.
for kv in bucket_list:
# print (key_value)
if kv[0] == key:
bucket_list.remove([kv[0], kv[1]])
####################################################################################################################
class Package:
def __init__(self, ID, Address, City, State, Zip, Deadline, Weight, Notes, Status, Deliverytime):
self.packageID = ID
self.packageAddress = Address
self.packageCity = City
self.packageState = State
self.packageZip = Zip
self.packageDeadline = Deadline
self.packageWeight = Weight
self.packageNotes = Notes
self.packageStatus = Status
self.deliveryTime = Deliverytime
#####################################################################################################################
def loadPackageData(fileName):
with open(fileName) as Package_List:
packageData = csv.reader(Package_List, delimiter=',')
for package in packageData:
pID = int(package[0])
pAddress = package[1]
pCity = package[2]
pState = package[3]
pZip = package[4]
pDeadline = package[5]
pWeight = package[6]
pNotes = package[7]
pStatus = "At hub"
pDeliverytime = "00:00"
#package object
p = Package(pID, pAddress, pCity, pState, pZip, pDeadline, pWeight, pNotes, pStatus, pDeliverytime)
#print (p)
# insert into the hash table
myHash.insert(pID, p)
# Hash table instance
myHash = hashtable()
# Load packages to Hashtable
loadPackageData('packageData.csv')
print("Packages from Hashtable:")
print(myHash.table)
# Fetch data from hashtable
#for i in range (len(myHash.table)+1):
# print("Package: {}".format(myHash.search(i+1))) # 1 to 40 sent to myHash.search()
When print(myHash.table) is called I get output structured like this except for all 40 packages.
[[[40, <__main__.Package object at 0x000001E1489114C0>]], [[1, <__main__.Package object at 0x000001E148914220>]], [[2, <__main__.Package object at 0x000001E148911DF0>]], [[3, <__main__.Package object at 0x000001E148911D00>]]
I couldn't understand how to implement another post asking a similar question with my project so I am here now. I really appreciate all of you for any help!
You must override __repr__ and __str__ methods for class to be able print what you need.
In other way you may add own human_readable-like property
class PackageA:
def __init__(self, ID, Address, City, State, Zip, Deadline, Weight, Notes, Status, Deliverytime):
self.packageID = ID
self.packageAddress = Address
self.packageCity = City
self.packageState = State
self.packageZip = Zip
self.packageDeadline = Deadline
self.packageWeight = Weight
self.packageNotes = Notes
self.packageStatus = Status
self.deliveryTime = Deliverytime
class PackageB:
def __init__(self, ID, Address, City, State, Zip, Deadline, Weight, Notes, Status, Deliverytime):
self.packageID = ID
self.packageAddress = Address
self.packageCity = City
self.packageState = State
self.packageZip = Zip
self.packageDeadline = Deadline
self.packageWeight = Weight
self.packageNotes = Notes
self.packageStatus = Status
self.deliveryTime = Deliverytime
def __str__(self):
return f'STR is <{self.packageID} {self.packageAddress} {self.packageCity} {self.packageState} {self.packageZip} {self.packageDeadline} {self.packageWeight} {self.packageNotes} {self.packageStatus} {self.deliveryTime}>'
def __repr__(self):
return f'REPR is <{self.packageID} {self.packageAddress} {self.packageCity} {self.packageState} {self.packageZip} {self.packageDeadline} {self.packageWeight} {self.packageNotes} {self.packageStatus} {self.deliveryTime}>'
#property
def human_readable(self):
return f'Readable representation is <{self.packageID} {self.packageAddress} {self.packageCity} {self.packageState} {self.packageZip} {self.packageDeadline} {self.packageWeight} {self.packageNotes} {self.packageStatus} {self.deliveryTime}>'
packagesA = []
packagesB = []
for i in range(0,3):
packagesA.append(PackageA(f"ID{i}", f"Address{i}", f"City{i}", f"State{i}", f"Zip{i}", f"Deadline{i}", f"Weight{i}", f"Notes{i}", f"Status{i}", f"Deliverytime{i}"))
packagesB.append(PackageB(f"ID{i}", f"Address{i}", f"City{i}", f"State{i}", f"Zip{i}", f"Deadline{i}", f"Weight{i}", f"Notes{i}", f"Status{i}", f"Deliverytime{i}"))
print(packagesA)
print("--")
print(packagesB)
print("--")
print([str(x) for x in packagesB])
print("--")
print([x.human_readable for x in packagesB])
Output:
[<__main__.PackageA object at 0x104ca0710>, <__main__.PackageA object at 0x104ca0a90>, <__main__.PackageA object at 0x104ca0e10>]
--
[REPR is <ID0 Address0 City0 State0 Zip0 Deadline0 Weight0 Notes0 Status0 Deliverytime0>, REPR is <ID1 Address1 City1 State1 Zip1 Deadline1 Weight1 Notes1 Status1 Deliverytime1>, REPR is <ID2 Address2 City2 State2 Zip2 Deadline2 Weight2 Notes2 Status2 Deliverytime2>]
--
['STR is <ID0 Address0 City0 State0 Zip0 Deadline0 Weight0 Notes0 Status0 Deliverytime0>', 'STR is <ID1 Address1 City1 State1 Zip1 Deadline1 Weight1 Notes1 Status1 Deliverytime1>', 'STR is <ID2 Address2 City2 State2 Zip2 Deadline2 Weight2 Notes2 Status2 Deliverytime2>']
--
['Readeable representation is <ID0 Address0 City0 State0 Zip0 Deadline0 Weight0 Notes0 Status0 Deliverytime0>', 'Readeable representation is <ID1 Address1 City1 State1 Zip1 Deadline1 Weight1 Notes1 Status1 Deliverytime1>', 'Readeable representation is <ID2 Address2 City2 State2 Zip2 Deadline2 Weight2 Notes2 Status2 Deliverytime2>']
In this case it is printing the python objects default __repr__() which prints classname<memory location>. You would want to write a custom __repr__() that returns a string of what data you want to show up there.
So in your case you might want to do something like this:
class Package:
def __init__(self, ID, Address, City, State, Zip, Deadline, Weight, Notes, Status, Deliverytime):
self.packageID = ID
self.packageAddress = Address
self.packageCity = City
self.packageState = State
self.packageZip = Zip
self.packageDeadline = Deadline
self.packageWeight = Weight
self.packageNotes = Notes
self.packageStatus = Status
self.deliveryTime = Deliverytime
def __repr__(self):
# Creates a list of lists where [value, attribute]
attributes = [[getattr(self, attr), attr] for attr in dir(self) if not attr.startswith("__")]
# Start result string with classname
result = "Package("
for attribute in attributes:
result += f"{attribute[1]}= {attribute[0]},"
result+=")"
return result
print(Package(1,1,1,1,1,1,1,1,1,1)) # prints Package(deliveryTime= 1,packageAddress= 1,packageCity= 1,packageDeadline= 1,packageID= 1,packageNotes= 1,packageState= 1,packageStatus= 1,packageWeight= 1,packageZip= 1,)
This is a very quick and dirty implementation you can clean up to be faster and do what you want exactly, but basically it steps through the class and goes through each non dunder (starting with __) attribute, and then creates a string that is in the form of classname(attribute=value,) for every attribute in the class.
Looking at your class you could also use the dataclasses module because you have so many attributes, but since I don't know the types I can't give you a solution, or use a namedtuple. All of these have built in __repr__() functions.

Defensive conditions when JSON field is missing in API

I am developing a small Python script in order to get the weather data from forecast.io Once I get the JSON document, I call a Class in order to create a new record to be saved in the database. The problem is that some fields (which are also attributes in my Class) are not always informed in the API so I must include some kind of defensive code or the script will break when field is not found.
I've found this answer of #Alex Martelli which seams pretty good: Reading from Python dict if key might not be present
If you want to do something different than using a default value (say,
skip the printing completely when the key is absent), then you need a
bit more structure, i.e., either:
for r in results:
if 'key_name' in r:
print r['key_name']
or
for r in results:
try: print r['key_name']
except KeyError: pass
But I am wondering if I must include an "if" or a "try" on every field I want to save or is there a prettier way to do this? (I want to save 27 fields and 27 "if" seems ugly)
This is the code I have so far:
from datetime import datetime
import tornado.web
import tornado.httpclient
from tornado import gen
from src.db.city import list_cities
from src.db.weather import Weather
from motorengine import *
#gen.coroutine
def forecastio_api():
http_client = tornado.httpclient.AsyncHTTPClient()
base_url = "https://api.forecast.io/forecast/APIKEY"
city yield list_cities()
for city in city:
url = base_url + "/%s,%s" %(str(city.loc[0]), str(city.loc[1]))
response = yield http_client.fetch(url)
json = tornado.escape.json_decode(response.body)
for day in json['daily']['data']:
weather = Weather(city=city,
time = datetime.fromtimestamp(day['time']),
summary = day.get('summary'),
icon = day.get('icon'),
sunrise_time = datetime.fromtimestamp(day.get('sunriseTime')),
sunset_time = datetime.fromtimestamp(day.get('sunsetTime')),
moon_phase = day.get('moonPhase'),
precip_intensity = day.get('precipIntensity'),
precip_intensity_max = day.get('precipIntensityMax'),
precip_intensity_max_time = datetime.fromtimestamp(day.get('precipIntensityMaxTime')),
precip_probability = day.get('precipProbability'),
precip_type = day.get('precipType'),
temperature_min = day.get('temperatureMin'),
temperature_min_time = datetime.fromtimestamp(day.get('temperatureMinTime')),
temperature_max = day.get('temperatureMax'),
temperature_max_time = datetime.fromtimestamp(day.get('temperatureMaxTime')),
apparent_temperature_min = day.get('apparentTemperatureMin'),
apparent_temperature_min_time = datetime.fromtimestamp(day.get('apparentTemperatureMinTime')),
apparent_temperature_max = day.get('apparentTemperatureMax'),
apparent_temperature_max_time = datetime.fromtimestamp(day.get('apparentTemperatureMaxTime')),
dew_point = day.get('dewPoint'),
humidity = day.get('humidity'),
wind_speed = day.get('windSpeed'),
wind_bearing = day.get('windBearing'),
visibility = day.get('visibility'),
cloud_cover = day.get('cloudCover'),
pressure = day.get('pressure'),
ozone = day.get('ozone')
)
weather.create()
if __name__ == '__main__':
io_loop = tornado.ioloop.IOLoop.instance()
connect("DATABASE", host="localhost", port=27017, io_loop=io_loop)
forecastio_api()
io_loop.start()
and this is the Weather Class using Motornegine:
from tornado import gen
from motorengine import Document
from motorengine.fields import DateTimeField, DecimalField, ReferenceField, StringField
from src.db.city import City
class Weather(Document):
__collection__ = 'weather'
__lazy__ = False
city = ReferenceField(reference_document_type=City)
time = DateTimeField(required=True)
summary = StringField()
icon = StringField()
sunrise_time = DateTimeField()
sunset_time = DateTimeField()
moon_phase = DecimalField(precision=2)
precip_intensity = DecimalField(precision=4)
precip_intensity_max = DecimalField(precision=4)
precip_intensity_max_time = DateTimeField()
precip_probability = DecimalField(precision=2)
precip_type = StringField()
temperature_min = DecimalField(precision=2)
temperature_min_time = DateTimeField()
temperature_max = DecimalField(precision=2)
temperature_max_time = DateTimeField()
apparent_temperature_min = DecimalField(precision=2)
apparent_temperature_min_time = DateTimeField()
apparent_temperature_max = DecimalField(precision=2)
apparent_temperature_max_time = DateTimeField()
dew_point = DecimalField(precision=2)
humidity = DecimalField(precision=2)
wind_speed = DecimalField(precision=2)
wind_bearing = DecimalField(precision=2)
visibility = DecimalField(precision=2)
cloud_cover = DecimalField(precision=2)
pressure = DecimalField(precision=2)
ozone = DecimalField(precision=2)
create_time = DateTimeField(auto_now_on_insert=True)
#gen.coroutine
def create(self):
yield self.save()
You can check Schematics. This library helps you define objects that can be easily populated from dicts(you can easily turn json to python dict). It allows you to define validation rules on each property. The object will throw ModelValidationError error when some properties are missing or in the wrong format. Schematics allows you to add default values and a lot more nice stuff when you define your models.

Looking for a better data structure in python

I have some basic data that I want to store and I'm looking for a better solution then what I've come up with.
I have multiple entries of data with 4 fields per entry, name, url, currYear, availYears
I can solve this with a simple array of arrays like so:
data = [
['test-name', ['http://example.com', '2015', '2015,2014']]
['next-name', ['http://example.org', '1999', '1999']]
]
But this gets messy when trying to access data in each array. I end up with a for loop like this
for each in data:
name = each[0]
url = each[1][0]
currYear = each[1][1]
I'd prefer to do something similar to a dict where I can reference what I want by a key name. This isn't valid syntax, but hopefully it gets the point across.
data = {'entry1': {'name': 'test-name'}, {'url': 'http://example.com'}, {'currYear': '2015'}, {'availYears': '2015,2014'}}
Then I could pull the url data for entryX.
EDIT:
Several good responses. I decided to go with creating a class since 1) it satisfies my need 2) helps clean up the code by segregating functionality and 3) learn how packages, modules and classes work compared to Java (which I'm more familiar with).
In addition to creating the class, I also created getters and setters.
class SchoolSiteData(object):
def __init__(self, name, url, currYear, availYears):
self.name = name
self.url = url
self.currYear = currYear
self.availYears = availYears
def getName(self):
return self.name
def getURL(self):
return self.url
def getCurrYear(self):
return self.currYear
def getAvailYears(self):
return self.availYears
def setName(self, name):
self.name = name
def setURL(self, url):
self.url = url
def setCurrYear(self, currYear):
self.currYear = currYear
def setAvailYears(self, availYears):
self.availYears = availYears
A class may make this easier to use: eg:
class Entry(object):
def __init__(self, name, url, currYear, availYears):
self.name = name
self.url = url
self.currYear = currYear
self.availYears = availYears
entry1 = Entry('test-name', 'http://example.com', '2015', '2015,2014')
entry2 = Entry('next-name', 'http://example.org', '1999', '1999')
data = [entry1, entry2]
for entry in data:
print entry.name
print entry.url
print entry.currYear
print entry.availYears
print
Use the names as the keys in a dictionary:
data = {'test-name':
{'url': 'http://example.com',
'currYear': '2015',
'availYears': '2015,2014'
}
}
Access like so:
data['test-data']['url']
You seem to have needlessly complicated things with the list-in-list solution. If you keep it a little flatter, you can just unpack the rows into variables:
data = [
['test-name', 'http://example.com', '2015', '2015,2014'],
['next-name', 'http://example.org', '1999', '1999']
]
for name, url, currYear, availYears in data:
....
The most light-weight solution for what you want is probably a namedtuple.
>>> from collections import namedtuple
>>> mytuple = namedtuple("mytuple", field_names="url currYear availYears")
>>> data = [ 'test-name': mytuple('http://example.com', '2015', '2015,2014'), ...
... ]
>>> print(data['test-name'])
mytuple(url='http://example.com', currYear='2015', availYears='2015,2014')
You can access members by numerical index or by name:
>>> x = data['test-name']
>>> print(x.currYear)
2015
>>> print(x[1])
2015
data = [
{'name': 'test-name', 'url': 'http://example.com', 'currYear': '2015', 'availYears': '2015,2014'},
{'name': 'next-name', 'url': 'http://example.org', 'currYear': '1999', 'availYears': '1999'}
]
for each in data:
name = each['name']
url = each['url']
currYear = each['currYear']

Layered Classes and JSON encoding

I have some Data that I need to write to a JSON string.
I have it working with dict items but want to encompass it all in classes to help ensure the correct data.
The following code is a comparison between the dict items and the class item output. They don't match, and I can't figure out what I am missing.
I get a "bound method Event.encode of Event..." in my JSON string.
from collections import namedtuple
import json
class Event(namedtuple('Event', 'itemName, itemID')):
def encode(self):
obj = {}
obj['itemName'] = str(self.itemName)
obj['itemID'] = int(self.itemID)
return json.dumps(obj)
curEv = Event('MyName', 5)
print 'ClassEv : ', curEv.encode()
curEv2 = {'itemName':'MyName', 'itemID':5}
print 'DictEv : ', json.dumps(curEv2)
class Packet(namedtuple('Packet', 'pID, itemType, itemData')):
def encode(self):
obj = {}
obj['pID'] = int(self.pID)
obj['itemType'] = int(self.itemType)
obj['itemData'] = str(self.itemData.encode)
return json.dumps(obj)
packet = Packet(11, 0, curEv)
print 'ClassPacket: ', packet.encode()
packet2 = {'pID':11, 'itemType':0}
packet2['itemData'] = curEv2
print 'DictPacket : ', json.dumps(packet2)
You are failing to call the itemData.encode() function. Instead you are simply returning a reference to it.
Try:
obj['itemData'] = str(self.itemData.encode())
Note the extra () at the end.

Categories