Aha, I get it. I never thought about the attributes of a service definition getting modified, but you're right, it might happen. I'll try to figure out whether using immutable data structures for attributes would work out.
The problem isn't so much if a specific service definition gets modified, it's more if they're trying to modify one, and accidentally modify many.
say they have a service with a ton of dependencies and they want to store it in a separate file:
class Application(miniboss.Service):
name = "python-todo"
image = "afroisalreadyin/python-todo:0.0.1"
env = {"DB_URI": "postgresql://dbuser:dbpwd@appdb:5432/appdb"}
ports = {8080: 8080}
stop_signal = "SIGINT"
def __init__(self):
with open('dependency_list') as f:
for dependency in f.readlines():
self.dependencies.append(dependency)
Once that class is initialized, any service that previously had zero dependencies, will now have everything in the file, because the list in miniboss.Service is shared by all instances of all subclasses that didn't override it.
One easy way to limit this is to define your miniboss.Service defaults in init instead of the toplevel. Then if users use mutable types at the top level, it only becomes an issue if they make subclasses, or if the process makes more than one instance of a particular class.
I still think immutable types are the best bet, but if they need mutable ones to throw some python magic in their somewhere along the build process, then tell them to define them within an __init__.
Or maybe just keep doing what your doing, and add a warning in the docs not to do screwy stuff like that.
Again, this really does look great I'm excited to see where it goes.
Without looking at miniboss code - is there a reason why services are defined as classes as opposed to instances? E.g.
# maybe even have the group as an instance
group = miniboss.Group(name="foobar")
group.database = miniboss.Service(
name="appdb",
image="postgres:10.6",
env={
"POSTGRES_PASSWORD": "dbpwd",
"POSTGRES_USER": "dbuser",
"POSTGRES_DB": "appdb"
},
ports={5432: 5433}
)
As I understand it the services are instances, the classes are the service definitions. So if you wanted 5 identical web servers you only need to make one service definition class, and then miniboss would use instances of it to make the containers. I could be wrong though.
I'll second the use of immutable data structures. Had to do some real nasty work of debugging last week because someone accidentally mutated a configuration object causing persistence issues much deeper in the stack. Would've been impossible with frozendicts.