I want to have some simple interfaces for the users to connect some pre-defined modules (I'm free to modify them if I have to).
Each module has a few named inputs and outputs.
One module may connect to a few modules.
A few modules can connect to a single module.
This is what I have in my mind so far:
Option 1:
Each module has "in" and "out" dictionary for input and output, and the connection is made through code like this:
a.out["out 1"].to(b.in["in 1"]) # connect a's "out 1" output to b's "in 1" input
a.out["out 2"].to(b.in["in 2"]) # connect a's "out 2" output to b's "in 2" input
But this looks quite tedious, so I came up with Option 2:
# connect a to b and c, then list which inputs connect to which outputs
a.to(b,{"out 1":"in 1",
"out 2":"in 2"},
c,{"out 4":"in 1",
"out 3":"in 2"})
This seems to look better as it's clearer to me which modules are connected and also the mapping between their outputs and inputs are clearly listed.
I wonder if there is any room to improve the above, to clearly show:
module level connections, e.g. module a connect to module b
outputs and inputs connections
simple and clear interface. By 'simple', I mean less typing; 'clear' means easy to understand. I understand that sometimes I can't have both in that case, 'clear' interface is preferable.
I'm not proficient in Python(2.7) so there might be some syntax or operator or data structure that I am not aware of but I may be able to take advantage for this purpose.
I have run into this exact issue, the issue of being able to clearly describe directed graphs linearly. None are particularly pleasant... Personally, I believe showing how the sources and sinks (node inputs and outputs) connect is more important than showing which nodes are connected, because the relationship is more specific.
Of the two designs you listed I would recommend the first, since it is clearer. It shows exactly how each input and output connects. However, I would slightly augment your implementation. I would make the node class capable of creating new handles for inputs and outputs that are actual attributes in the object. Then use those handles when describing the graph and capturing traffic, etc. Making the inputs and outputs actual objects instead of labels means construction-time checking and the ability to generate better error messages. For example:
b = Node()
b.input("in1", "in2") # this creates a new input object that is located in 'b' with the attribute name of the given string
b.output("out1") # this could be in the constructor
c = Node(in=["in1", "in2"], out=["out1"]) # like so
# describe the connections
a.out1.to(b.in1)
a.out2.to(b.in2)
a.out3.to(c.in2)
a.out4.to(c.in1)
# maybe syntax like 'a.out3 >> c.in2' would be prettier?
module_graph_output = c.out1.capture()
# do stuff with the graph output
Additionally, the module definitions can be passed these output and input object handlers for the user as they implement the module logic.
All this aside, how you are going to run the module graph is the bigger issue. If I'm not intruding, what is the application of this?
Related
I using the following action to generate ambient occlusion maps for models in maya:
Create and assign aiAmbientOcclusion to my model (the one I want to generate oa maps for).
Then, I go Arnold>Utilities>Render Selection To Texture.
Since this process is always the same I want to write a python script to automate it unfortunately I haven't found many useful examples about writing scripts for Arnold.
To add this functionality I must:
import mtoa.renderToTexture
that script is located in
the_way_to_my_install_folder/solidangle/mtoa/2017/scripts/mtoa
I saw that the script defines the class MtoARenderToTexture and I should pass an object to it. Now.
What kind of object I mush use and is there some sort of documentation for MtoARenderToTexture class?
I was able to do what I wanted using ether this tutorial and extending MtoARenderToTexture class.
I do not iclude all my scripts that load scene and manage scenes files as they very specific to my needs, but still think it's a good idea to share some very basic and fundamental elements that may be useful for some new entries as myself.
This is how my extended class looks like
import mtoa.renderToTexture as renderToTexture
import maya.cmds as cmds
class rkMtoaRtoT(renderToTexture.MtoARenderToTexture):
def __init__(self):
renderToTexture.MtoARenderToTexture.__init__(self)
self.dFolder = '~'
self.dResolution = 1024
self.dCameraSamples = 5
def doAutomaticExport(self):
renderToTexture.MtoARenderToTexture.create(self)
cmds.textFieldButtonGrp('outputFolder', e=True, tx=self.dFolder)
cmds.intFieldGrp('resolution', e=True, v1=self.dResolution)
cmds.intFieldGrp('aa_samples', e=True, v1=self.dCameraSamples)
renderToTexture.MtoARenderToTexture.doExport(self)
tl;dr in bold below
I'm currently developing a text-based adventure game, and I've implemented a basic saving system.
The process takes advantage of the 'pickle' module. It generates or appends to a file with a custom extension (when it is, in reality, a text file).
The engine pickles the player's location, their inventory, and, well, the last part is where it gets a little weird.
The game loads dialog from a specially formatted script (Here I mean as in an actor's script). Some dialog changes based on certain conditions (already spoken to them before, new event, etc.). So, for that third object the engine saves, it saves ALL dialog trees in their current positions. As in, it saves the literal script in its current state.
Here is the saving routine:
with open('save.devl','wb') as file:
pickle.dump((current_pos,player_inv,dia_dict),file)
for room in save_map:
pickle.dump(room,file)
file.close()
My problem is, this process makes a very ugly, very verbose, super large text file. Now I know that text files are basically the smallest files I can generate, but I was wondering if there was any way to compress or otherwise make more efficient the process of recording the state of everything in the game. Or, less preferably but better in the long run, just a smarter way to save the player's data.
The format of dialog was requested. Here is a sample:
[Isaac]
a: Hello.|1. I'm Evan.|b|
b: Nice to meet you.|1. Where are you going?\2.Goodbye.|c,closer|
c: My cousin's wedding.|1. Interesting. Where are you from?\2. What do you know about the ship?\3. Goodbye.|e,closer|
closer: See you later.||break|
e: It's the WPT Magnus. Cruise-class zeppelin. Been in service for about three years, I believe.||c|
standing: Hello, again.|1. What do you know about the ship?\2.Goodbye.|e,closer|
The name in brackets is how the program identifies which tree to call. Each letter is a separate branch in the tree. The bars separate the branch into three parts: 1. What the character says 2. The responses you are allowed 3. Where each response goes, or if the player doesn't respond, where the player is directed afterwards.
In this example, after the player has talked to Isaac, the 'a' branch is erased from the copy of the tree that the game stores in memory. It then permanently uses the 'standing' branch.
Pickle itself has other protocols that are all more compact than the default protocol (protocol 0) - which is the only one "text based" - the others are binary protocols.
But them, you hardly would get more than 50% of the file size - to be able to enhance the answer, we need to know better what you are saving, and if there are smarter ways to save your data - for example, by avoiding repeating the same sub-data structure if it is present in several of your rooms. (Although if you are using object identity inside your game, Pickle should take care of that).
That said, just change your pickle.dump calls to include the protocol parameter - the -1 value is equivalent to "HIGHEST_PROTOCOL", which is usually the most efficient:
pickle.dump(room,file, protocol=-1)
(loading the pickles do not require that the protocol is passed at all)
Aditionally, you might want to use Python's zlib interface to compress pickle data. That could give you another 20-30% file size reduction - you have to chain the calls to file.write, zlib.compress and pickle.dumps, so you will be easier with a little helper code - also you need to control file offsets, as zlib is not like pickle which advances the file pointer:
import pickle, zlib
def store_obj(file_, obj):
compressed = zlib.compress(pickle.dumps(obj, protocol=-1), level=9)
file_.write(len(compressed).to_bytes(4, "little"))
file_.write(compressed)
def get_obj(file_):
obj_size = int.from_bytes(file_.read(4), "little")
if obj_size == 0:
return None
data = zlib.decompress(self.file_.read(obj_size))
return pickle.loads(data)
I'm writing something for a game that involves networks. In this game, a network is a class and the "connections" to each node are formatted like:
network.nodes = [router, computer1, computer2]
network.connections = [ [1, 2], [0], [0] ]
Each iteration in "network.nodes" works in parallel with each iteration in "network.connections", meaning "network.connections[0]" represents all the nodes "network.nodes[0]" is connected to. I'm trying to write a simple function in the network class that finds a route starting from the router - "network.connections[0]" - and then to a specific "node". The more thought I put into this, the more complicated the answer seems to be.
In this, rather simple case it should return something like
[router, computer1]
That's what I'd like to see if I was trying to find a route to "computer1", but I need something that will work with more complicated network simulations.
It's basically a simulator for a computer network. But in this game, I need to be able to know exactly which nodes something might travel though to reach a specific target.
Any help would be greatly appreciated. Thanks.
How about dropping the .nodes and .connections and just keeping them in one data structure like a dictionary.
network.nodes = {"router": [computer1, computer2],
"computer1": [router],
"computer2": [router]
}
You could even drop the strings as keys and use the objects themselves:
network.nodes = {router: [computer1, computer2],
computer1: [router],
computer2: [router]
}
That way if you need to access the the connections for the router you would do:
>>>network.nodes[router]
[computer1, computer2]
Because I don't have a full overview of your project, I can't just give you a function to do that, but I can try and point you in the right direction.
If you build the network 'map' up as a dictionary, and network.nodes[router] returns [computer1, computer2], the next thing you would need to do is network.nodes[computer1] and network.nodes[computer2].
In your firewall example from the comments, you would rebuild the network map to include the firewall. So the dictionary would look like this:
network.nodes = {router: [firewall, computer2],
firewall: [computer1]
computer1: [firewall],
computer2: [router]
}
I use a Raspberry Pi to collect sensor data and set digital outputs, to make it easy for other applications to set and get values I'm using a socket server. But I am having some problems finding an elegant way of making all the data available on the socket server without having to write a function for each data type.
Some examples of values and methods I have that I would like to make available on the socket server:
do[2].set_low() # set digital output 2 low
do[2].value=0 # set digital output 2 low
do[2].toggle() # toggle digital output 2
di[0].value # read value for digital input 0
ai[0].value # read value for analog input 0
ai[0].average # get the average calculated value for analog input 0
ao[4].value=255 # set analog output 4 to byte value 255
ao[4].percent=100 # set analog output 4 to 100%
I've tried eval() and exec():
self.request.sendall(str.encode(str(eval('item.' + recv_string)) + '\n'))
eval() works unless I am using equal sign (=), but I'm not to happy about the solution because of dangers involved. exec() does the work but does not return any value, also dangerous.
I've also tried getattr():
recv_string = bytes.decode(self.data).lower().split(';')
values = getattr(item, recv_string[0])
self.request.sendall(str.encode(str(values[int(recv_string[1])].value) + '\n'))
^^^^^
This works for getting my attributes, and the above example works for getting the value of the attribute I am getting with getattr(). But I can not figure out how to use getattr() on the value attribute as well.
The semi-colon (;) is used to split the incoming command, I've experimented with multiple ways of formatting the commands:
# unit means that I want to talk to a I/O interface module,
# and the name specified which one
unit;unit_name;get;do;1
unit;unit_name;get;do[1]
unit;unit_name;do[1].value
I am free to choose the format since I am also writing the software that uses these commands. I have not yet found a good format which covers all my needs.
Any suggestions how I can write an elegant way of accessing and returning the data above? Preferably with having to add new methods to the socket server every time a new value type or method is added to my I/O ports.
Edit: This is not public, it's only available on my LAN.
Suggestions
Make your API all methods so that eval can always be used:
def value_m(self, newValue=None):
if newValue is not None:
self.value = newValue
return self.value
Then you can always do
result = str(eval(message))
self.request.sendall(str.encode(result + '\n'))
For your message, I would suggest that your messages are formatted to include the exact syntax of the command exactly so that it can be evaled as-is, e.g.
message = 'do[1].value_m()' # read a value, alternatively...
message = 'do[1].value_m(None)'
or to write
message = 'do[1].value_m(0)' # write a value
This will make it easy to keep your messages up-to-date with your API, because they must match exactly, you won't have a second DSL to deal with. You really don't want to have to maintain a second API, on top of your IO one.
This is a very simple scheme, suitable for a home project. I would suggest some error handling in evaluation, like so:
import traceback
try:
result = str(eval(message))
except Exception:
result = traceback.format_exc()
self.request.sendall(str.encode(result + '\n'))
This way your caller will receive a printout of the exception traceback in the returned message. This will make it much, much easier to debug bad calls.
NOTE If this is public-facing, you cannot do this. All input must be sanitised. You will have to parse each instruction and compare it to the list of available (and desirable) commands, and verify input validity and validity ranges for everything. For such a scenario you are better off simply using one of the input validation systems used for web services, where this problem receives a great deal of attention.
I'm having a little bit of trouble assigning values to a QLineEdit. I've read the documentation and feel that the QLineEdit.SetText() command will be used at some point.
I've used Qt Designer to design a GUI for my software. On the main window (MainWindow.py, with an accompanying ui_MainWindow.py setup file), I have a LineEdit (lineEditScanBarcode) which has strong focus. I've managed to pull input from that LineEdit pretty well. What I'd like to do is this:
If the input in LineEditScanBarcode = x, then assign the name 'John Smith' to a secondary QLineEdit (lineEditUser) which has a zero focus policy. This is what I have so far:
def ScanBarcode(self):
barcode = self.lineEditScanBarcode.text()
self.lineEditScanBarcode.clear()
if barcode == '12345':
print("Welcome John")
self.lineEditUser.setText() = 'John'
else: print("Sorry, user not recognised.")
Upon running this, I get the following error:
Syntax Error: can't assign to function call
I've had a look at the above error, but I'm still unsure as to what's going on here. I still have no idea to open one window on top of another (this software package will have about 10 windows), but that's another story!
Is my logic here on track? I've never used Qt before, so my understanding of the intricacies involved is lacking to say the least.
Any input would be great!
As the comment states, the error is on this line:
self.lineEditUser.setText() = 'John'
You are attempting to assign the value 'John' to that functioncall (as the error states). If you review the documentation for QLineEdit in PyQT, you'll see that QLineEdit.setText() requires a string to be passed to it.
So, what you need to do instead is pass the value 'John' to the function like so:
self.lineEditUser.setText('John')
On another note your idea that your
software package will have about 10 windows
is definitely something that you want to reexamine. More windows, especially when undocked and floating independently will no doubt cause usability issues. I'd strongly recommend sharing your ideas over at UserExperience.SE.