Can't write copy of activity in newly created databases - brightway

I am trying to write a copy of an activity from an existing database (in this case ecoinvent 3.2 cut-off, but that shouldn't matter) into a new database. I have:
In: ei = bw.Database('ecoinvent 3.2 cutoff')
testDB = bw.Database('testdb')
testDB.register()
bw.databases
Out: Brightway2 databases metadata with 3 objects:
biosphere3
ecoinvent 3.2 cutoff
testdb
In: act = ei.random()
actCopy = act.copy()
testDB.write(actCopy)
Out: ---------------------------------------------------------------------------
WrongDatabase Traceback (most recent call last)
<ipython-input-20-831953ab6cb9> in <module>()
----> 1 testdb.write(act)
[...]
WrongDatabase: Can't write activities in databases {'a', 'd', 'u', 'c', 'r', 'n', 'f', 'l', 't', 'p'} to database testdb
What is the meaning of the single letter strings in the set in the error message?
What part of my code makes the writing to my new database break down?

Calling Database('foo').write(data) requires that data is a dictionary, see the technical documentation. In this case, actCopy is an activity proxy, so the easiest solution would be to use actCopy.save(). Alternatively, you could use the following utility function to get a list of activities into the correct form:
def format_me(list_of_activities, database_obj):
return {(database_obj.name, obj['code']): obj for obj in list_of_activities}
The reason you get the error message "Can't write activities in databases {'a', 'd', 'u', 'c', 'r', 'n', 'f', 'l', 't', 'p'} to database testdb" is that you are passing a list, and one of the things the write function does is to make sure that you are not trying to write data to the wrong database. The way it does this is to iterate over the keys in the dictionary data, and take the first element as the database name. It then checks to make sure that these names are same as the database which is being written to. When you passed a data object like this:
{
'alpha': 'something',
'delta': 'something',
'umberto': 'something',
'california': 'something',
...
}
Then, when iterating over the object you passed into data, it would get these database keys, i.e. alpha, delta, etc. It then takes the first element (a, d, etc.) and checks to make sure the database name is correct
Here is the actual bw2data code that raises this error:
wrong_database = {key[0] for key in data}.difference({self.name})
if wrong_database:
raise WrongDatabase("Can't write activities in databases {} to database {}".format(
wrong_database, self.name))

Related

Python, convert dictionary to comma separated values

I need to convert the values in dict to comma separated so I can pass it to a dataclass directly.
I referred to - Link & Link
Code:
d = {'Exch': 'N', 'ExchType': 'C', 'Signal': 1660,
'Price': 207.75, 'date': '/Date(1626690582000)/'}
print(",".join(d.keys()))
print(",".join(d.values()))
But in my case, the keys get printed, but I get an error as below for values (Note: the values in dict are of different data types):
Exch,ExchType,Signal,Price,date
print(",".join(d.values()))
TypeError: sequence item 2: expected str instance, int found
Pardon if this query is elementary, as am quite new to Python.
It's because the value of the Price key is not a string.
To fix it try a list comprehension:
print(",".join([str(i) for i in d.values()]))

Robot framework: Lists should be equal problem with empty values: "None" and ''

So problem here is that I am comparing two lists from different locations. One list is from excel and other list is from particular table which represents the imported values of the same excel values.
So all values are correct; but the excel gives one or possbily more values which are "none" and from the table i get those values only empty value as astrophes ''. How can i change "None" to '' or vice versa?
In this particular case "None" and '' are in the 10th value slot in lists but over time it can change because different values are put to the excel.
So how can I remove or replace/modify these "nones" to '':s or vice versa?
Excel list: [1, 'X', 'Y', 200, 1999, 'Z', 'W', 4, 'V', None, 2, 1100]
Table list: [1, 'X', 'Y', 200, 1999, 'Z', 'W', 4, 'V', '', 2, 1100]
Using ExcelLibrary and ExcelRobot to get the mixture of keywords .. below is the similar approach
${iTotalRows} = Get Row Count Sheet1 (etc.) # excel
${item1} = Get Table cell //table[#class="xx"] 2 1
${item1} = Get Table cell //table[#class="xx"] 2 2 #etc..
Lists should be equal ${x} ${y}
Thank you in advance
I don't think there is a prepared keyword for this (e.g. in Collections library). If I'm wrong and I'm reinventing the wheel, please let me know, I can edit or delete my answer.
I'd create a custom keyword in Python and import it as a library into RF. This could be easily done in Python (one line in fact), so it doesn't even take much time or effort to create it.
Libraries/ListUtils.py:
def substitute_values_in_list(list, value_to_substitute, substitute_to):
return [substitute_to if ele == value_to_substitute else ele for ele in list]
Then in a test or in keywords:
*** Settings ***
Library ../Libraries/ListUtils.py
*** Test Cases ***
Empty List Value
${list}= Create List 1 2 ${None}
Log To Console ${list}
${new_list}= Substitute Values In List ${list} ${None} ${Empty}
Log To Console ${new_list}
The first console output will be:
['1', '2', None]
and the second one with substituted values:
['1', '2', '']
You can parametrize custom keyword Substitute Values In List in another way, so you can substitute empty string for None values or something like that.

How to cast random key with pyautogui?

I am trying to create an AI character to move randomly in game engines for reinforcement learning project. How do I cast (w,a,s,d) keys randomly in a duration ?
def randommove():
UP =pyautogui.keyDown('w')
LEFT =pyautogui.keyDown('a')
DOWN =pyautogui.keyDown('s')
RIGHT=pyautogui.keyDown('d')
You could create a list and then select from it randomly with random.choice() Also I recommend using the press() function rather than keyDown() as the key will be held down until you use keyUp(). You can set x to be the number of times to repeat the function, or use a while loop to do it indefinitely.
def randommove():
x = 10
for i in range(x):
move_keys = ['w', 'a', 's', 'd']
random_move = random.choice(move_keys)
pyautogui.press(random_move)

question about custom sorting using key argument in sorted()

I'm trying to gain some insight in to why I'm receiving an error message.
I'm trying to sort a dictionary using a custom function. I realize I can use lambda to achieve the same goal, as well as sorting the dictionary in to tuples first, but what I'm really trying to do is understand why my function isn't returning a list.
sample_dict = {"a":4,"b":2,"c":7,"d":9}
def all_values(x):
return list(x.values())
print(sorted(sample_dict, key = all_values))
Expecting for return list(x.values()) to return a list to be used in the sorted key argument, but instead, I'm given the error message:
AttributeError: 'str' object has no attribute 'values'
you mean to sort the keys according to the values.
The key function is meant to convert the dictionary key to something comparable (if you omit it, it's like passing an identity function, you're comparing on the dictionary key itself). You want to return the value from the key, so it's a dictionary access:
sample_dict = {"a":4,"b":2,"c":7,"d":9}
def all_values(x):
return sample_dict[x]
print(sorted(sample_dict, key = all_values))
You were expecting the dictionary to be passed in the key, which would have no interest at all. key must be different at each call sort does.
Using a lambda is of course shorter
print(sorted(sample_dict, key = lambda x: sample_dict[x]))
but passing a real function allows to insert side effects more easily:
def all_values(x):
print("key input",x)
return sample_dict[x]
with that you get an insight of what sort is doing (and the final result is printed by the main print statement):
key input b
key input a
key input c
key input d
['b', 'a', 'c', 'd']
and now you understand why list('b'.values()) failed.
I think you've been confused by the way key argument works.
Essentially, it maps a given function over all elements of your iterable, and then sorted sorts based on the outputs of the mapping.
In fact, when you sort sample_dict, you are sorting its keys, which are strings:
sample_dict = {"b":2, "c":7, "d":9, "a":4}
print(sorted(sample_dict))
# ['a', 'b', 'c', 'd']
and if I try to map all_values to this list of strings:
list(map(all_values, sample_dict))
# AttributeError: 'str' object has no attribute 'values'
all_values must get a string in input then, like #Jean-FrançoisFabre suggests:
def all_values(x):
return sample_dict[x]
print(sorted(sample_dict, key = all_values))
# ['b', 'a', 'c', 'd']

Python: casting map object to list makes map object empty?

I have a map object that I want to print as a list but continue using as a map object afterwards. Actually I want to print the length so I cast to list but the issue also happens if I just print the contents as follows:
print("1",my_map)
print("1",list(my_map))
print("2",my_map)
print("2",list(my_map))
and this gives me the following outputs.
1 <map object at 0x7fd2962a75f8>
1 [(1000.0, 1.0, 0.01, 0.01, 0.01, 0.01, 0.01)]
2 <map object at 0x7fd2962a75f8>
2 []
Why is this happening and how can I avoid it to continue using the map and its contents?
A map object is a generator returned from calling the map() built-in function. It is intended to be iterated over (e.g. by passing it to list()) only once, after which it is consumed. Trying to iterate over it a second time will result in an empty sequence.
If you want to save the mapped values to reuse, you'll need to convert the map object to another sequence type, such as a list, and save the result. So change your:
my_map = map(...)
to
my_map = list(map(...))
After that, your code above should work as you expect.
The reason is that the Python 3 map returns an iterator and listing the elements of an iterator "consumes" it and there's no way to "reset" it
my_map = map(str,range(5))
list(my_map)
# Out: ['0', '1', '2', '3', '4']
list(my_map)
# Out: []
If you want to preserve the map object you can use itertools.tee to create a copy of the iterator to be used later
from itertools import tee
my_map, my_map_iter = tee(map(str,range(5)))
list(my_map)
# Out: ['0', '1', '2', '3', '4']
list(my_map)
# Out: []
list(my_map_iter)
# Out: ['0', '1', '2', '3', '4']
I faced the same issue since I am using Python 3.7 version. Using list(map(...)) worked. For lower python version using map(...) would work fine, but for higher versions, map returns an iterator pointing to a memory location. So print(...) statement will give the address rather than the items itself. To get the items try using list(map(...))

Resources