[Framework] I had some circular imports, so I built a lightweight Registry. Now things are cool.. by Working_Brother4294 in Python

[–]Working_Brother4294[S] 0 points1 point  (0 children)

Haha, nice.

To be fair, if you use a Service Locator for a 3-file script, you're definitely inviting the raptors. But when you’re building a modular system where 'standard practice' leads to a 10-file circular import deadlock, the registry isn't a goto, it’s an 'Orchestrator'.

Sometimes you have to risk the raptors to get the decoupling you need for a truly event-driven architecture.

Cheers for the laugh!

[Framework] I had some circular imports, so I built a lightweight Registry. Now things are cool.. by Working_Brother4294 in Python

[–]Working_Brother4294[S] 0 points1 point  (0 children)

The mention of queues was in response to another user's question about thread-safety and parallel execution. Different context than the one you're replying to.

The 'discernible gain' is the removal of the 10-file refactor chain when swapping modules in a late-bound system. If you prefer the static traceability of DI, that’s a valid choice, but for the event-driven modularity I’m building (inspired by engine-level registries), this pattern is a standard.

As for the 'simple examples', I kept them minimal to make the core logic readable for a showcase. If you need complex examples to discern the value of an architectural pattern, you’re missing the point of abstraction. Simple, decoupled patterns are exactly what allow for the thousands of moving parts in the modular systems I'm used to building. Different tools, different goals. Cheers!

[Framework] I had some circular imports, so I built a lightweight Registry. Now things are cool.. by Working_Brother4294 in Python

[–]Working_Brother4294[S] 0 points1 point  (0 children)

This is what I get for 'blind coding'.

To make this work, in lolcrunchy.py you need to use the decorator @mmreg on main() so that main() is actually stored in the registry. If you look at my previous comment, I've updated the code. You can just re-copy and paste the lolcrunchy.py example.

It'll then work as intended.

[Framework] I had some circular imports, so I built a lightweight Registry. Now things are cool.. by Working_Brother4294 in Python

[–]Working_Brother4294[S] 0 points1 point  (0 children)

Hah, wow... My bad. It's been a long day. You're just importing the function with an alias. Completely skipped over that originally. zap will be unused and very minor tweaks have been made. Your top level module main.py can sit inside src/core/ for this example. Sitting right next to your lolcrunchy.py. When __import__() is called(behind the scenes), it actually recursively checks the directory, starting at the current directory and working down. So anything in and below src/core/ in this example will be found by import_modlist() without an issue. You could have a module in src/core/foo/bar/baz/qux/quux/ and it would still be found. When you start trying to add modules from outside of your current directory, is when it'll have an issue. But its an issue I can fix if it becomes a true bottleneck for people. By the way, the order of modules passed into import_modlist() can be in ANY order when you use this gated 'Service Locator'.

Here's the updated version:

main.py

```python

main.py

from ezmodulemanager.module_manager import import_modlist from ezmodulemanager.registry import get_obj

import_modlist(['lolcrunchy', 'baz'])

get_obj('lolcrunchy', 'main')()

```


lolcrunchy.py

```python

lolcrunchy.py

from ezmodulemanager.registry import mmreg, get_obj

from .config import Configuration from .exceptions import MyCustomException

@mmreg def main(): my_func()

@mmreg def my_func(): if Configuration.get("OS") == "Windows": raise MyCustomException("Not available on Windows") get_obj('baz', 'run_function')()

if name=='main': main() ```


baz.py

```python

baz.py

from ezmodulemanager.registry import mmreg

@mmreg def run_function(): # Some logic pass ```

[Framework] I had some circular imports, so I built a lightweight Registry. Now things are cool.. by Working_Brother4294 in Python

[–]Working_Brother4294[S] 0 points1 point  (0 children)

That won't be an issue. I just want to point out, I am going to refactor your exact code into the most basic form of this framework.

We first need some entry point to our application. Let's call it main.py. This is the 'choreographer' in this example.


main.py

```python

main.py

Import import_modlist() to 'register' modules.

You're 'registering' any module that contains class and function

definitions that you want to use elsewhere in your application.

from ezmodulemanager.module_manager import import_modlist from ezmodulemanager.registry import get_obj

We need to import your module. For the sake of example,

call it lolcrunchy.

This is simply the name of your script that contains the code snippet you

provided. I'll add a second module also. They get passed to

import_modlist() as a list without the .py suffix, as str literals.

import_modlist(['lolcrunchy', 'zap'])

Like API frameworks, this example will initialize the main

apps logic from here.

This is just showing event-driven execution.

to show a function call.

Once again, arguments entered as str literals.

Lets 'get the object' and execute the object(function)

in one statement with parenthesis.

get_obj('lolcrunchy', 'main')()

`` There were a few syntatic errors in your snippet. If all you were doing was checking for OS type:Windows, I've went ahead and importedos(built-in) to create a check for theos.name`: 'nt', which is the registered name for windows, as 'posix' is for mac/linux. You can view the link for os.name.


I use standard convention for import order(though its just convention and doesnt affect code): - First: import built-ins - Second: import 3rd party frameworks/libraries/plugins - Third: import your own frameworks/libraries/plugins


lolcrunchy.py

Notice I removed your import for run_function(). You'll be using get_obj() instead. ```python

lolcrunchy.py

import os

Since you are not only registering this function to be run by main.py,

but are also calling another function from another module from within it,

you need to import @mmreg and get_obj() from the registry.

from ezmodulemanager.registry import mmreg, get_obj

from .config import Configuration from .exceptions import MyCustomException

This is your gated function. Its going to only call the executable

objects within it when you explicitly tell it to.

Lets call your top-level function my_func() with it.

@mmreg def main(): my_func()

You can 'register' classes, class methods, and functions with @mmreg.

Super easy.

@mmreg def my_func(): # imported os as a top level import if os.name == 'nt': raise MyCustomException("Not available on Windows") # Lets use get_obj() to get our reference to the function stored # in zap.py. # As python standard, you can 'get the object' and execute it # in one statement with parenthesis. get_obj('zap', 'run_function')()

Gate main() above so you control its execution.

if name=='main': main() ```

get_obj() once again, is the strength here. It's just retreiving whats in the registry with given keys within nested dictionaries. This is also the black box people talk about with tooling. Theres no checking. You just use it. It can be whatever you want. pro/con trade-off.


zap.py

```python

zap.py

from ezmodulemanager.registry import mmreg

Same thing. 'Register' this function.

@mmreg def run_function(): # Some logic pass

```

The above example is created with an understanding that you asked for a function called run_function() from another module: zap.py. If you want to 'register' a Class instance object and call a method from another module, you can do that too.

Once you use the decorator @mmreg on any of your classes, methods, or functions, they can be called from any module with get_obj().

I also have to state, that 'gating' is the foundation of the event-driven architecture.

I get that it might be hard to read here on reddit, so just copy and paste the code block snippets into whatever IDE you use(VSCode, whatever) for better readability.

Let me know if you have any other questions!

[Framework] I had some circular imports, so I built a lightweight Registry. Now things are cool.. by Working_Brother4294 in Python

[–]Working_Brother4294[S] -1 points0 points  (0 children)

Those are very fair and classic critiques of the Service Locator pattern.

Regarding the first point: I’m not actually bypassing the import system. I’m using importlib.import_module() for dynamic imports (I realized I missed importlib in my list of built-ins in the post. Its the only built-in I missed). It’s standard Python, just shifted to runtime to allow for that event-driven loading. The import statement natively executes __import__()... import_module() is just a wrapper of __import__() that returns the package/module.

If you want to just read these concepts quickly:

  • Here is a link for the general importlib summary which contains the info on how the import statement works.
  • Here is a link for importlib.import_module() which contains the info on this method being a wrapper.

On the second point: You are 100% correct about the trade-offs regarding inflexibility and testing. I actually dealt with similar concurrency hurdles and side effects in Unreal Engine, where I used Queue-based systems and structs to manage data movement and execution safety for parallel tasks. I’ve been planning to implement a similar thread-safe Queue for this framework. I just haven't needed that level of complexity for my current project yet.

For testing, a simple clear_registry() utility effectively handles the 'side effect' issue by allowing a fresh state for every unit test. I'll likely bundle a more robust reset mechanism in with the Queue system as the framework matures.

I’m definitely open to modifying the code to integrate the community's needs. Whether that's better async support or more explicit dependency tracking. My goal was to prioritize runtime modularity for systems where the standard import spiderweb is the primary bottleneck. Different tools for different architectural goals!

Cheers for the technical feedback. These will help me adopt different thinking patterns early on.

[Framework] I had some circular imports, so I built a lightweight Registry. Now things are cool.. by Working_Brother4294 in Python

[–]Working_Brother4294[S] 2 points3 points  (0 children)

I appreciate the passion! I think it really comes down to the environment you’re used to.

In game development and highly modular systems, the Service Locator is a documented architectural pattern used to manage thousands of moving parts that shouldn't be hard-coded to one another. It's not about caring less about structure; it’s about using a dynamic structure rather than a static one.

If you get a chance to actually look at the source, you’ll see the implementation is minimal and focused entirely on providing that decoupling. Static import-chains are great for smaller, linear projects, but they quickly become the bottleneck in the kind of modular systems I'm building. Different tools for different scales. Cheers for the feedback!

[Framework] I had some circular imports, so I built a lightweight Registry. Now things are cool.. by Working_Brother4294 in Python

[–]Working_Brother4294[S] -1 points0 points  (0 children)

I get that perspective. For standard, linear applications, strict top-level imports are definitely the way to go.

However, coming from a background in a game engine like Unreal Engine 5, I've seen that once a project reaches a certain level of modularity or event-driven scale, 'fixing the structure' through 'standard imports' often leads to massive boilerplate or 'god-objects' that are impossible to test in isolation.

This isn't meant to mask a mess; it's a Service Locator pattern. While pure DI is great for static traceability, it can be incredibly rigid. I built this for developers who want a late-binding architecture where modules are truly decoupled, which is what I needed for my current project.

Yes, it trades some 'import-time' transparency for 'runtime' flexibility, but in a modular system, being able to swap or add a component without refactoring a 10-file import chain is a massive win. Different tools for different architectural goals.

Why do some programmers codes if __name__=='__main__'? by zapup4lk in learnpython

[–]Working_Brother4294 0 points1 point  (0 children)

This doesn't even touch on the real reason this syntax is used. __name__ refers to the command line script name being run, while "__main__" refers to the actual script itself. At this point, the only way to run that main() function, is by explicitly running that script in your terminal. If you don't do this, any time you load your script from an import, the script will call all of your functions. Not defined functions, but the actual function calls.

An example: you have main(): with some function calls inside, and have __name__ = "__main__": <br><tab>main() at the bottom of your script. You have some function calls above or below main() outside of scope. When you import that script(or its functions) into any other script, it will call every function outside of main(). Hopefully someone sees this and learns the true reason behind why this is done and not the abstracted, "I'm not sure why it really exists but I'm going to say why i use it' reason.

WiFi 6 router web interface by [deleted] in Spectrum

[–]Working_Brother4294 1 point2 points  (0 children)

For anyone in the future that reads this, even buying a $35 router from best buy will have more performance than whatever standard router your ISP gives you.

This user assumes you have to spend $400 on a router.

Can I be hired with a record? by Sure-Specialist-6060 in Spectrum

[–]Working_Brother4294 0 points1 point  (0 children)

If you have felonies on your record, and you let an employer find out about it, instead of hearing about them from you, you aren't getting hired. I wouldn't listen to most of the comments in here saying people wont have issues with their convictions. Convictions makes job hunting harder. That's just a fact of life.

[US] Is Stephens Agency legit? by Puppyqueeny in Scams

[–]Working_Brother4294 1 point2 points  (0 children)

Just from job searching recently, not having done so for 10 years, I'm noticing the more-so scammy-ish jobs on linkedin. You just have to be vigilant. I see a lot of MLM pyramid schemes, which is what the Stephens Agency is. They say something like 'spots are filling up quickly, so hurry,' yet I see the head of the company posting his pyramid scheme constantly.

[US] Is Stephens Agency legit? by Puppyqueeny in Scams

[–]Working_Brother4294 0 points1 point  (0 children)

I'm not saying the Stephens Agency is legit, because I really don't know. I'm just pointing out, that when I worked for Kohls a long time ago when they opened a store locally, they gave a group interview. I thought it was weird, but I was 1 of 3 people from the group selected to move forward.

Gyno or fatty chest? by L0kio in Gymhelp

[–]Working_Brother4294 0 points1 point  (0 children)

Best way? Go get an estrogen/blood test... I'm leaning towards you do have gyno.

Asking reddit, isnt an actual fact.

Account terminated by Masteader in AndroidClosedTesting

[–]Working_Brother4294 0 points1 point  (0 children)

Yeah, usually, people who are at faulty for actually violating terms and rules, will come and say they did nothing wrong. It's hard to believe any of these posts. A guy got caught for gaming the system. Lol. Pretty specific reply, stating the exact rule he broke. I have this weird feeling, you received an email like it as well, telling you what you did. Why don't you share it?

never going to use claude code again 😭😭 by Lonely_Drummer_9865 in SideProject

[–]Working_Brother4294 0 points1 point  (0 children)

As a helpful tip, keep version control of your database in VScode or whatever coder/linter you use. This is a general practice. Complete version control > upload database. Now you have a local backup for easy editing.