-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Figure out the 'core' and the module system #12
Comments
Hi, That said, if your really want to avoid pypi/packages (in the sense of setup.py backed packages), it could be done like this (I never did it, but I think it could work):
All of this doesn't solve the "module not found" issues in IDEs while importing the modules, because the plugin directory is still dynamically loaded. IMO the most pythonic way to handle this is by using namespace packages, so that all the modules/plugins created can be installed separately and seen as a single package.
Let me know what you think! |
Hi! Sorry for a late reply, was a bit busy over the weekend... Thanks for your thorough comments and time spent analyzing the code. Really appreciate it, and your thoughts! I decided to respond to your other comment here too, because the issues kind of overlap anyway.
Thanks, actually a really good idea. I'll make it a default :)
I actually published a whole post about it just yesterday, it's kind of relevant to this package too! Overall:
Yep, feels about right!
Not that I have anything against it, but most modules are fairly simple and consist of a single file. Maybe some 'heavy' modules could indeed be properly packaged when matured (with
Sure, seems like a reasonable default! For inspiration, might also be a good idea to look how tools like
Yeah, it's kind of the way it is now (just namespace packages instead separaty). Some of them are single-file modules, and I just didn't bother creating unnecessary dirctory for them.
Yeah, sure, don't have any strong opinion about that -- some like it more explicit, some more implicit. E.g. I personally use it with a helper script.
Yep, sure. That actually might work with namespace packages too.. E.g.:
Then
Haven't tested, but seems like it could work?
Maybe, but that makes it quite a bit more complicated. As you mentioned, virtualenv or something similar could be used? Seems that it might work in conjunction with pip/
Yep! All of this doesn't solve the "module not found" issues in IDEs while importing the modules, because the plugin directory is still dynamically loaded.
100% agree! That's actually what I've been doing so far with external dependencies.
Actually, not necessarily! I've been getting away with it by simply using symlinks! E.g. example in the repository That makes it transparent and pylint/mypy/IDE friendly. Wow, that's quite long. Again, thanks for you elaborate comments :) Hopefully that helps with simplifying and documenting the system! |
Hi, Let's say that I'm biased towards a separation of configuration from the code, mainly because I write tools for colleagues that don't know python but can handle (more or less) an ini or json file. As I stated in the other issue, a library like file-config makes configuration loading easier, with type hinting and validation at runtime, and you have the entire configuration object definition already available for the logic to work. As of now, to know the configuration options that can/should be present in mycfg, one needs to inspect every single file in search for This is an (untested) example of a refactored configuration for rss and pdfs # my/config.py
from pathlib import Path
from typing import List
from file_config import config, var
@config(title="Feedbin", description="Feedbin export paths configuration")
class Feedbin:
enabled = var(bool, default=False)
export_dir = var(str)
@config(title="Feedly", description="Feedly export paths configuration")
class Feedly:
enabled = var(bool, default=False)
export_dir = var(str)
@config(title="RSS", description="RSS configuration")
class RSS:
feedbin = var(Feedbin)
feedly = var(Feedly)
@config(title="PDF", description="PDF annotations configuration")
class PDFs:
search_paths = var(List[str])
ignore_files = var(List[str])
@config(title="My Config", description="HPI modules configuration")
class MyConfig:
pdfs = var(PDFs)
rss = var(RSS)
def load_user_config() -> MyConfig:
cfg_path = Path.home() / ".config" / "my" / "config.toml"
if cfg_path.exists():
with path.open() as tomlconfig:
return MyConfig.load_toml(tomlconfig) To make it extendable, you can modify this pattern my making plugins declare their own configuration object to be added to the main config via injection, if it has to be shared with other modules, or just use their own config object, leveraging HPI only for a configuration loading function. Again, from what I saw, it seems that the various modules can't be called proper plugins, since there's no logic that ties them together. So the only "logic" that I see is to have everything inside the For namespace packages I meant what it's stated in the documentation I linked:
That way, users can create and publish their own subpackage that will be added to the In the case I am totally off, and indeed a plugin architecture is needed, here are some other thoughts: Plugin discovery and loading is a topic already covered by multiple projects in multiple ways; Previously mentioned Ulauncher, instead, implements its own plugin discovery and management, by looking for folders with But then again, I'm biased because I need to deploy apps that don't need tinkering on the user side. I guess the discussion is to complex to solve it in short messages :D |
Sure. But for now the whole system is so far from being accessible for an average user (i.e. you have to get oauth tokens, run cron jobs, and so on), that I'd rather not trade the flexibility at this stage. I think adding plain yaml configs would be easy to do later if it feels necessary.
Ah, yep, totally agree about it! I just have been postponing it so far until things relatively settle!
Hmm, it looks nice indeed, thanks! From the first grance looks similar to mypy's Protocols, but having extra runtime checks are probably better for an average user, who wouldn't bother running mypy.
Yep! So far, I've applied your suggestion of namespace packages, and split out the config into a namespace package. So at the moment it's:
(in the future common/error might be moved into my.core and the individual modules into separate 'plugins'). And the private configuration in
And thanks for your links regarding packaging! Bookmarked and will check them out. |
Namespace packages turned out to be even more flexible than I expected... So I managed to simplify it quite a bit, hopefully can finally extract the interfaces as the next step! #41 |
I thought about the configs specifically a bit more, and ended up writing a whole document about it, figured it's worth a separate issue #46 |
I can manage, say, 30 modules I'm using personally.
If there are 200 modules, I will be completely overwhelmed (i.e. see what happened to oh-my-zsh or spacemacs).
I guess I need to figure out the 'core' of the system and a good way to make 'plugins', so you can use third party modules without merging them in the main repository/maintaining a fork.
Python packages kind of work, but modules need to be more lightweight. Ideally you don't need to make a proper python package from a module, as long as you're accepting you manage dependencies yourself.
The text was updated successfully, but these errors were encountered: