sceneprogexec 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sceneprogexec-0.1.0/PKG-INFO +161 -0
- sceneprogexec-0.1.0/README.md +142 -0
- sceneprogexec-0.1.0/sceneprogexec/__init__.py +3 -0
- sceneprogexec-0.1.0/sceneprogexec/__main__.py +4 -0
- sceneprogexec-0.1.0/sceneprogexec/exec.py +324 -0
- sceneprogexec-0.1.0/sceneprogexec.egg-info/PKG-INFO +161 -0
- sceneprogexec-0.1.0/sceneprogexec.egg-info/SOURCES.txt +10 -0
- sceneprogexec-0.1.0/sceneprogexec.egg-info/dependency_links.txt +1 -0
- sceneprogexec-0.1.0/sceneprogexec.egg-info/entry_points.txt +2 -0
- sceneprogexec-0.1.0/sceneprogexec.egg-info/top_level.txt +1 -0
- sceneprogexec-0.1.0/setup.cfg +4 -0
- sceneprogexec-0.1.0/setup.py +28 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: sceneprogexec
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A CLI and Python module for executing Blender scripts and managing Blender's Python environment. Built to support SceneProg projects.
|
|
5
|
+
Home-page: https://github.com/KunalMGupta/SceneProgExec
|
|
6
|
+
Author: Kunal Gupta
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Dynamic: author
|
|
13
|
+
Dynamic: classifier
|
|
14
|
+
Dynamic: description
|
|
15
|
+
Dynamic: description-content-type
|
|
16
|
+
Dynamic: home-page
|
|
17
|
+
Dynamic: requires-python
|
|
18
|
+
Dynamic: summary
|
|
19
|
+
|
|
20
|
+
# π SceneProgExec: Blender Python Script & Package Manager
|
|
21
|
+
|
|
22
|
+
**SceneProgExec** is a command-line tool and Python module that enables seamless execution of **Blender scripts** and **package management** within Blender's **isolated Python environment**.
|
|
23
|
+
|
|
24
|
+
## π₯ Features
|
|
25
|
+
β
**Execute Python scripts inside Blender**
|
|
26
|
+
β
**Install Python packages in Blender's Python environment**
|
|
27
|
+
β
**Perform a full reset (remove all third-party packages)**
|
|
28
|
+
β
**Automatically cleans up temporary files after execution**
|
|
29
|
+
β
**Works both as a CLI tool and a Python module**
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## π₯ Installation
|
|
34
|
+
|
|
35
|
+
### **1οΈβ£ Install from PyPI**
|
|
36
|
+
```bash
|
|
37
|
+
pip install sceneprogexec
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
OR **Clone the Repository**
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/KunalMGupta/SceneProgExec.git
|
|
43
|
+
cd SceneProgExec
|
|
44
|
+
pip install .
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### **2οΈβ£ Set Environment Variables**
|
|
48
|
+
Before using `SceneProgExec`, set the required environment variables:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
export BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
|
|
52
|
+
export BLENDER_PYTHON=/Applications/Blender.app/Contents/Resources/4.3/python/bin/python3.11
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
To make this **permanent**, add the lines to your `~/.bashrc` or `~/.zshrc`:
|
|
56
|
+
```bash
|
|
57
|
+
echo 'export BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender' >> ~/.zshrc
|
|
58
|
+
echo 'export BLENDER_PYTHON=/Applications/Blender.app/Contents/Resources/4.3/python/bin/python3.11' >> ~/.zshrc
|
|
59
|
+
source ~/.zshrc
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### **3οΈβ£ Run CLI Commands**
|
|
63
|
+
Once installed, you can use `sceneprogexec` globally.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## π οΈ Usage
|
|
68
|
+
|
|
69
|
+
### **πΉ Run a Python Script Inside Blender**
|
|
70
|
+
```bash
|
|
71
|
+
sceneprogexec run my_script.py --target my_scene.blend
|
|
72
|
+
```
|
|
73
|
+
β
Runs `my_script.py` inside **Blender**.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### **πΉ Install Packages Inside Blender**
|
|
78
|
+
```bash
|
|
79
|
+
sceneprogexec install numpy pandas
|
|
80
|
+
```
|
|
81
|
+
β
Installs `numpy` and `pandas` inside **Blenderβs Python**.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### **πΉ Install Packages With a Hard Reset**
|
|
86
|
+
```bash
|
|
87
|
+
sceneprogexec install numpy pandas --reset
|
|
88
|
+
```
|
|
89
|
+
β
**Removes all third-party packages** before installing new ones.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### **πΉ Reset Blender's Python (Remove All Third-Party Packages)**
|
|
94
|
+
```bash
|
|
95
|
+
sceneprogexec reset
|
|
96
|
+
```
|
|
97
|
+
ποΈ **Deletes all third-party Python packages** in Blender.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## ποΈ **Using as a Python Module**
|
|
102
|
+
SceneProgExec can also be **imported and used in Python scripts**:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from sceneprogexec import SceneProgExec
|
|
106
|
+
|
|
107
|
+
executor = SceneProgExec()
|
|
108
|
+
executor.install_packages(["numpy"])
|
|
109
|
+
executor.run_script("my_script.py")
|
|
110
|
+
executor._delete_all_third_party_packages() # Hard reset
|
|
111
|
+
|
|
112
|
+
script = """
|
|
113
|
+
import bpy
|
|
114
|
+
print("Hello, World!")
|
|
115
|
+
"""
|
|
116
|
+
executor(script, target="test.blend")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## π **Automatic Cleanup**
|
|
122
|
+
- **Temporary directory (`blender_tmp`) is deleted** after execution.
|
|
123
|
+
- **No leftover logs or scripts clutter your system**.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## π οΈ **Troubleshooting**
|
|
128
|
+
β **Blender not found?**
|
|
129
|
+
Ensure `BLENDER_PATH` and `BLENDER_PYTHON` are correctly set. Run:
|
|
130
|
+
```bash
|
|
131
|
+
echo $BLENDER_PATH
|
|
132
|
+
echo $BLENDER_PYTHON
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
β **Permission denied?**
|
|
136
|
+
Try:
|
|
137
|
+
```bash
|
|
138
|
+
chmod +x /usr/local/bin/sceneprogexec
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
β **Blender script fails to execute?**
|
|
142
|
+
Check the log:
|
|
143
|
+
```bash
|
|
144
|
+
cat blender_tmp/blender_log.txt
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## π License
|
|
150
|
+
This project is licensed under the **MIT License**.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## π¨βπ» Author
|
|
155
|
+
Developed by **Kunal Gupta**
|
|
156
|
+
GitHub: [KunalMGupta](https://github.com/KunalMGupta)
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## β **Support the Project**
|
|
161
|
+
If you find this tool useful, give it a β on GitHub!
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# π SceneProgExec: Blender Python Script & Package Manager
|
|
2
|
+
|
|
3
|
+
**SceneProgExec** is a command-line tool and Python module that enables seamless execution of **Blender scripts** and **package management** within Blender's **isolated Python environment**.
|
|
4
|
+
|
|
5
|
+
## π₯ Features
|
|
6
|
+
β
**Execute Python scripts inside Blender**
|
|
7
|
+
β
**Install Python packages in Blender's Python environment**
|
|
8
|
+
β
**Perform a full reset (remove all third-party packages)**
|
|
9
|
+
β
**Automatically cleans up temporary files after execution**
|
|
10
|
+
β
**Works both as a CLI tool and a Python module**
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## π₯ Installation
|
|
15
|
+
|
|
16
|
+
### **1οΈβ£ Install from PyPI**
|
|
17
|
+
```bash
|
|
18
|
+
pip install sceneprogexec
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
OR **Clone the Repository**
|
|
22
|
+
```bash
|
|
23
|
+
git clone https://github.com/KunalMGupta/SceneProgExec.git
|
|
24
|
+
cd SceneProgExec
|
|
25
|
+
pip install .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### **2οΈβ£ Set Environment Variables**
|
|
29
|
+
Before using `SceneProgExec`, set the required environment variables:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
export BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
|
|
33
|
+
export BLENDER_PYTHON=/Applications/Blender.app/Contents/Resources/4.3/python/bin/python3.11
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To make this **permanent**, add the lines to your `~/.bashrc` or `~/.zshrc`:
|
|
37
|
+
```bash
|
|
38
|
+
echo 'export BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender' >> ~/.zshrc
|
|
39
|
+
echo 'export BLENDER_PYTHON=/Applications/Blender.app/Contents/Resources/4.3/python/bin/python3.11' >> ~/.zshrc
|
|
40
|
+
source ~/.zshrc
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### **3οΈβ£ Run CLI Commands**
|
|
44
|
+
Once installed, you can use `sceneprogexec` globally.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## π οΈ Usage
|
|
49
|
+
|
|
50
|
+
### **πΉ Run a Python Script Inside Blender**
|
|
51
|
+
```bash
|
|
52
|
+
sceneprogexec run my_script.py --target my_scene.blend
|
|
53
|
+
```
|
|
54
|
+
β
Runs `my_script.py` inside **Blender**.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
### **πΉ Install Packages Inside Blender**
|
|
59
|
+
```bash
|
|
60
|
+
sceneprogexec install numpy pandas
|
|
61
|
+
```
|
|
62
|
+
β
Installs `numpy` and `pandas` inside **Blenderβs Python**.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### **πΉ Install Packages With a Hard Reset**
|
|
67
|
+
```bash
|
|
68
|
+
sceneprogexec install numpy pandas --reset
|
|
69
|
+
```
|
|
70
|
+
β
**Removes all third-party packages** before installing new ones.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### **πΉ Reset Blender's Python (Remove All Third-Party Packages)**
|
|
75
|
+
```bash
|
|
76
|
+
sceneprogexec reset
|
|
77
|
+
```
|
|
78
|
+
ποΈ **Deletes all third-party Python packages** in Blender.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## ποΈ **Using as a Python Module**
|
|
83
|
+
SceneProgExec can also be **imported and used in Python scripts**:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from sceneprogexec import SceneProgExec
|
|
87
|
+
|
|
88
|
+
executor = SceneProgExec()
|
|
89
|
+
executor.install_packages(["numpy"])
|
|
90
|
+
executor.run_script("my_script.py")
|
|
91
|
+
executor._delete_all_third_party_packages() # Hard reset
|
|
92
|
+
|
|
93
|
+
script = """
|
|
94
|
+
import bpy
|
|
95
|
+
print("Hello, World!")
|
|
96
|
+
"""
|
|
97
|
+
executor(script, target="test.blend")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## π **Automatic Cleanup**
|
|
103
|
+
- **Temporary directory (`blender_tmp`) is deleted** after execution.
|
|
104
|
+
- **No leftover logs or scripts clutter your system**.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## π οΈ **Troubleshooting**
|
|
109
|
+
β **Blender not found?**
|
|
110
|
+
Ensure `BLENDER_PATH` and `BLENDER_PYTHON` are correctly set. Run:
|
|
111
|
+
```bash
|
|
112
|
+
echo $BLENDER_PATH
|
|
113
|
+
echo $BLENDER_PYTHON
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
β **Permission denied?**
|
|
117
|
+
Try:
|
|
118
|
+
```bash
|
|
119
|
+
chmod +x /usr/local/bin/sceneprogexec
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
β **Blender script fails to execute?**
|
|
123
|
+
Check the log:
|
|
124
|
+
```bash
|
|
125
|
+
cat blender_tmp/blender_log.txt
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## π License
|
|
131
|
+
This project is licensed under the **MIT License**.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## π¨βπ» Author
|
|
136
|
+
Developed by **Kunal Gupta**
|
|
137
|
+
GitHub: [KunalMGupta](https://github.com/KunalMGupta)
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## β **Support the Project**
|
|
142
|
+
If you find this tool useful, give it a β on GitHub!
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# #!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# import os
|
|
4
|
+
# import subprocess
|
|
5
|
+
# import shutil
|
|
6
|
+
# import argparse
|
|
7
|
+
# import sys
|
|
8
|
+
# import tempfile
|
|
9
|
+
|
|
10
|
+
# class SceneProgExecutor:
|
|
11
|
+
# def __init__(self, output_blend="scene_output.blend"):
|
|
12
|
+
# """
|
|
13
|
+
# Initializes SceneProgExecutor with script execution and package management capabilities.
|
|
14
|
+
# """
|
|
15
|
+
# blender_path = os.getenv("BLENDER_PATH")
|
|
16
|
+
# blender_python = os.getenv("BLENDER_PYTHON")
|
|
17
|
+
|
|
18
|
+
# if blender_path is None or blender_python is None:
|
|
19
|
+
# msg = """
|
|
20
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
21
|
+
# BLENDER_PATH and BLENDER_PYTHON environment variables must be set.
|
|
22
|
+
# Example:
|
|
23
|
+
# export BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
|
|
24
|
+
# export BLENDER_PYTHON=/Applications/Blender.app/Contents/Resources/4.3/python/bin/python3.11
|
|
25
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
26
|
+
# """
|
|
27
|
+
# raise Exception(msg)
|
|
28
|
+
|
|
29
|
+
# self.blender_path = blender_path
|
|
30
|
+
# self.blender_python = blender_python
|
|
31
|
+
# self.output_blend = output_blend
|
|
32
|
+
# self.tmp_dir = "blender_tmp"
|
|
33
|
+
# self.log_path = os.path.join(self.tmp_dir, "blender_log.txt")
|
|
34
|
+
|
|
35
|
+
# os.makedirs(self.tmp_dir, exist_ok=True)
|
|
36
|
+
|
|
37
|
+
# def __call__(self, script: str):
|
|
38
|
+
# """Creates a temporary script file and runs it inside Blender."""
|
|
39
|
+
# temp_script_path = os.path.join(self.tmp_dir, "sceneprog_exec.py")
|
|
40
|
+
|
|
41
|
+
# # Save the script content to a temporary file
|
|
42
|
+
# with open(temp_script_path, "w") as f:
|
|
43
|
+
# f.write(script)
|
|
44
|
+
|
|
45
|
+
# # Run the script inside Blender
|
|
46
|
+
# output = self.run_script(temp_script_path)
|
|
47
|
+
|
|
48
|
+
# # Cleanup the temporary script file
|
|
49
|
+
# if os.path.exists(temp_script_path):
|
|
50
|
+
# os.remove(temp_script_path)
|
|
51
|
+
|
|
52
|
+
# return output
|
|
53
|
+
|
|
54
|
+
# def run_script(self, script_path, show_output=False):
|
|
55
|
+
# """Runs a given Python script inside Blender."""
|
|
56
|
+
# if not os.path.exists(script_path):
|
|
57
|
+
# print(f"β Error: Script {script_path} not found.")
|
|
58
|
+
# sys.exit(1)
|
|
59
|
+
|
|
60
|
+
# print(f"π Running script {script_path} in Blender...")
|
|
61
|
+
# os.system(f"{self.blender_path} --background --python {script_path} 2> {self.log_path}")
|
|
62
|
+
# with open(self.log_path, "r") as log_file:
|
|
63
|
+
# blender_output = log_file.read().strip()
|
|
64
|
+
# self.cleanup()
|
|
65
|
+
# if show_output:
|
|
66
|
+
# print(blender_output)
|
|
67
|
+
# return blender_output
|
|
68
|
+
|
|
69
|
+
# def install_packages(self, packages, hard_reset=False):
|
|
70
|
+
# """Installs Python packages inside Blender's environment."""
|
|
71
|
+
# if hard_reset:
|
|
72
|
+
# print("\nπ Performing Hard Reset...\n")
|
|
73
|
+
# self._delete_all_third_party_packages()
|
|
74
|
+
# self._delete_user_modules()
|
|
75
|
+
|
|
76
|
+
# for package in packages:
|
|
77
|
+
# print(f"π¦ Installing {package} inside Blender's Python...")
|
|
78
|
+
# os.system(f"{self.blender_python} -m pip install {package} --force 2> {self.log_path}")
|
|
79
|
+
# with open(self.log_path, "r") as log_file:
|
|
80
|
+
# print(log_file.read())
|
|
81
|
+
|
|
82
|
+
# print("β
All packages installed.")
|
|
83
|
+
|
|
84
|
+
# def _delete_all_third_party_packages(self):
|
|
85
|
+
# """Deletes all third-party packages from Blender's site-packages."""
|
|
86
|
+
# try:
|
|
87
|
+
# result = subprocess.run(
|
|
88
|
+
# [self.blender_python, "-m", "pip", "freeze"],
|
|
89
|
+
# capture_output=True, text=True
|
|
90
|
+
# )
|
|
91
|
+
# packages = [line.split("==")[0] for line in result.stdout.splitlines()]
|
|
92
|
+
|
|
93
|
+
# if not packages:
|
|
94
|
+
# print("β
No third-party packages found.")
|
|
95
|
+
# return
|
|
96
|
+
|
|
97
|
+
# print(f"ποΈ Removing {len(packages)} third-party packages...")
|
|
98
|
+
# subprocess.run(
|
|
99
|
+
# [self.blender_python, "-m", "pip", "uninstall", "-y"] + packages,
|
|
100
|
+
# text=True
|
|
101
|
+
# )
|
|
102
|
+
# print("β
All third-party packages removed.")
|
|
103
|
+
# except Exception as e:
|
|
104
|
+
# print(f"β οΈ Error removing packages: {e}")
|
|
105
|
+
|
|
106
|
+
# def _delete_user_modules(self):
|
|
107
|
+
# """Deletes all user-installed packages from Blender's user module directory."""
|
|
108
|
+
# if os.path.exists(self.user_modules):
|
|
109
|
+
# try:
|
|
110
|
+
# shutil.rmtree(self.user_modules)
|
|
111
|
+
# print(f"ποΈ Deleted all modules in {self.user_modules}")
|
|
112
|
+
# except Exception as e:
|
|
113
|
+
# print(f"β οΈ Could not delete user modules: {e}")
|
|
114
|
+
# else:
|
|
115
|
+
# print(f"β
No user modules found in {self.user_modules}")
|
|
116
|
+
|
|
117
|
+
# def cleanup(self):
|
|
118
|
+
# """π₯ Deletes the temporary directory `blender_tmp` after execution."""
|
|
119
|
+
# if os.path.exists(self.tmp_dir):
|
|
120
|
+
# shutil.rmtree(self.tmp_dir)
|
|
121
|
+
# print(f"ποΈ Cleanup: Deleted {self.tmp_dir}")
|
|
122
|
+
|
|
123
|
+
# def main():
|
|
124
|
+
# parser = argparse.ArgumentParser(description="SceneProgExecutor CLI")
|
|
125
|
+
# subparsers = parser.add_subparsers(dest="command")
|
|
126
|
+
|
|
127
|
+
# install_parser = subparsers.add_parser("install", help="Install packages inside Blender's Python")
|
|
128
|
+
# install_parser.add_argument("packages", nargs="+")
|
|
129
|
+
# install_parser.add_argument("--reset", action="store_true")
|
|
130
|
+
|
|
131
|
+
# run_parser = subparsers.add_parser("run", help="Run a Python script inside Blender")
|
|
132
|
+
# run_parser.add_argument("script_path")
|
|
133
|
+
|
|
134
|
+
# reset_parser = subparsers.add_parser("reset", help="Remove all third-party packages in Blender")
|
|
135
|
+
|
|
136
|
+
# args = parser.parse_args()
|
|
137
|
+
# executor = SceneProgExecutor()
|
|
138
|
+
|
|
139
|
+
# if args.command == "install":
|
|
140
|
+
# executor.install_packages(args.packages, hard_reset=args.reset)
|
|
141
|
+
# elif args.command == "run":
|
|
142
|
+
# executor.run_script(args.script_path, show_output=True)
|
|
143
|
+
# elif args.command == "reset":
|
|
144
|
+
# executor._delete_all_third_party_packages()
|
|
145
|
+
|
|
146
|
+
# if __name__ == "__main__":
|
|
147
|
+
# main()
|
|
148
|
+
|
|
149
|
+
#!/usr/bin/env python3
|
|
150
|
+
|
|
151
|
+
import os
|
|
152
|
+
import subprocess
|
|
153
|
+
import shutil
|
|
154
|
+
import argparse
|
|
155
|
+
import sys
|
|
156
|
+
import tempfile
|
|
157
|
+
|
|
158
|
+
class SceneProgExecutor:
|
|
159
|
+
def __init__(self, output_blend="scene_output.blend"):
|
|
160
|
+
"""
|
|
161
|
+
Initializes SceneProgExecutor with script execution and package management capabilities.
|
|
162
|
+
"""
|
|
163
|
+
blender_path = os.getenv("BLENDER_PATH")
|
|
164
|
+
blender_python = os.getenv("BLENDER_PYTHON")
|
|
165
|
+
|
|
166
|
+
if blender_path is None or blender_python is None:
|
|
167
|
+
msg = """
|
|
168
|
+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
169
|
+
BLENDER_PATH and BLENDER_PYTHON environment variables must be set.
|
|
170
|
+
Example:
|
|
171
|
+
export BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
|
|
172
|
+
export BLENDER_PYTHON=/Applications/Blender.app/Contents/Resources/4.3/python/bin/python3.11
|
|
173
|
+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
174
|
+
"""
|
|
175
|
+
raise Exception(msg)
|
|
176
|
+
|
|
177
|
+
self.blender_path = blender_path
|
|
178
|
+
self.blender_python = blender_python
|
|
179
|
+
self.output_blend = output_blend # Default .blend filename if none specified
|
|
180
|
+
self.tmp_dir = "blender_tmp"
|
|
181
|
+
self.log_path = os.path.join(self.tmp_dir, "blender_log.txt")
|
|
182
|
+
|
|
183
|
+
os.makedirs(self.tmp_dir, exist_ok=True)
|
|
184
|
+
|
|
185
|
+
def __call__(self, script: str, target: str = None):
|
|
186
|
+
"""
|
|
187
|
+
Creates a temporary script file and runs it inside Blender,
|
|
188
|
+
saving the .blend file to `target` if specified, otherwise
|
|
189
|
+
uses `self.output_blend`.
|
|
190
|
+
"""
|
|
191
|
+
if target is None:
|
|
192
|
+
target = self.output_blend
|
|
193
|
+
|
|
194
|
+
temp_script_path = os.path.join(self.tmp_dir, "sceneprog_exec.py")
|
|
195
|
+
|
|
196
|
+
# Save the script content to a temporary file
|
|
197
|
+
with open(temp_script_path, "w") as f:
|
|
198
|
+
f.write(script)
|
|
199
|
+
|
|
200
|
+
# Run the script inside Blender and save to `target`
|
|
201
|
+
output = self.run_script(temp_script_path, target=target)
|
|
202
|
+
|
|
203
|
+
# Cleanup the temporary script file
|
|
204
|
+
if os.path.exists(temp_script_path):
|
|
205
|
+
os.remove(temp_script_path)
|
|
206
|
+
|
|
207
|
+
return output
|
|
208
|
+
|
|
209
|
+
def run_script(self, script_path, show_output=False, target=None):
|
|
210
|
+
"""
|
|
211
|
+
Runs a given Python script inside Blender, saving
|
|
212
|
+
to the `.blend` path specified by `target` (or default).
|
|
213
|
+
"""
|
|
214
|
+
if not os.path.exists(script_path):
|
|
215
|
+
print(f"β Error: Script {script_path} not found.")
|
|
216
|
+
sys.exit(1)
|
|
217
|
+
|
|
218
|
+
if target is None:
|
|
219
|
+
target = self.output_blend
|
|
220
|
+
|
|
221
|
+
print(f"π Running script {script_path} in Blender and saving to {target}...")
|
|
222
|
+
|
|
223
|
+
# We append a small Python one-liner that saves the .blend file
|
|
224
|
+
blender_cmd = (
|
|
225
|
+
f"{self.blender_path} --background --python {script_path} "
|
|
226
|
+
f"--python-expr \"import bpy; bpy.ops.wm.save_mainfile(filepath=r'{target}')\" "
|
|
227
|
+
f"2> {self.log_path}"
|
|
228
|
+
)
|
|
229
|
+
os.system(blender_cmd)
|
|
230
|
+
|
|
231
|
+
# Read output log
|
|
232
|
+
with open(self.log_path, "r") as log_file:
|
|
233
|
+
blender_output = log_file.read().strip()
|
|
234
|
+
|
|
235
|
+
self.cleanup()
|
|
236
|
+
|
|
237
|
+
if show_output:
|
|
238
|
+
print(blender_output)
|
|
239
|
+
|
|
240
|
+
return blender_output
|
|
241
|
+
|
|
242
|
+
def install_packages(self, packages, hard_reset=False):
|
|
243
|
+
"""Installs Python packages inside Blender's environment."""
|
|
244
|
+
if hard_reset:
|
|
245
|
+
print("\nπ Performing Hard Reset...\n")
|
|
246
|
+
self._delete_all_third_party_packages()
|
|
247
|
+
self._delete_user_modules()
|
|
248
|
+
|
|
249
|
+
for package in packages:
|
|
250
|
+
print(f"π¦ Installing {package} inside Blender's Python...")
|
|
251
|
+
os.system(f"{self.blender_python} -m pip install {package} --force 2> {self.log_path}")
|
|
252
|
+
with open(self.log_path, "r") as log_file:
|
|
253
|
+
print(log_file.read())
|
|
254
|
+
|
|
255
|
+
print("β
All packages installed.")
|
|
256
|
+
|
|
257
|
+
def _delete_all_third_party_packages(self):
|
|
258
|
+
"""Deletes all third-party packages from Blender's site-packages."""
|
|
259
|
+
try:
|
|
260
|
+
result = subprocess.run(
|
|
261
|
+
[self.blender_python, "-m", "pip", "freeze"],
|
|
262
|
+
capture_output=True, text=True
|
|
263
|
+
)
|
|
264
|
+
packages = [line.split("==")[0] for line in result.stdout.splitlines()]
|
|
265
|
+
|
|
266
|
+
if not packages:
|
|
267
|
+
print("β
No third-party packages found.")
|
|
268
|
+
return
|
|
269
|
+
|
|
270
|
+
print(f"ποΈ Removing {len(packages)} third-party packages...")
|
|
271
|
+
subprocess.run(
|
|
272
|
+
[self.blender_python, "-m", "pip", "uninstall", "-y"] + packages,
|
|
273
|
+
text=True
|
|
274
|
+
)
|
|
275
|
+
print("β
All third-party packages removed.")
|
|
276
|
+
except Exception as e:
|
|
277
|
+
print(f"β οΈ Error removing packages: {e}")
|
|
278
|
+
|
|
279
|
+
def _delete_user_modules(self):
|
|
280
|
+
"""Deletes all user-installed packages from Blender's user module directory."""
|
|
281
|
+
if os.path.exists(self.user_modules):
|
|
282
|
+
try:
|
|
283
|
+
shutil.rmtree(self.user_modules)
|
|
284
|
+
print(f"ποΈ Deleted all modules in {self.user_modules}")
|
|
285
|
+
except Exception as e:
|
|
286
|
+
print(f"β οΈ Could not delete user modules: {e}")
|
|
287
|
+
else:
|
|
288
|
+
print(f"β
No user modules found in {self.user_modules}")
|
|
289
|
+
|
|
290
|
+
def cleanup(self):
|
|
291
|
+
"""π₯ Deletes the temporary directory `blender_tmp` after execution."""
|
|
292
|
+
if os.path.exists(self.tmp_dir):
|
|
293
|
+
shutil.rmtree(self.tmp_dir)
|
|
294
|
+
print(f"ποΈ Cleanup: Deleted {self.tmp_dir}")
|
|
295
|
+
|
|
296
|
+
def main():
|
|
297
|
+
parser = argparse.ArgumentParser(description="SceneProgExecutor CLI")
|
|
298
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
299
|
+
|
|
300
|
+
# Subcommand: install packages
|
|
301
|
+
install_parser = subparsers.add_parser("install", help="Install packages inside Blender's Python")
|
|
302
|
+
install_parser.add_argument("packages", nargs="+")
|
|
303
|
+
install_parser.add_argument("--reset", action="store_true")
|
|
304
|
+
|
|
305
|
+
# Subcommand: run a script
|
|
306
|
+
run_parser = subparsers.add_parser("run", help="Run a Python script inside Blender and save as a .blend file")
|
|
307
|
+
run_parser.add_argument("script_path")
|
|
308
|
+
run_parser.add_argument("--target", required=True, help="Path to save the resulting .blend file")
|
|
309
|
+
|
|
310
|
+
# Subcommand: reset third-party packages
|
|
311
|
+
reset_parser = subparsers.add_parser("reset", help="Remove all third-party packages in Blender")
|
|
312
|
+
|
|
313
|
+
args = parser.parse_args()
|
|
314
|
+
executor = SceneProgExecutor()
|
|
315
|
+
|
|
316
|
+
if args.command == "install":
|
|
317
|
+
executor.install_packages(args.packages, hard_reset=args.reset)
|
|
318
|
+
elif args.command == "run":
|
|
319
|
+
executor.run_script(args.script_path, show_output=True, target=args.target)
|
|
320
|
+
elif args.command == "reset":
|
|
321
|
+
executor._delete_all_third_party_packages()
|
|
322
|
+
|
|
323
|
+
if __name__ == "__main__":
|
|
324
|
+
main()
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: sceneprogexec
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A CLI and Python module for executing Blender scripts and managing Blender's Python environment. Built to support SceneProg projects.
|
|
5
|
+
Home-page: https://github.com/KunalMGupta/SceneProgExec
|
|
6
|
+
Author: Kunal Gupta
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Dynamic: author
|
|
13
|
+
Dynamic: classifier
|
|
14
|
+
Dynamic: description
|
|
15
|
+
Dynamic: description-content-type
|
|
16
|
+
Dynamic: home-page
|
|
17
|
+
Dynamic: requires-python
|
|
18
|
+
Dynamic: summary
|
|
19
|
+
|
|
20
|
+
# π SceneProgExec: Blender Python Script & Package Manager
|
|
21
|
+
|
|
22
|
+
**SceneProgExec** is a command-line tool and Python module that enables seamless execution of **Blender scripts** and **package management** within Blender's **isolated Python environment**.
|
|
23
|
+
|
|
24
|
+
## π₯ Features
|
|
25
|
+
β
**Execute Python scripts inside Blender**
|
|
26
|
+
β
**Install Python packages in Blender's Python environment**
|
|
27
|
+
β
**Perform a full reset (remove all third-party packages)**
|
|
28
|
+
β
**Automatically cleans up temporary files after execution**
|
|
29
|
+
β
**Works both as a CLI tool and a Python module**
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## π₯ Installation
|
|
34
|
+
|
|
35
|
+
### **1οΈβ£ Install from PyPI**
|
|
36
|
+
```bash
|
|
37
|
+
pip install sceneprogexec
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
OR **Clone the Repository**
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/KunalMGupta/SceneProgExec.git
|
|
43
|
+
cd SceneProgExec
|
|
44
|
+
pip install .
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### **2οΈβ£ Set Environment Variables**
|
|
48
|
+
Before using `SceneProgExec`, set the required environment variables:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
export BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
|
|
52
|
+
export BLENDER_PYTHON=/Applications/Blender.app/Contents/Resources/4.3/python/bin/python3.11
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
To make this **permanent**, add the lines to your `~/.bashrc` or `~/.zshrc`:
|
|
56
|
+
```bash
|
|
57
|
+
echo 'export BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender' >> ~/.zshrc
|
|
58
|
+
echo 'export BLENDER_PYTHON=/Applications/Blender.app/Contents/Resources/4.3/python/bin/python3.11' >> ~/.zshrc
|
|
59
|
+
source ~/.zshrc
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### **3οΈβ£ Run CLI Commands**
|
|
63
|
+
Once installed, you can use `sceneprogexec` globally.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## π οΈ Usage
|
|
68
|
+
|
|
69
|
+
### **πΉ Run a Python Script Inside Blender**
|
|
70
|
+
```bash
|
|
71
|
+
sceneprogexec run my_script.py --target my_scene.blend
|
|
72
|
+
```
|
|
73
|
+
β
Runs `my_script.py` inside **Blender**.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### **πΉ Install Packages Inside Blender**
|
|
78
|
+
```bash
|
|
79
|
+
sceneprogexec install numpy pandas
|
|
80
|
+
```
|
|
81
|
+
β
Installs `numpy` and `pandas` inside **Blenderβs Python**.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### **πΉ Install Packages With a Hard Reset**
|
|
86
|
+
```bash
|
|
87
|
+
sceneprogexec install numpy pandas --reset
|
|
88
|
+
```
|
|
89
|
+
β
**Removes all third-party packages** before installing new ones.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### **πΉ Reset Blender's Python (Remove All Third-Party Packages)**
|
|
94
|
+
```bash
|
|
95
|
+
sceneprogexec reset
|
|
96
|
+
```
|
|
97
|
+
ποΈ **Deletes all third-party Python packages** in Blender.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## ποΈ **Using as a Python Module**
|
|
102
|
+
SceneProgExec can also be **imported and used in Python scripts**:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from sceneprogexec import SceneProgExec
|
|
106
|
+
|
|
107
|
+
executor = SceneProgExec()
|
|
108
|
+
executor.install_packages(["numpy"])
|
|
109
|
+
executor.run_script("my_script.py")
|
|
110
|
+
executor._delete_all_third_party_packages() # Hard reset
|
|
111
|
+
|
|
112
|
+
script = """
|
|
113
|
+
import bpy
|
|
114
|
+
print("Hello, World!")
|
|
115
|
+
"""
|
|
116
|
+
executor(script, target="test.blend")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## π **Automatic Cleanup**
|
|
122
|
+
- **Temporary directory (`blender_tmp`) is deleted** after execution.
|
|
123
|
+
- **No leftover logs or scripts clutter your system**.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## π οΈ **Troubleshooting**
|
|
128
|
+
β **Blender not found?**
|
|
129
|
+
Ensure `BLENDER_PATH` and `BLENDER_PYTHON` are correctly set. Run:
|
|
130
|
+
```bash
|
|
131
|
+
echo $BLENDER_PATH
|
|
132
|
+
echo $BLENDER_PYTHON
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
β **Permission denied?**
|
|
136
|
+
Try:
|
|
137
|
+
```bash
|
|
138
|
+
chmod +x /usr/local/bin/sceneprogexec
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
β **Blender script fails to execute?**
|
|
142
|
+
Check the log:
|
|
143
|
+
```bash
|
|
144
|
+
cat blender_tmp/blender_log.txt
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## π License
|
|
150
|
+
This project is licensed under the **MIT License**.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## π¨βπ» Author
|
|
155
|
+
Developed by **Kunal Gupta**
|
|
156
|
+
GitHub: [KunalMGupta](https://github.com/KunalMGupta)
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## β **Support the Project**
|
|
161
|
+
If you find this tool useful, give it a β on GitHub!
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
sceneprogexec/__init__.py
|
|
4
|
+
sceneprogexec/__main__.py
|
|
5
|
+
sceneprogexec/exec.py
|
|
6
|
+
sceneprogexec.egg-info/PKG-INFO
|
|
7
|
+
sceneprogexec.egg-info/SOURCES.txt
|
|
8
|
+
sceneprogexec.egg-info/dependency_links.txt
|
|
9
|
+
sceneprogexec.egg-info/entry_points.txt
|
|
10
|
+
sceneprogexec.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sceneprogexec
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as f:
|
|
4
|
+
long_description = f.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="sceneprogexec",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
packages=find_packages(), # Automatically finds the 'sceneprogexec' package (and any sub-packages)
|
|
10
|
+
entry_points={
|
|
11
|
+
"console_scripts": [
|
|
12
|
+
# If 'main()' is defined in exec.py, reference it here.
|
|
13
|
+
"sceneprogexec=sceneprogexec.exec:main",
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
install_requires=[], # Add any dependencies here
|
|
17
|
+
author="Kunal Gupta",
|
|
18
|
+
description="A CLI and Python module for executing Blender scripts and managing Blender's Python environment. Built to support SceneProg projects.",
|
|
19
|
+
long_description=long_description,
|
|
20
|
+
long_description_content_type="text/markdown",
|
|
21
|
+
url="https://github.com/KunalMGupta/SceneProgExec",
|
|
22
|
+
classifiers=[
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Environment :: Console",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
],
|
|
27
|
+
python_requires=">=3.9",
|
|
28
|
+
)
|