Repository: ManimCommunity/manim
Pull request: Properly parse the file path to get the module containing the Scenes
This PR will close #171 .

The lines/file concerned are:

https://github.com/ManimCommunity/manim/blob/ea79842b17ccb7e0a5eb33be5edc5abb4ce60b50/manim/__main__.py#L137-L139

The issue was that the regex based approach would fail when there was a `.` in the path and end up importing all scenes in the library instead of those that were needed.

The pattern `"\..+$"` matches all characters after a `.` , and makes sure that the matched characters end with a newline, and replaces them with an empty string.

The pattern works fine when the only characters to the right of the `.` is `py`, but fails when you are leading in from another path.

For `./basic.py`, the `file_name.replace(os.sep,".")` makes the string into `..basic.py`, and the regex sees that the first character is a `.` and sees that the line ends with that string, and matches `..basic,py` entirely, and replaces it with an empty string.

`./basic.py` --> .replace(..) --> `..basic.py` --> regex --> ""

And then this empty string gets passed to `importlib`, which imports all the scenes that exist in the entire repo since it didn't receive a proper module to import.

This has been solved by using string slicing and splitting at appropriate places to extract the module name.

`module_name = file_name[:-3].replace(os.sep, '.').split('.')[-1]`

The string is first sliced to get rid of the `.py`, then the separators are replaced with `.`s. The resulting string is split at every `.` and the last element of that list, which _should_ be the module name, is taken.

I have tested this from multiple locations, with multiple file names. 

The only issue that this approach might face is that it will completely fail when there's a `.` in the name of the file containing the module, like `my.module.py`, but the original approach would fail in that case too, so, no net loss ;)

Problem statement:
With no scene specified on CLI, manim gives false choice.
I was running the command:
`manim -pl --media_dir ~/renderings ~/dev/manim/example_scenes/basic.py ` 
and was greeted by this:
```

[19:29:42] INFO     Read configuration files:                                                                      config.py:416
                    ['/home/cobordism/.local/lib/python3.8/site-packages/manim/default.cfg']                                    
1: GraphScene
2: LinearTransformationScene
3: MovingCameraScene
4: OpeningManimExample
5: ReconfigurableScene
6: SampleSpaceScene
7: SpecialThreeDScene
8: SquareToCircle
9: ThreeDScene
10: UpdatersExample
11: VectorScene
12: WarpSquare
13: WriteStuff
14: ZoomedScene

Choose number corresponding to desired scene/arguments.
(Use comma separated list for multiple entries)
Choice(s): 

```

Clearly something is wonky here The choices should have been only the scenes from basic.py.
i.e. OpeningManimExample, SquareToCircle, WarpSquare, WriteStuff, UpdatersExample.

Hints from issue discussion:
What a weird bug. Running manim on `basic.py` works as expected, but on `./basic.py` it doesn't:

```
$ manim -pl basic.py
[09:49:01] INFO     Read configuration files: ['/home/leo/code/manim/manim/default.cfg']                                                                        config.py:416 
1: OpeningManimExample
2: SquareToCircle
3: UpdatersExample
4: WarpSquare
5: WriteStuff

Choose number corresponding to desired scene/arguments.
(Use comma separated list for multiple entries)
Choice(s):
```


```
$ manim -pl ./basic.py 
[10:44:15] INFO     Read configuration files: ['/home/leo/code/manim/manim/default.cfg']                                                                        config.py:416 
1: GraphScene
2: LinearTransformationScene
3: MovingCameraScene
4: OpeningManimExample
5: ReconfigurableScene
6: SampleSpaceScene
7: SpecialThreeDScene
8: SquareToCircle
9: ThreeDScene
10: UpdatersExample
11: VectorScene
12: WarpSquare
13: WriteStuff
14: ZoomedScene

Choose number corresponding to desired scene/arguments.
(Use comma separated list for multiple entries)
Choice(s):
```
I'm at a loss here. Apparently when using `./basic.py`, manim is reading all Scene classes in the scope (which include all those imported with `from manim import *` e.g. GraphScene, ZoomedScene, etc); but when using `basic.py` these don't show up.

Commit message: Use a better way of getting the module name from the file path.

Patch to review:
diff --git a/manim/__main__.py b/manim/__main__.py
index d1536e26fc..c14ca06126 100644
--- a/manim/__main__.py
+++ b/manim/__main__.py
@@ -135,7 +135,7 @@ def get_module(file_name):
             sys.exit(2)
     else:
         if os.path.exists(file_name):
-            module_name = re.sub(r"\..+$", "", file_name.replace(os.sep, "."))
+            module_name = file_name[:-3].replace(os.sep, '.').split('.')[-1]
             spec = importlib.util.spec_from_file_location(module_name, file_name)
             module = importlib.util.module_from_spec(spec)
             spec.loader.exec_module(module)


Code review comments:
diff_hunk: @@ -135,7 +135,7 @@ def get_module(file_name):
             sys.exit(2)
     else:
         if os.path.exists(file_name):
-            module_name = re.sub(r"\..+$", "", file_name.replace(os.sep, "."))
+            module_name = file_name[:-3].replace(os.sep, '.').split('.')[-1]
path: manim/__main__.py
text: @user2:
Perhaps add a line before this to check that `module_name[-3:] == ".py"`. Also, I think @user1 has Opinions about this line.

@author:
Will do, but isn't it sort of mandatory for the file to be a python file anyway? Should I make it raise an exception if it is not a file ending with `.py`?

@user2:
"Trust, but verify" ;)

@author:
Understood :)

Also done in the latest commit.