31 Mar, 2011, Nich wrote in the 1st comment:
Votes: 0
I debated putting this in java rather then python. I'm using jython to use python as a scripting language for my MUD server which is primarily java (although I'm trying to limit java to being a database/network layer, with anything MUD specific like commands implemented in python). The singletons themselves are written in java, but they're used primarily in python.

At the moment, for proof of concept testing purposes, my data layer is connected to a mock "database" which is composed mainly of arrays and hashes, and doesn't actually persist. This layer is implemented through singleton "stores", one for each type of data. (So there is an account store, a room store, a clientdata store… etc.). These stores are accessed statically through a GlobalData class where required.

For example, my "say" command, written in python, grabs the room store and the client store, and sends a message to each client in the room where the command was executed.
Commands dealing with objects get the object store, etc.

Now, obviously this isn't great. For starters, if I want to test my commands, I either need to a) prepare a set of GlobalData for each test, and set is up so I can measure the pre/post conditions of that data, or b) Test as though I were the client, which has timing issues. Both testing methods are slow and buggy. The first requires that I set up a test world in it's entirety, and reset it between tests. The second *also* requires that I do that, but adds the issue of dropped packets as a means for failure. Currently, my object creation/pickup/drop tests pass the first time they're run, but fail the second time if the server isn't restarted in between trials.

What I want to do is pass the required information from my commands into my commands. That's where I hit a snag, since python is dynamically typed. In Java, I could simply declare my command to require the objects it needs, but from Java looking at python, there's no way of knowing what types python expects to be passed in.

I was thinking of giving the Command classes a static "requires" list, which Java will read, and the command factory will attempt to supply. The python class can then just have *args as a parameter, and I can expect that args[0] will correspond to requires[0], etc. , or else throw an exception from the factory if a command is looking for data that doesn't exist. Is this an intuitive way of solving the problem, or are there better ways?

If it helps, you can pretend this is pure python, since I don't think the problem goes away. How does a class tell another class in python that it will fail if not given sufficient data? Does that just not happen? I have a feeling I'm actually trying to hammer a screw here, so if there's a more "pythony" way of dealing with the problem, I'd be happy to hear that too.
31 Mar, 2011, David Haley wrote in the 2nd comment:
Votes: 0
It seems a little backwards to me to be modifying your method signatures just for a testing framework to avoid creating dummy data sets. Surely it is not that hard to create dummy/clean-slate data stores for your tests?

And yes, you are sort of trying to "hammer a screw" here to some extent… you can do introspection to find out how many parameters a function takes but part of the point of dynamic typing is to not specify types precisely.

If you really want to do this, I would treat commands as data, not modify the signature:

my_cmd = {
'name': 'say',
'code': ref_to_say_func,
params = [
{'name': 'text', 'type': str},
{'name': 'target', 'type': actor, 'optional': True},
# etc.
]
}


Really though, I would avoid driving the design of your classes based on convenience of testing. Do what makes sense for the code, and then test it.
31 Mar, 2011, Nich wrote in the 3rd comment:
Votes: 0
Your example (and especially that params dictionary) is almost exactly what I'm talking about. Except that I would keep it in a class, since that more or less serves the same function (Actually, I think the way python classes are implemented, it's *exactly* the same thing, just written differently). Your example has neat properties, though, in that it can be trivially serialized. It's not obvious, though, where the juicy bit, "ref_to_say_func", should be defined, if we're loading commands from XML, say.

The problem I have right now is that my dummy data needs to be fairly comprehensive, even if most of the stores are null, just because commands can request any kind of data inline. At the very least, I need to make/clear my globalStore class for every test, since that's the way the commands get the data. It's more intuitive, I think, if instead of making/clearing globalStore with the data I need for the test, I just pass the data I need for the test. For example, currently to properly test object creation, I need a globaldata instance, a roomstore instance, a room instance, a client store instance, and a client instance, a an object store instance, and an object instance. Really, though, I should only need a Client, Room, and Object instance. The client to observe the object, the room to contain the object, and the object to be an object. And for the purposes of the test, the client needn't connect through the server, and the room needn't have exits.

Yo're right, though. Testing shouldn't be my primary concern. It's still a large concern (this MUD server is getting too big to feasibly test in a non-automated way), but it still has to work, and shouldn't be kludgy to deal with.
31 Mar, 2011, Idealiad wrote in the 4th comment:
Votes: 0
Forget your Store classes at this point, keep everything in lists (one for each type) and iterate over the list as needed. If necessary keep a global hash of instances keyed to their id. I feel like your abstractions aren't helping you right now, and it won't be a big deal to add them in the future.
31 Mar, 2011, chrisd wrote in the 5th comment:
Votes: 0
If you want a Pythonic approach you should be passing the command function what it needs and checking that it works when the data is valid. A concern here is that if the data is invalid the function may do something undefined rather than failing as it should. My approach to this problem is that if the function is being passed invalid parameters then it's the code calling that function that is buggy, not the function itself.

Here's how I want to write a command function in Python:

@command("say", "text [player]")
def cmd_say(player, text, target=None):
if target is not None:
first_person = "You say to %s, \"%s\"" % (target.name, text)
third_person = "%s says to %s, \"%s\"" % (player.name, target.name, text)
else:
first_person = "You say, \"%s\"" % text
third_person = "%s says, \"%s\"" % (player.name, text)

player.send(first_person)
for p in player.room.players:
if p is player:
continue
p.send(third_person)


Firstly, I'm using a decorator to register the command function and its parsing details rather than having a big dictionary of commands somewhere. Build that dictionary at runtime.

Secondly, relevant data is accessible as attributes on the objects passed to the command function. Why pass a room object to the command function when you can grab the player's current room off the player object? Similarly, why manually fetch each client in a room from a store when you could have an iterator (room.players) do that work for you? The fetch-from-store code is in far fewer places then, which is a plus as well.
31 Mar, 2011, Nich wrote in the 6th comment:
Votes: 0
Nah, the abstractions are definitely required. Since the lists and hashs are a stand-in for a proper database, I want the interface to be the same when I actually substitute them for a database. If I remove the layer of abstraction, first I'll have to go through all my code and change it to direct access, and then when I want to add the database again, I'll have to revert all those changes :).

Just for the record, I've decided to go with somewhat of a hybrid approach. Global data is going to be pretty unavoidable here, I think, since some commands inherently change the state of the world (that being the whole point). What I've decided to do is have commands declare the params they expect (similar to David Haley's example), and have my command factory pull the data from the global store and hand it to the command. That way I can break off my commands to test them in isolation. However, since I still have the global data store, I can still call on that when I need to do something weird. I'm insulated from Global data problems most of the time, unless I explicitly bring them into the code. I think that this is the best compromise.

Edit:
I really need to look into that decorator thing, and see if it can be accessed from Java. It's almost exactly what I need.
And yeah, I noticed that the commands all seemed to revolve around the player. For most commands, I think it'll suffice just to pass a reference to the calling player and leave it at that. But I can think of some (really, really niche) situations where the command would require more information then that. Although those situations are mostly ones that I wouldn't have many qualms about reaching directly into the data store… hmm.
01 Apr, 2011, David Haley wrote in the 7th comment:
Votes: 0
Sorry, I unfortunately do not have time to write a full reply right now as I'm in the middle of traveling. But I wanted to address these two:

Nich said:
It's not obvious, though, where the juicy bit, "ref_to_say_func", should be defined, if we're loading commands from XML, say.

That's a very good question… there are at least two ways you could address this:
1- have a function that maps command names to function references. This function would be defined in a place that has access to the function refs, one way or another.
2- given a name, use introspection to look up that function name in a list of known places to look for commands. For example, if you know that some module has registered itself as a place where command functions live, you can look up the function "say" in that module's namespace and see if you find it.

Nich said:
I really need to look into that decorator thing, and see if it can be accessed from Java.

Probably not – decorators in Python are function wrappers, rather than data like in Java. Java decorators are indeed data tags added to the function. But Python decorators are functions that take functions and return new functions.

But, the decorator – if you are implementing it – can add attributes to the function object.

E.g.,

@my_decorator("yay"):
def foo():
return yay

if my_decorator is a function that takes a function and returns the same function with the parameter set as an attribute, then you have essentially added data rather than just wrapping a function.
01 Apr, 2011, Nich wrote in the 8th comment:
Votes: 0
Ah, I see, the @command flag is actively registering the function as a command. That's not how I'm doing it (I'm dynamically loading the modules the commands are in), but that looks like it would save me some headache.
02 Apr, 2011, David Haley wrote in the 9th comment:
Votes: 0
Well, technically,

@decorator
def x(a,b,c):
# bla


is:

def temp_func(a,b,c):
# bla
x = decorator(temp_func)


I'm not sure if that's what you meant by "registering" it, but decorators in Python are essentially function wrappers, whereas in Java they are data attached to functions. A Python decorator takes a function (and potentially more) as an argument, and returns another function.
02 Apr, 2011, Nich wrote in the 10th comment:
Votes: 0
No, I meant specifically for chrisd's example, he would have implemented the decorator to register his commands for him. Since I didn't know that the decorator was a function, I didn't know that that's what he was doing.

I'm strongly considering re-writing my command code to work like that. It would appear to solve some of the headaches I'm experiencing.
02 Apr, 2011, David Haley wrote in the 11th comment:
Votes: 0
Oh, sorry, yes. If you wanted to, you could do something like what I described – represent commands as data – using a decorator rather than a dict object. You'd pass in command attributes to the decorator, and it would (a) register the command, (b) set up the data representation, © possibly tag the function itself with the relevant semantic information.
02 Apr, 2011, Nich wrote in the 12th comment:
Votes: 0
I'm not sure what the benefit of decoupling the command data with the command function would be? In a compiled language, I can see the draw, since it would enable certain changes to the command without recompiling/restarting the server, but since my commands are in python, I can reload my commands on the fly anyways. In your example, there isn't much you could change in the data that wouldn't require a corresponding change in the function. But possibly I'm just misunderstanding.

Unless it's decoupling the logic from the presentation, but that's not what your example was doing. I could see that being interesting, though. You could take common command patterns like "display X to me and Y to everyone else in the room", and inject client specific messages for X and Y. That might be overcomplicated, though. For sanity purposes, it might be best if each command were wholly described in one location.
02 Apr, 2011, David Haley wrote in the 13th comment:
Votes: 0
Reloading modules is tricky, and there are all kinds of subtleties. If you reload a command module, any references to symbols in that module will refer to the old module. And of course, those things referred to will internally refer to the old module. If you update symbols to refer to the new module, other symbols referring to the now-updated reference won't be updated. Basically, reloading modules dynamically is rather tricky. Of course it's possible, with care, but it's not something you should think is a trivial solution to the problem.

One advantage to describing the command separately is that it's easier to swap implementations while leaving everything else intact. Also, and again I really apologize for having to be brief, it is generally better in the long run to have data rather than code describing how things work.
02 Apr, 2011, Runter wrote in the 14th comment:
Votes: 0
If your modules are encapsulated enough reloading them is less of an issue. And less likely to become an issue in the future, but that type of design isn't typical for MUDs and most people don't assume modules will be reloaded, or are going to heed the subtleties required to modify/reuse that code later. In a lot of paradigms it's safe to reload stuff because everything that is being ran per request is being reloaded each time, anyways. (Typically you'd do this in pre-production and have it turned off in production.) Well, but, that's not typical for MUDs either.
02 Apr, 2011, Nich wrote in the 15th comment:
Votes: 0
I don't think that random references to my commands will be an issue. I'm making encapsulation a priority (Hence the topic title :)). The only module that should be accessing my commands is the one that fetches the commands that a client requests. If reloading isn't working because of that, then I have one clear point where I need to make it work (And it will be pretty obvious any time I try to modify a command without restarting the server).

The command shouldn't be in memory when it's not running anyways. And if the command takes time to run, I don't want to swap the implementation until it's finished running.

Your point on swappable implementations is well taken, though. I'm going to play around with decorators and see if I can't get a nice concise format I like. It'll have the benefit of eliminating some truly silly looking code I hacked together to make the command loading work in the first place.
03 Apr, 2011, chrisd wrote in the 16th comment:
Votes: 0
Nich said:
I don't think that random references to my commands will be an issue. I'm making encapsulation a priority (Hence the topic title :)). The only module that should be accessing my commands is the one that fetches the commands that a client requests. If reloading isn't working because of that, then I have one clear point where I need to make it work (And it will be pretty obvious any time I try to modify a command without restarting the server).

I'd suggest having a copyover command that reloads everything rather than reloading individual modules. It's similarly convenient, but reloading everything at once avoids a lot of problems. Depending on how much interaction your Java and Python code have, you might even find it possible to unload and then reload all the Python stuff without doing a "real" copyover.

Nich said:
The command shouldn't be in memory when it's not running anyways. And if the command takes time to run, I don't want to swap the implementation until it's finished running.

I think you'll find there are a number of references to your command functions hanging around even when they're not being run - particularly if you're adding them to some sort of central registry for easy lookup.

Nich said:
Your point on swappable implementations is well taken, though. I'm going to play around with decorators and see if I can't get a nice concise format I like. It'll have the benefit of eliminating some truly silly looking code I hacked together to make the command loading work in the first place.

Here's a simple decorator function:

def command(name, pattern):
def decorator(func):
register_command(func, name, pattern)
return func

return decorator
Using the @ syntax to apply this to a function basically has this effect:

def baz():
pass

baz = command("foo", "bar")(baz)

## The above is the same as this:

@command("foo", "bar")
def baz():
pass
Note that the inner decorator() function returns a reference to baz() which is then assigned to the name "baz" in the module. If the "return func" statement wasn't in the decorator() function then your decorated function wouldn't actually "exist" in its module - although if you'd stored a reference to it somewhere it obviously wouldn't be G/Ced.
0.0/16