Python How to force object instantiation via Context Manager?

If you consider that your clients will follow basic python coding principles then you can guarantee that no method from your class will be called if you are not within the context.

Your client is not supposed to call __enter__ explicitly, therefore if __enter__ has been called you know your client used a with statement and is therefore inside context (__exit__ will be called).

You just need to have a boolean variable that helps you remember if you are inside or outside context.

class Obj:
    def __init__(self):
        self.inside_context = False

    def __enter__(self):
        self.inside_context = True
        print("Entering context.")
        return self

    def __exit__(self, *exc):
        print("Exiting context.")
        self.inside_context = False

    def some_stuff(self, name):
        if not self.inside_context:
            raise Exception("This method should be called from inside context.")
        print("Doing some stuff with", name)

    def some_other_stuff(self, name):
        if not self.inside_context:
            raise Exception("This method should be called from inside context.")
        print("Doing some other stuff with", name)


with Obj() as inst_a:
    inst_a.some_stuff("A")
    inst_a.some_other_stuff("A")

inst_b = Obj()
with inst_b:
    inst_b.some_stuff("B")
    inst_b.some_other_stuff("B")

inst_c = Obj()
try:
    inst_c.some_stuff("c")
except Exception:
    print("Instance C couldn't do stuff.")
try:
    inst_c.some_other_stuff("c")
except Exception:
    print("Instance C couldn't do some other stuff.")

This will print:

Entering context.
Doing some stuff with A
Doing some other stuff with A
Exiting context.
Entering context.
Doing some stuff with B
Doing some other stuff with B
Exiting context.
Instance C couldn't do stuff.
Instance C couldn't do some other stuff.

Since you'll probably have many methods that you want to "protect" from being called from outside context, then you can write a decorator to avoid repeating the same code to test for your boolean:

def raise_if_outside_context(method):
    def decorator(self, *args, **kwargs):
        if not self.inside_context:
            raise Exception("This method should be called from inside context.")
        return method(self, *args, **kwargs)
    return decorator

Then change your methods to:

@raise_if_outside_context
def some_other_stuff(self, name):
    print("Doing some other stuff with", name)

None that I am aware of. Generally, if it exists in python, you can find a way to call it. A context manager is, in essence, a resource management scheme... if there is no use-case for your class outside of the manager, perhaps the context management could be integrated into the methods of the class? I would suggest checking out the atexit module from the standard library. It allows you to register cleanup functions much in the same way that a context manager handles cleanup, but you can bundle it into your class, such that each instantiation has a registered cleanup function. Might help.

It is worth noting that no amount of effort will prevent people from doing stupid things with your code. Your best bet is generally to make it as easy as possible for people to do smart things with your code.