How to automate saving constants? [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed last year.
Improve this question
I am in the process of running experiments, and ideally, once all of my code is working, the only parameters that will need to be changed will all be present in one file. My initial idea was to store these parameters in a JSON file:
{
"param1": 1,
"param2": "string parameter"
}
Where, obviously, I have many more than 2 parameters. This turns out to be a nightmare, as my IDE will not guess any of the parameters, which massively slows down my programming as I generally feel obligated to create local variables for every constant that I need in the current function that I'm working in. This results in a lot of unnecessary code (but local to that function, it is significantly more convenient than trying to index the JSON object).
My next thought was then: store the constants in a file like:
PARAM1 = 1
PARAM2 = 'string parameter'
The problem with this is that I'd like to store the parameters with experimental results so that I can look back to see which parameters were specified to produce those results.
Beyond this, my thought is to use a dataclass (probably one with frozen=True), as those can be converted to a dictionary. However, I do not need access to an instance of the class, just the constants within it.
Another thought is to use a class with static variables:
class ExperimentalMetaData:
param1 = 1
param2 = "string parameter"
Which can be converted to a dict with vars(ExperimentalMetaData), except this will contain additional keys that should be popped off before I go about storing the data.
My question is: what is the best way to store constants in python such that they can be saved to a JSON file easily, and also be easily accessed within my code?

If you want to be able to recall different versions of inputs, give them a version
This allows you to create JSON-like input files and keep a collection of parsers which can parse them if you make a breaking change
Here's a very simple example which is more sustainable
class Parser_v1_2(): pass
class Parser_v3_2(): pass
VERSION_PARSER_MAPPING = {
"1.2": Parser_v1_2,
"3.2": Parser_v3_2,
}
def parser_map(input_file):
with open(input_file) as fh:
input_json = json.load(fh)
# get version or optionally provide a default
version = input_json.get("version", "1.0")
# dynamically select parser
return VERSION_PARSER_MAPPING[version](input_json)

Split up your problems.
Storing the data
Serialise it to JSON or YAML (or even csv).
Getting the data
Have a module which reads your json and then sets the right values. Something like:
# constants.py
from json import load
data = load("dump.json")
const1: str = data["const1"]
const2: str = data["const2"]
const3: int = data["const3"]
# some_other_module.py
from constants import const1, const2 # IDE knows what they are
I'd only do this manually with vars in a module for a small (<20) number of vars I needed a lot and didn't want to wrap in some dictionary or the like. Otherwise I'd just use a dict in the module. Pre-populating the dict with keys and None and typehinting it will do the same job of getting autocomplete working.

Related

Using a variable as a dict key

I have JSON objects coming in:
{"Name":"server1","NodeID":1063,"RowID":"3","Vendor":"HP","Load":"41"},
{"Name":"server2","NodeID":1064,"RowID":"7","Vendor":"HP","Load":"12"},
{"Name":"server82","NodeID":1064,"RowID":12","Vendor":"HP","Load":"2"},
{"Name":"server242","NodeID":1064,"RowID":"4","Vendor":"HP","Load":"1"},
{"Name":"server572","NodeID":1064,"RowID":"4","Vendor":"HP","Load":"44"},
{"Name":"server8","NodeID":1064,"RowID":"2","Vendor":"HP","Load":"23"},
{"Name":"server8","NodeID":1064,"RowID":"7","Vendor":"HP","Load":"1"},
...
And I am outputting a different format, here is the dict before I feed it to urllib.request.
import json
import urllib.request
machine = {}
machine['_type'] = "general_data"
machine['_system'] = "LinuxDataCpu"
machine['_device'] = i['Name']
machine['CPUload1'] = i['Load']
If this was a bash script, CPUload$RowID would likely form the basis of the solution.
I have some machines with 1 CPU, some with 8, and some with 12.
I have a JSON object machine() that will be created and pushed out in a post.
Each JSON object will contain only one CPU value, so the key needs to reflect which cpu is being reported (1 to 12).
How do I use a variable for a key such that I can indicate a different key name for each CPU?
So the first line for server1 would get:
machine['CPUload3'] = i['Load']
And the second line gets:
machine['CPUload7'] = i['Load']
For the respective output key: value pair. Each line only reports one row at a time, so a 12 cpu machine would randomly send reports listing individual cpu's. On the back end nothing is random, but the raw sql generating the data is not ordering the data in any way. The data is actually a large block of data, but the API I am sending the json to can only take one key value pair for the data. it should let me pass the whole json object, but decisions were made out of my control, and one payload variable is allowd per post.
Michael Butscher offers: "['CPUload' + i['RowID']]"... this was what I was looking for. (yeah I'm a rookie hack with python).
Type it up Michael and I'll mark it to give you the credit.
Thanks everyone!!
Just create a string variable, pass the incremental server number via a loop and pass the string variable into the key.
Something like:
incrementalCPUnumber = 1
key = 'CPUload{0}'.format(incrementalCPUnumber)
machine[x] = i['Load']
I think you'll need to clarify more, but on face value, this is what it seems like you are trying to do.

Key 'boot_num' is not recognized when being interpreted from a .JSON file

Currently, I am working on a Boot Sequence in Python for a larger project. For this specific part of the sequence, I need to access a .JSON file (specs.json), establish it as a dictionary in the main program. I then need to take a value from the .JSON file, and add 1 to it, using it's key to find the value. Once that's done, I need to push the changes to the .JSON file. Yet, every time I run the code below, I get the error:
bootNum = spcInfDat['boot_num']
KeyError: 'boot_num'`
Here's the code I currently have:
(Note: I'm using the Python json library, and have imported dumps, dump, and load.)
# Opening of the JSON files
spcInf = open('mki/data/json/specs.json',) # .JSON file that contains the current system's specifications. Not quite needed, but it may make a nice reference?
spcInfDat = load(spcInf)
This code is later followed by this, where I attempt to assign the value to a variable by using it's dictionary key (The for statement was a debug statement, so I could visibly see the Key):
for i in spcInfDat['spec']:
print(CBL + str(i) + CEN)
# Loacting and increasing the value of bootNum.
bootNum = spcInfDat['boot_num']
print(str(bootNum))
bootNum = bootNum + 1
(Another Note: CBL and CEN are just variables I use to colour text I send to the terminal.)
This is the interior of specs.json:
{
"spec": [
{
"os":"name",
"os_type":"getwindowsversion",
"lang":"en",
"cpu_amt":"cpu_count",
"storage_amt":"unk",
"boot_num":1
}
]
}
I'm relatively new with .JSON files, as well as using the Python json library; I only have experience with them through some GeeksforGeeks tutorials I found. There is a rather good chance that I just don't know how .JSON files work in conjunction with the library, but I figure that it would still be worth a shot to check here. The GeeksForGeeks tutorial had no documentation about this, as well as there being minimal I know about how this works, so I'm lost. I've tried searching here, and have found nothing.
Issue Number 2
Now, the prior part works. But, when I attempt to run the code on the following lines:
# Changing the values of specDict.
print(CBL + "Changing values of specDict... 50%" + CEN)
specDict ={
"os":name,
"os_type":ost,
"lang":"en",
"cpu_amt":cr,
"storage_amt":"unk",
"boot_num":bootNum
}
# Writing the product of makeSpec to `specs.json`.
print(CBL + "Writing makeSpec() result to `specs.json`... 75%" + CEN)
jsonobj = dumps(specDict, indent = 4)
with open('mki/data/json/specs.json', "w") as outfile:
dump(jsonobj, outfile)
I get the error:
TypeError: Object of type builtin_function_or_method is not JSON serializable.
Is there a chance that I set up my dictionary incorrectly, or am I using the dump function incorrectly?
You can show the data using:
print(spcInfData)
This shows it to be a dictionary, whose single entry 'spec' has an array, whose zero'th element is a sub-dictionary, whose 'boot_num' entry is an integer.
{'spec': [{'os': 'name', 'os_type': 'getwindowsversion', 'lang': 'en', 'cpu_amt': 'cpu_count', 'storage_amt': 'unk', 'boot_num': 1}]}
So what you are looking for is
boot_num = spcInfData['spec'][0]['boot_num']
and note that the value obtained this way is already an integer. str() is not necessary.
It's also good practice to guard against file format errors so the program handles them gracefully.
try:
boot_num = spcInfData['spec'][0]['boot_num']
except (KeyError, IndexError):
print('Database is corrupt')
Issue Number 2
"Not serializable" means there is something somewhere in your data structure that is not an accepted type and can't be converted to a JSON string.
json.dump() only processes certain types such as strings, dictionaries, and integers. That includes all of the objects that are nested within sub-dictionaries, sub-arrays, etc. See documentation for json.JSONEncoder for a complete list of allowable types.

Multi language support in application [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I'm trying to create a little tool which also features a GUI. I want to offer different languages in the interface. That's why I think about writing all the strings in a file for each language and read the data while creating the gui. I'm worried about that this could takes alot of memory and decreasing performance.
Is there a good way to implement this?
Pseudocode example:
language_file = open(path)
title = language_file.title
text = language_file.text
button_text = language_file.btntext
window = tk.Tk()
la_title = tk.Label(window, text=title)
la_text = tk.Label(window, text=text)
btn = tk.Button(window, text=button_text, command=close_window)
1. Find a proper file Format.
Some Formats are better suited than others. You Need something where you can define something like a label and for each language the correpsonding value. You could try the csv Format.
2. Loading the data into a python object
When you have created your file with all your data you can load it at the start of your program into a python object. this shouldn't take too Long when your file isn't huge and I mean huge. You open the file and load in some python opject to work with it.
3. Creating a proper python object.
What you want is something like a dictionary. You have a label which is the key and a value dependent on the selected language. So you could either have for each language a dictionary. or a more nested ditionary.
For better Access I would create a class to handle all this.
Possible Things that can make Things easier. (I will expand this part later on. And add more details)
You could:
Override the __getattr__ method so you can write: Language.header
Extend the __dict__ of the the class with the language dictionary: Language.header is possible
write a function: Language.get_text("Header") or Language.get_text("Header", "english") or ...
Dictionary example (expanding __dict__)
class Language:
def __init__(self, texts):
self.texts = Texts
print(dir(self)) # just for debug
# Magic part
self.__dict__.update(self.texts)
print(dir(self)) # just for debug. Note the last entries
#staticmethod
def from_file(path, language):
# comment the open part out if you just want to test this example without a file
with open(path, r) as f:
pass # Read content. Get all words of language
texts = {"header": "My header", "label_username": "Username"}
return Language(texts)
l = Language.from_file("Some path to a file", "English")
print(l.header)
print(l.label_username)

Layer between data extraction and storage

What I am doing:
Get data from data source (could be from API or scraping) in form of a dictionary
Clean/manipulate some of the fields
Combine fields from data source dictionary into new dictionaries that represent objects
Save the created dictionaries into database
Is there a pythonic way to do this? I am wondering about the whole process but I'll give some guiding questions:
What classes should I have?
What methods/classes should the cleaning of fields from the data source to objects be in?
What methods/classes should the combining/mapping of fields from the data source to objects be in?
If the method is different in scraping vs. api, please explain how and why
Here is an example:
API returns:
{data: {
name: "<b>asd</b>",
story: "tame",
story2: "adjet"
}
}
What you want to do:
Clean name
Create a name_story object
Set name_story.name = dict['data']['name']
Set name_story.story = dict['data']['story'] + dict['data']['story2']
Save name_story to database
(and consider that there could be multiple objects to create and multiple incoming data sources)
How would you structure this process? An interface of all classes/methods would be enough for me without any explanation.
What classes should I have?
In Python, there is no strong need to use classes. Classes are the way to manage complexity. If your solution is not complex, use functions (or, maybe, module-level code, if it is one-time solution)
If the method is different in scraping vs. api, please explain how and why
I prefer to organize my code in respect with modularity and principle of least knowledge and define clear interfaces between parts of modules system.
Example of modular solution
You can have module (either function or class) for fetching information, and it should return dictionary with specified fields, no matter what exactly it does.
Another module should process dictionary and return dictionary too (for example).
Third module can save information from that dictionary to database.
There is great possibility, that this plan far from what you need or want and you should develop your modules system yourself.
And some words about your wants:
Clean name
Consider this stackoverflow answer
Create a name_story object
Set name_story.name = dict['data']['name']
Set name_story.story = dict['data']['story'] + dict['data']['story2']
If you want to have access to attributes of object through dot (as you specified in 3 and 4 items, you could use either python namedtuple or plain python class. If indexed access is OK for you, use python dictionary.
In case of namedtuple, it will be:
from collections import namedtuple
NameStory = namedtuple('NameStory', ['name', 'story'])
name_story1 = NameStory(name=dict['data']['name'], story=dict['data']['story'] + dict['data']['story2'])
name_story2 = NameStory(name=dict2['data']['name'], story=dict2['data']['name'])
If your choice if dictionary, it's easier:
name_story = {
'name': dict['data']['name'],
'story': dict['data']['story'] + dict['data']['story2'],
}
Save name_story to database
This is much more complex question.
You can use raw SQL. Specific instructions depends on your database. Google for 'python sqlite' or 'python postgresql' or what you want, there are plenty of good tutorials.
Or you can utilize one of python ORMs:
peewee
SQLAlchemy
google for more options
By the way
It's strongly recommended to not override python built-in types (list, dict, str etc), as you did in this line:
name_story.name = dict['data']['name']

How to inspect mystery deserialized object in Python

I'm trying to load JSON back into an object. The "loads" method seems to work without error, but the object doesn't seem to have the properties I expect.
How can I go about examining/inspecting the object that I have (this is web-based code).
results = {"Subscriber": {"firstname": "Neal", "lastname": "Walters"}}
subscriber = json.loads(results)
for item in inspect.getmembers(subscriber):
self.response.out.write("<BR>Item")
for subitem in item:
self.response.out.write("<BR> SubItem=" + subitem)
The attempt above returned this:
Item
SubItem=__class__
I don't think it matters, but for context:
The JSON is actually coming from a urlfetch in Google App Engine to
a rest web service created using this utility:
http://code.google.com/p/appengine-rest-server.
The data is being retrieved from a datastore with this definition:
class Subscriber(db.Model):
firstname = db.StringProperty()
lastname = db.StringProperty()
Thanks,
Neal
Update #1: Basically I'm trying to deserialize JSON back into an object.
In theory it was serialized from an object, and I want to now get it back into an object.
Maybe the better question is how to do that?
Update #2: I was trying to abstract a complex program down to a few lines of code, so I made a few mistakes in "pseudo-coding" it for purposes of posting here.
Here's a better code sample, now take out of website where I can run on PC.
results = '{"Subscriber": {"firstname": "Neal", "lastname": "Walters"}}'
subscriber = json.loads(results)
for key, value in subscriber.items():
print " %s: %s" %(key, value)
The above runs, what it displays doesn't look any more structured than the JSON string itself. It displays this:
Subscriber: {u'lastname': u'Walters', u'firstname': u'Neal'}
I have more of a Microsoft background, so when I hear serialize/deserialize, I think going from an object to a string, and from a string back to an object. So if I serialize to JSON, and then deserialize, what do I get, a dictionary, a list, or an object? Actually, I'm getting the JSON from a REST webmethod, that is on my behalf serializing my object for me.
Ideally I want a subscriber object that matches my Subscriber class above, and ideally, I don't want to write one-off custom code (i.e. code that would be specific to "Subscriber"), because I would like to do the same thing with dozens of other classes. If I have to write some custom code, I will need to do it generically so it will work with any class.
Update #3: This is to explain more of why I think this is a needed tool. I'm writing a huge app, probably on Google App Engine (GAE). We are leaning toward a REST architecture for several reasons, but one is that our web GUI should access the data store via a REST web layer. (I'm a lot more used to SOAP, so switching to REST is a small challenge in itself). So one of the classic ways of getting and update data is through a business or data tier. By using the REST utility mention above, I have the choice of XML or JSON. I'm hoping to do a small working prototype of both before we develop the huge app). Then, suppose we have a successful app, and GAE doubles it prices. Then we can rewrite just the data tier, and take our Python/Django user tier (web code), and run it on Amazon or somewhere else.
If I'm going to do all that, why would I want everything to be dictionary objects. Wouldn't I want the power of full-blown class structure? One of the next tricks is sort of an object relational mapping (ORM) so that we don't necessarily expose our exact data tables, but more of a logical layer.
We also want to expose a RESTful API to paying users, who might be using any language. For them, they can use XML or JSON, and they wouldn't use the serialize routine discussed here.
json only encodes strings, floats, integers, javascript objects (python dicts) and lists.
You have to create a function to turn the returned dictionary into a class and then pass it to a json.loads using the object_hook keyword argument along with the json string. Heres some code that fleshes it out:
import json
class Subscriber(object):
firstname = None
lastname = None
class Post(object):
author = None
title = None
def decode_from_dict(cls,vals):
obj = cls()
for key, val in vals.items():
setattr(obj, key, val)
return obj
SERIALIZABLE_CLASSES = {'Subscriber': Subscriber,
'Post': Post}
def decode_object(d):
for field in d:
if field in SERIALIZABLE_CLASSES:
cls = SERIALIZABLE_CLASSES[field]
return decode_from_dict(cls, d[field])
return d
results = '''[{"Subscriber": {"firstname": "Neal", "lastname": "Walters"}},
{"Post": {"author": {"Subscriber": {"firstname": "Neal",
"lastname": "Walters"}}},
"title": "Decoding JSON Objects"}]'''
result = json.loads(results, object_hook=decode_object)
print result
print result[1].author
This will handle any class that can be instantiated without arguments to the constructor and for which setattr will work.
Also, this uses json. I have no experience with simplejson so YMMV but I hear that they are identical.
Note that although the values for the two subscriber objects are identical, the resulting objects are not. This could be fixed by memoizing the decode_from_dict class.
results in your snippet is a dict, not a string, so the json.loads would raise an exception. If that is fixed, each subitem in the inner loop is then a tuple, so trying to add it to a string as you are doing would raise another exception. I guess you've simplified your code, but the two type errors should already show that you simplified it too much (and incorrectly). Why not use an (equally simplified) working snippet, and the actual string you want to json.loads instead of one that can't possibly reproduce your problem? That course of action would make it much easier to help you.
Beyyond peering at the actual string, and showing some obvious information such as type(subscriber), it's hard to offer much more help based on that clearly-broken code and such insufficient information:-(.
Edit: in "update2", the OP says
It displays this: Subscriber: {u'lastname': u'Walters', u'firstname': u'Neal'}
...and what else could it possibly display, pray?! You're printing the key as string, then the value as string -- the key is a string, and the value is another dict, so of course it's "stringified" (and all strings in JSON are Unicode -- just like in C# or Java, and you say you come from a MSFT background, so why does this surprise you at all?!). str(somedict), identically to repr(somedict), shows the repr of keys and values (with braces around it all and colons and commas as appropriate separators).
JSON, a completely language-independent serialization format though originally centered on Javascript, has absolutely no idea of what classes (if any) you expect to see instances of (of course it doesn't, and it's just absurd to think it possibly could: how could it possibly be language-independent if it hard-coded the very concept of "class", a concept which so many languages, including Javascript, don't even have?!) -- so it uses (in Python terms) strings, numbers, lists, and dicts (four very basic data types that any semi-decent modern language can be expected to have, at least in some library if not embedded in the language proper!). When you json.loads a string, you'll always get some nested combination of the four datatypes above (all strings will be unicode and all numbers will be floats, BTW;-).
If you have no idea (and don't want to encode by some arbitrary convention or other) what class's instances are being serialized, but absolutely must have class instances back (not just dicts etc) when you deserialize, JSON per se can't help you -- that metainformation cannot possibly be present in the JSON-serialized string itself.
If you're OK with the four fundamental types, and just want to see some printed results that you consider "prettier" than the default Python string printing of the fundamental types in question, you'll have to code your own recursive pretty-printing function depending on your subjective definition of "pretty" (I doubt you'd like Python's own pprint standard library module any more than you like your current results;-).
My guess is that loads is returning a dictionary. To iterate over its content, use something like:
for key, value in subscriber.items():
self.response.out.write("%s: %s" %(key, value))

Categories