question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Manually selecting a manim.cfg when NOT running from ClI

See original GitHub issue

Title. It’s not possible rn, as the .cfg files are chosen first when importing manim by a CLI flag.

This would be useful for tests, and for (maybe) a potential migrating toward a manim that can be run from python files.

Pinging @leotrs

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:13 (13 by maintainers)

github_iconTop GitHub Comments

2reactions
leotrscommented, Aug 29, 2020

I’m working on this. The tempconfig was the first step toward that goal

2reactions
leotrscommented, Aug 18, 2020

Ok I’ve been thinking about this, and I’ll make it my priority for now because it’s holding up other things (#318, #317). If manim could be ran programmatically (and not only from the command line), testing would be much easier too. Also, I just realized that the configuration is actually being parsed (at least) twice, because the config._run_config() function is being called multiple times… So here’s my plan to do this. cc @Aathish04 @huguesdevimeux @naveen521kk @eulertour @PgBiel please share your thoughts.

I propose that we implement the following ways of rendering a scene using manim:

From the command line (already supported):

manim <file.py> SceneName -pl

From a python script:

import manim

class MyScene(manim.Scene):
    pass

# now, to render the scene, we do either of the following:
MyScene().render()
manim.render(MyScene)
manim.render(some_module)
  • MyScene().render(). For this one to work, we need to implement a Scene.render method. Right now, a Scene is automatically rendered when it is constructed, but this can be easily changed by moving a few lines from Scene.__init__ to Scene.render, and calling render inside __main__.main() so that manim can still be called from the command line without any changes. This is an easy PR that we could implement ASAP (and, I think, regardless of the rest of this proposal). Note that this alone would simplify testing a good deal.

  • manim.render(MyScene). For this one to work, we can implement a render method in __init__.py that just calls the newScene.render (see the previous paragraph).

  • manim.render(some_module). When called in this way, this just searches any Scene classes in some_module and creates them and calls their render method. This is pretty much what the current __main__.main() does.

Now, the main problem (and going back to the present issue) is how to specify a config file when rendering programmatically, in any of the previous three ways. I suggest that we implement them as:

MyScene().render(config=None, config_file=None)
manim.render(scene_or_module, config=None, config_file=None)

The config argument is a dictionary that will temporarily update the global config dict. This means that if I do manim.render(MyScene, config={"background_color": WHITE}), then the global config will be used, but the "background_color" option will be overriden by WHITE. Right before returning, this function will restore the global config dict. Calling manim.render(MyScene) without a config argument just uses the global config dict untouched. Using the other argument, config_file, will read the specified file and add it as the highest priority to the cascading file system, and update the global config dict. The global config is again restored after the call returns. (We can perhaps cache the resulting overriden config dicts in case they are needed again in the future.)

Now, all of this pivots on the fact that executing import manim will correctly setup the global config dict. In particular, recall that import manim first executes __init__.py which in turn executes import config. So the order of events would be the following:

  1. A script executes import manim, which executes manim/__init__.py. This can be a user scene script or our own manim/__main__.py.
  2. In __init__.py, the first line of code is import config which executes config.py.
  3. In config.py, as much as possible of the config dict should be defined. In particular, all config files must be read and parsed. Another change I’m proposing is that config.py also parses the sections of the configuration corresponding to the logger, and exports a new dictionary called logger_config. All of config, camera_config, file_writer_config, and logger_config are defined and exported. NOTE the logger is NOT set here.
  4. Back in __init__.py, the next line should be import logger. This executes logger.py, which will execute from config import logger_config, and use it to set the logger.
  5. Here comes the split.
    • If the original script is a user script, then we are done and execution is returned to the user. They can then go about defining their Scene classes and ultimately calling manim.render(Scene, config=some_config_dict). If they do so, then the function manim.render will call config.udpate(some_config_dict), render the Scene, and then restore the original global config dict. Execution ends here. (Note this is also the case for tests or docs builds which require to import manim.)
    • If the original script was __main__ because manim has been called from the command line, __init__.py returns execution to __main__.main. Now, this function must deal with parsing command line flags and then updating the global config dict permanently. This can easily be done by e.g. manim.config.parse_cli(args). Note this will remove the problem we’ve had in the past where config.py had to determine whether it had been called from the command line. Once the CLI flags have been parsed and the config updated, __main__.main simply decides what to execute next, depending on the subcommand used. Thus, a big chunk of cfg_subcommands will be ported into __main__.py. In the event that the console command requires manim to render a scene, __main__.main can just call manim.render(module_passed_on_the_cli).

Note that in the process of making these changes, we will eliminate the hacky function _from_command_line, as well as eliminating the need of calling _run_config twice, and there will be even more consolidation of the whole mess that is the config system. (I’m 100% guilty of it being a mess.)

I hope this made some sense. I wanted to ran it by everyone before going into it because it will require a certain degree of surgery and being very careful.

Are there any objections? Did I miss anything?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Configuration - Manim Community v0.17.1
cfg . Currently, Manim does not support config files with any other name. The config file must start with the section header [CLI] ......
Read more >
CLI flags and configuration - manim documentation
flag abbr function ‑‑help ‑h Show the help message and exit ‑‑version ‑v Display the version of manimgl ‑‑write_file ‑w Render the scene as a movie...
Read more >
First example command returns error (get_monitors) #1389
Describe the error. I want to execute : manimgl example_scenes.py OpeningManimExample. Code and Error. Code: example_scenes.py. Error:
Read more >
python - Is it possible to run manim programmatically (and not ...
The "manim" command is just a Python script, so clearly the answer is yes. You can poke through the source to find their...
Read more >
Manim Tutorial Series E02: Positioning and Configuration
Manim is a free and open-source, community-maintained Python library for creating (mathematical) animations originally started by Grant ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found