How to put values from dictionary to variable - python

I try to get all values from section in my ini file (via configparser) as a variable:
hue310section = dict(parser.items('HUE_310'))
for keys, value in hue310section.items():
pairs = keys + ' = ' + value
print(pairs)
it gave me partnewfilepath = http://some_site:PORT/about, but I don't know how to import this output as an python variable, that I can use partnewfilepath somewhere in my code. Of course one section will have more values than only one, and I want to change all that in variable. I trying to find solution but I think I miss something because my knowledge about python is not enough yet. I think I need to rebuilt my for statement but don't have a clue how to do it in this particular problem.
My config.ini file looks like:
[HUE_310]
partNewFilePath = ${common:domain}/about
otherValues = something
nextvalue = another something
UPDATE:
I think I need to elaborate more about what I want to achieve. In other part of my code I check version of site I want to process. If the site has, let say version 3.10 I want to get all values from section HUE_310 from my ini file, and use them as python variable. Rest of my code use those variable and if the site version will change I can get values from other section from my ini file and get those values to python variable and use them. I assume that some variables will change from version to version and that's why I want to prepare my code to check this. Also it gives me some freedom to modify some variable if site will change.
I hope it is now more clear.

You don't need a new variable or a for loop, you already have hue310section dict.
You can just use
hue310section['partNewFilePath']
which will be equal to
"http://some_site:PORT/about"
Note that after hue310section = dict(parser.items('HUE_310'))
, otherValues and nextvalue keys will also be defined.

from configobj import ConfigObj
parser_data = ConfigObj(config_path)
current = parser_data['HUE_310'].get('partNewFilePath', 'http://www.default.com')
config_path is path to the file
http://www.default.com is the default value in case that particular key is not found.

Related

Dynamo Revit set formula for a parameter in a family

I am trying to add a formula to a parameter within a Revit Family.
Currently I have multiple families in a project. I run Dynamo from within that project then I extract the families that I want to modify using Dynamo standard nodes.
Then I use a python script node that goes through every selected family and find the parameter I am interested in, and assign a formula for it.
That seemed fine until I noticed that it is not assigning the formula, but it is entering it as a string — as in it is in quotes. And sure enough, the code i am using will only work with Text type parameters.
Can someone shed the light on how to assign a formula to a parameter using dynamo?
see line 32 in code below
Thanks
for family in families:
TransactionManager.Instance.ForceCloseTransaction()
famdoc = doc.EditFamily(family)
FamilyMan = famdoc.FamilyManager
found.append(family.Name)
TransactionManager.Instance.EnsureInTransaction(famdoc)
check = 0
# Loop thru the list of parameters to assign formula values to them... these are given as imput
for r in range(len(param_name_lst)):
# Loop thru the list of parameters in the current family per the families outter loop above.
for param in FamilyMan.Parameters:
#for param in FamilyMan.get_Parameter(param_name_lst[r]):
# for each of the parameters get their name and store in paramName.
paramName = param.Definition.Name
# Check if we have a match in parameter name.
if param_name_lst[r] in paramName:
if param.CanAssignFormula:
canassignformula.append(param_name_lst[r])
else:
cannotassignformula.append(param_name_lst[r])
try:
# Make sure that the parameter is not locked.
if FamilyMan.IsParameterLocked(param):
FamilyMan.SetParameterLocked(param,False)
locked.append(paraName)
# Enter formula value to parameter.
FamilyMan.SetFormula(param, param_value_lst[r])
check += 1
except:
failed.append(paramName)
else:
continue
Actually, you can access the family from the main project, and you can assign a formula automatically.... That's what i currently do, i load all the families i want in one project and run the script.
After a lot of work, i was able to figure out what i was doing wrong, and in it is not in my code... my code was fine.
The main problem is that i need to have all of my formula's dependencies lined up.... just like in manual mode.
so if my formula is:
size_lookup(MY_ID_tbl, "MY_VAR", "MY_DefaultValue", ND1,ND2)
then i need to have the following:
MY_ID_tbl should exist and be assigned a valid value, in this case it should have a csv filename. Moreover, that file should be also loaded. This is important for the next steps.
MY_VAR should be defined in that csv file, so Does ND1, ND2
The default value (My_Default_Value) should match what that csv file says about that variable...in this case, it is a text.
Needless to say, i did not have all of the above lined up as it should be, once i fixed that, my setFormula code did its job. And i had to change my process altogether, cause i have to first create the MY_ID_tbl and load the csv file which i also do using dynamo, then i go and enter the formulas using dynamo.
Revit parameters can only be assigned to a formula inside the family editor only, that is the first point, so you should run your dynamo script inside the family editor for each family which will be a waste of time and you just edit the parameter's formula manually inside each family.
and the second point, I don't even think that it is possible to set a certain parameter's formula automatically, it must be done manually ( I haven't seen anything for it in the Revit API docs).

Can I use asterisk * in config file variable name?

I am using Config Parser to specify a list of variables, and the values for those variables are then pulled from a larger file. The variables/lines in the larger file all look like this:
callCount.1.cell=2
callCount.2.cell=10
callCount.3.cell=12
Rather than listing all these variables specifically, would I be able to use an '*' as a wildcard character, in place of the number, like this:
[variablesToPull]
callCount.*.cell
I can't change the formatting of the larger file I'm pulling values from, and I don't always know what the numbers that are apart of the variables will be.
EDIT: I'm using Python 2.7 to do all my Config Parsing
After looking around for a while I don't think it's possible. I ended up using just the first part of the desired variable name in the config file
[variablesToPull]
callCount
Then I created a dictionary from the file I was storing the full list of variable names and values in (All the following code is for Python 2.7, it probably works for Python 3, but might need some syntax changes)
f = open(variable_names_and_values_file, 'r')
dict_of_vars= {}
for line in f:
k, v = line.strip().split('=')
dict_of_vars[k.strip()] = v.strip()
f.close()
Then I looped over this dictionary and created a new list of the specific variables to pull (like callCount.1.cell, callCount.2.cell, ect...)
new_variables= []
for var in partial_variable_names_from_config_file:
for data in dict_of_vars:
if var in data:
new_variables.append(data)
Initially I didn't want to do so much looping for fear of performance decrease (my file of variables has like 10000 lines), but it doesn't seem to have slowed down my script by a noticeable amount.
Hope this helps someone out there

gitpython to check for if there are any changes in files using PYTHON

I am experimenting with gitpython and I am new to it. I am trying to detect if there are any changes staged for commit.
Currently, I have a function that looks like this:
def commit(dir):
r = Repo(dir)
r.git.add(A=True)
r.git.commit(m='commit all')
But this is just the code to commit the directory. I wanna do something like, if there are changes, then display some message, else, display another message.
Anybody have any idea how do I do it in python ?
You can check for all unstaged changes like this:
for x in r.index.diff("HEAD"):
# Just print
print(x)
# Or for each entry you can find out information about it, e.g.
print(x.new_file)
print(x.b_path)
Basically you are comparing the staging area (i.e. index) to the active branch.
To get a definitive list of what's changed (but not yet staged):
# Gives a list of the differing objects
diff_list = repo.head.commit.diff()
for diff in diff_list:
print(diff.change_type) # Gives the change type. eg. 'A': added, 'M': modified etc.
# Returns true if it is a new file
print(diff.new_file)
# Print the old file path
print(diff.a_path)
# Print the new file path. If the filename (or path) was changed it will differ
print(diff.b_path)
# Too many options to show. This gives a comprehensive description of what is available
help(diff_list[0])
I found the diff object to be very useful and should give any info you require.
For staged items, use repo.index
From my testing, I found that the previous answer gave a diff output the wrong way round (ie. added files would show up as deleted).
The other option is repo.git.diff(...) which I found less useful as it gives long text strings for output rather than objects that can be easily parsed.

Python Environment variable within environment variable

I'm trying to set up an environment variable via Python:
os.environ["myRoot"]="/home/myName"
os.environ["subDir"]="$myRoot/subDir"
I expect the subDir environment variable to hold /home/myname/subDir, however it holds the string '$myRoot/subDir'. How do I get this functionality?
(Bigger picture : I'm reading a json file of environment variables and the ones lower down reference the ones higher up)
Use os.environ to fetch the value, and os.path to correctly put slashes in the right places:
os.environ["myRoot"]="/home/myName"
os.environ["subDir"] = os.path.join(os.environ['myRoot'], "subDir")
You can use os.path.expandvars to expand environment variables like so:
>>> import os
>>> print os.path.expandvars("My home directory is $HOME")
My home director is /home/Majaha
>>>
For your example, you might do:
os.environ["myRoot"] = "/home/myName"
os.environ["subDir"] = os.path.expandvars("$myRoot/subDir")
I think #johntellsall's answer is the better for the specific example you gave, however I don't doubt you'll find this useful for your json work.
Edit: I would now recommend using #johntellsall's answer, as os.path.expandvars() is designed explicitly for use with paths, so using it for arbitrary strings may work but is kinda hacky.
def fix_text(txt,data):
'''txt is the string to fix, data is the dictionary with the variable names/values'''
def fixer(m): #takes a regex match
match = m.groups()[0] #since theres only one thats all we worry about
#return a replacement or the variable name if its not in the dictionary
return data.get(match,"$%s"%match)
return re.sub("$([a-zA-Z]+)",fixer,txt) #regular expression to match a "$" followed by 1 or more letters
with open("some.json") as f: #open the json file to read
file_text= f.read()
data = json.loads(file_text) #load it into a json object
#try to ensure you evaluate them in the order you found them
keys = sorted(data.keys() ,key=file_text.index)
#create a new dictionary by mapping our ordered keys above to "fixed" strings that support simple variables
data2= dict(map(lambda k:(k,fixer(data[k],data)),keys)
#sanity check
print data2
[edited to fix a typo that would cause it not to work]

Using Strings to Name Hash Keys?

I'm working through a book called "Head First Programming," and there's a particular part where I'm confused as to why they're doing this.
There doesn't appear to be any reasoning for it, nor any explanation anywhere in the text.
The issue in question is in using multiple-assignment to assign split data from a string into a hash (which doesn't make sense as to why they're using a hash, if you ask me, but that's a separate issue). Here's the example code:
line = "101;Johnny 'wave-boy' Jones;USA;8.32;Fish;21"
s = {}
(s['id'], s['name'], s['country'], s['average'], s['board'], s['age']) = line.split(";")
I understand that this will take the string line and split it up into each named part, but I don't understand why what I think are keys are being named by using a string, when just a few pages prior, they were named like any other variable, without single quotes.
The purpose of the individual parts is to be searched based on an individual element and then printed on screen. For example, being able to search by ID number and then return the entire thing.
The language in question is Python, if that makes any difference. This is rather confusing for me, since I'm trying to learn this stuff on my own.
My personal best guess is that it doesn't make any difference and that it was personal preference on part of the authors, but it bewilders me that they would suddenly change form like that without it having any meaning, and further bothers me that they don't explain it.
EDIT: So I tried printing the id key both with and without single quotes around the name, and it worked perfectly fine, either way. Therefore, I'd have to assume it's a matter of personal preference, but I still would like some info from someone who actually knows what they're doing as to whether it actually makes a difference, in the long run.
EDIT 2: Apparently, it doesn't make any sense as to how my Python interpreter is actually working with what I've given it, so I made a screen capture of it working https://www.youtube.com/watch?v=52GQJEeSwUA
I don't understand why what I think are keys are being named by using a string, when just a few pages prior, they were named like any other variable, without single quotes
The answer is right there. If there's no quote, mydict[s], then s is a variable, and you look up the key in the dict based on what the value of s is.
If it's a string, then you look up literally that key.
So, in your example s[name] won't work as that would try to access the variable name, which is probably not set.
EDIT: So I tried printing the id key both with and without single
quotes around the name, and it worked perfectly fine, either way.
That's just pure luck... There's a built-in function called id:
>>> id
<built-in function id>
Try another name, and you'll see that it won't work.
Actually, as it turns out, for dictionaries (Python's term for hashes) there is a semantic difference between having the quotes there and not.
For example:
s = {}
s['test'] = 1
s['othertest'] = 2
defines a dictionary called s with two keys, 'test' and 'othertest.' However, if I tried to do this instead:
s = {}
s[test] = 1
I'd get a NameError exception, because this would be looking for an undefined variable called test whose value would be used as the key.
If, then, I were to type this into the Python interpreter:
>>> s = {}
>>> s['test'] = 1
>>> s['othertest'] = 2
>>> test = 'othertest'
>>> print s[test]
2
>>> print s['test']
1
you'll see that using test as a key with no quotes uses the value of that variable to look up the associated entry in the dictionary s.
Edit: Now, the REALLY interesting question is why using s[id] gave you what you expected. The keyword "id" is actually a built-in function in Python that gives you a unique id for an object passed as its argument. What in the world the Python interpreter is doing with the expression s[id] is a total mystery to me.
Edit 2: Watching the OP's Youtube video, it's clear that he's staying consistent when assigning and reading the hash about using id or 'id', so there's no issue with the function id as a hash key somehow magically lining up with 'id' as a hash key. That had me kind of worried for a while.

Categories