powsybl / powsybl-core

A framework to build power system oriented software

Home Page:https://www.powsybl.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Programmaticaly changeable PlatformConfigProvider

nicolas-pierr opened this issue · comments

  • Do you want to request a feature or report a bug?
    Feature

  • What is the current behavior?
    There are only two way to have a PlatformConfigProvider with powsybl packages, classic or test. The test one should be used for test, and the classic only handles environment variables to tell where to look for config files.
    A new way could be to have a simple PlatformConfigProvider that store the path to the config folder/file and it can be modify via a setters.

  • What is the motivation / use case for changing the behavior?
    One use case is for pypowsybl which would benefit from exposing to the python user the config path instead on always relying on the default ~/.itools folder.

Widely inspired from the classic PlatformConfigProvider, it would be something like this :

public class CustomPlatformConfig implements PlatformConfigProvider {
    private static final String NAME = "custom";
    private String path = "~/.itools";
    private String configName = "config";
    private FileSystem fs;

    public CustomPlatformConfig() {
        fs = FileSystems.getDefault();
    }

    @Override
    public String getName() {
        return NAME;
    }

    static ModuleConfigRepository loadModuleRepository(Path[] configDirs, String configName) {
        List<ModuleConfigRepository> repositoriesFromPath = Arrays.stream(configDirs)
                .map(configDir -> PlatformConfig.loadModuleRepository(configDir, configName))
                .collect(Collectors.toList());
        List<ModuleConfigRepository> repositories = new ArrayList<>();
        repositories.add(new EnvironmentModuleConfigRepository(System.getenv(), FileSystems.getDefault()));
        repositories.addAll(repositoriesFromPath);
        return new StackedModuleConfigRepository(repositories);
    }

    @Override
    public PlatformConfig getPlatformConfig() {
        return new PlatformConfig(
                loadModuleRepository(new Path[] {fs.getPath(path)}, configName),
                fs.getPath(path));
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getConfigName() {
        return configName;
    }

    public void setConfigName(String configName) {
        this.configName = configName;
    }

    public FileSystem getFs() {
        return fs;
    }

    public void setFs(FileSystem fs) {
        this.fs = fs;
    }

}

The difficulty to implement this is that in general the platform config is read:

  • only once
  • very early at execution time

Today, it's not obvious for an application to know when this read will occur. Therefore, even if you are able to set the path in the config provider, it is likely that it will have no effect at all, because getPlatformConfig will have been called earlier.

In particular, it is very possible that in pypowsybl, the config creation is done as soon as you import the python module, which does not leave any room for the python user to set the config path.

Even if it's not the case, it will be hard for the user to understand when the setter stops to be effective. For example:

import pypowsybl as pp
pp.set_config_path('/path/to/my/config.yml') # ok, works
n = pp.network.load('network.xiidm')  # will read the config
pp.set_config_path('/other/path/to/my/config.yml') # completely useless

So, if we want to make this work, it means that everywhere where PlatformConfig is used today, we need to reload it from the config provider, and we must find a way to guarantee that it's done this way in the future --> API needs probably to evolve with a breaking change.

A consequence of the above thoughts:
if we go for the "settable path" approach, we should allow it only as long as config has not been read, and throw an exception otherwise, with a clear message.

I agree that we should not allow calling the setter if this has no impact on the config loaded.
It is easy to know if it was loaded since the result getPlatformConfig is cached.
I just checked pypowsybl and it does not load the config when I import the package.