Skip to content

Commit 82d5ed6

Browse files
authored
Merge branch 'main' into black_formatting
2 parents 4a58fdf + c504b9d commit 82d5ed6

File tree

5 files changed

+335
-75
lines changed

5 files changed

+335
-75
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
* Added `Data.sha256` for computing a hash value of data objects, for example for comparisons during version control.
1515
* Added optional `path` parameter to `compas.rpc.Proxy` to allow for non-package calls.
1616
* Added Grasshopper component to call RPC functions.
17+
* Added alternative installation procedure for Blender on Windows.
1718
* Added `Mesh.to_lines` method and tests.
1819
* Added `Data.guid` to JSON serialization.
1920
* Added `Data.guid` to pickle state.
@@ -23,11 +24,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2324

2425
* Set `jinja >= 3.0` to dev dependencies to fix docs build error.
2526
* Fixed removing of collections for `compas_plotters`.
27+
* Fixed bug in `compas_plotters.plotter.Plotter.add_from_list`.
2628
* Fixed bug in `compas.robots.Configuration`.
2729
* Rebuild part index after deserialization in `Assembly`.
2830
* Fixed bug in `compas.artists.colordict.ColorDict`.
2931
* Change `Mesh.mesh_dual` with option of including the boundary.
3032
* Moved from `autopep8` to `black`
33+
* Fixed bug in `compas.utilities.linspace` for number series with high precision start and stop values.
3134

3235
### Removed
3336

docs/gettingstarted/blender.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ It is important that the version of Python installed in the ``conda`` environmen
1212
the version of Python that was originally shipped with Blender. For Blender 2.83 LTS
1313
the version of the bundled Python is 3.7, and for 2.93 LTS it is 3.9.
1414

15+
.. note::
16+
17+
On windows, the standard installation procedure recently stopped working.
18+
For an alternative procedure see `Installation on Windows`_.
19+
1520

1621
Installation
1722
============
@@ -178,3 +183,37 @@ Alternatively, you can create a new environment and simply install entire COMPAS
178183
conda activate blender
179184
pip install compas
180185
python -m compas_blender.install
186+
187+
188+
Installation on Windows
189+
=======================
190+
191+
On Windows, the procedure described above no longer works.
192+
However, an alternative procedure is still possible.
193+
Note that since this procedure is based on installing COMPAS directly using the `python` and `pip` executables shipped with Blender,
194+
it is limited to packages that can be installed from the Python Package Index (PyPI).
195+
196+
The basic command will install `compas` and `compas_blender` (and `compas_rhino` and `compas_ghpython`) for the default version of Blender (2.93),
197+
if that version can be found in the default installation location.
198+
199+
.. code-block:: bash
200+
201+
python -m compas_blender.install_windows
202+
203+
Install for a different version.
204+
205+
.. code-block:: bash
206+
207+
python -m compas_blender.install_windows -v 3.1
208+
209+
Install additional packages.
210+
211+
.. code-block:: bash
212+
213+
python -m compas_blender.install_windows -p compas_cloud
214+
215+
Install with `pip` configuration options.
216+
217+
.. code-block:: bash
218+
219+
python -m compas_blender.install_windows --force-reinstall --no-deps

src/compas/utilities/itertools.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616

1717

1818
__all__ = [
19-
'normalize_values',
20-
'remap_values',
21-
'meshgrid',
22-
'linspace',
23-
'flatten',
24-
'pairwise',
25-
'window',
26-
'iterable_like',
27-
'grouper'
19+
"normalize_values",
20+
"remap_values",
21+
"meshgrid",
22+
"linspace",
23+
"flatten",
24+
"pairwise",
25+
"window",
26+
"iterable_like",
27+
"grouper",
2828
]
2929

3030

@@ -57,12 +57,14 @@ def normalize_values(values, new_min=0.0, new_max=1.0):
5757
"""
5858
old_max = max(values)
5959
old_min = min(values)
60-
old_range = (old_max - old_min)
61-
new_range = (new_max - new_min)
60+
old_range = old_max - old_min
61+
new_range = new_max - new_min
6262
return [(((value - old_min) * new_range) / old_range) + new_min for value in values]
6363

6464

65-
def remap_values(values, target_min=0.0, target_max=1.0, original_min=None, original_max=None):
65+
def remap_values(
66+
values, target_min=0.0, target_max=1.0, original_min=None, original_max=None
67+
):
6668
"""Maps a list of numbers from one domain to another.
6769
6870
Parameters
@@ -94,7 +96,7 @@ def remap_values(values, target_min=0.0, target_max=1.0, original_min=None, orig
9496
return [target_min + ((value - original_min) * ratio) for value in values]
9597

9698

97-
def meshgrid(x, y, indexing='xy'):
99+
def meshgrid(x, y, indexing="xy"):
98100
"""Construct coordinate matrices from two coordinate vectors.
99101
100102
Parameters
@@ -153,7 +155,7 @@ def meshgrid(x, y, indexing='xy'):
153155
"""
154156
x = list(x)
155157
y = list(y)
156-
if indexing == 'xy':
158+
if indexing == "xy":
157159
X = [[x[j] for j in range(len(x))] for i in range(len(y))]
158160
Y = [[y[i] for j in range(len(x))] for i in range(len(y))]
159161
else:
@@ -193,8 +195,9 @@ def linspace(start, stop, num=50):
193195
194196
"""
195197
step = (stop - start) / (num - 1)
196-
for i in range(num):
198+
for i in range(num - 1):
197199
yield start + i * step
200+
yield float(stop)
198201

199202

200203
def flatten(list_of_lists):
@@ -364,8 +367,7 @@ def padnone(iterable):
364367

365368

366369
def grouper(iterable, n, fillvalue=None):
367-
"""Collect data into fixed-length chunks or blocks.
368-
"""
370+
"""Collect data into fixed-length chunks or blocks."""
369371
args = [iter(iterable)] * n
370372
return zip_longest(*args, fillvalue=fillvalue)
371373

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import os
2+
import sys
3+
import subprocess
4+
5+
import compas
6+
import compas_blender
7+
8+
from compas._os import remove
9+
from compas._os import remove_symlink
10+
from compas._os import rename
11+
12+
13+
BOOTSTRAPPER_TEMPLATE = """
14+
import os
15+
import sys
16+
17+
import bpy
18+
19+
ENVIRONMENT_NAME = r"{}"
20+
PYTHON_DIRECTORY = r"{}"
21+
22+
def register():
23+
pass
24+
25+
def unregister():
26+
pass
27+
28+
"""
29+
30+
31+
def install_windows(
32+
blender_path, version=None, packages=None, force_reinstall=False, no_deps=False
33+
):
34+
"""Install COMPAS for Blender on Windows.
35+
36+
Parameters
37+
----------
38+
blender_path : str
39+
The path to the folder with the version number of Blender.
40+
For example, on Mac: ``'/Applications/Blender.app/Contents/Resources/2.83'``.
41+
On Windows: ``'%PROGRAMFILES%/Blender Foundation/Blender 2.83/2.83'``.
42+
version : {'2.83', '2.93', '3.1'}, optional
43+
The version number of Blender.
44+
Default is ``'2.93'``.
45+
packages : list[str], optional
46+
Additional packages to install.
47+
Note that the packages should be available on the Python Package Index (PyPI).
48+
force_reinstall : bool, optional
49+
Force existing packages to be reinstalled.
50+
no_deps : bool, optional
51+
Ignore requirements of the specified packages during installation.
52+
53+
Examples
54+
--------
55+
.. code-block:: bash
56+
57+
$ python -m compas_blender.install
58+
59+
.. code-block:: bash
60+
61+
$ python -m compas_blender.install -v 2.93
62+
63+
.. code-block:: bash
64+
65+
$ python -m compas_blender.install /Applications/Blender.app/Contents/Resources/2.93
66+
67+
"""
68+
if not compas.WINDOWS:
69+
print(
70+
"This install procedure is only suited for installations on Windows. Please use the basic install instead..."
71+
)
72+
sys.exit(-1)
73+
74+
if not version and not blender_path:
75+
version = "2.93"
76+
77+
if version and blender_path:
78+
print(
79+
"Both options cannot be provided simultaneously. Provide the full installation path, or the version with flag -v."
80+
)
81+
sys.exit(-1)
82+
83+
if version:
84+
if compas.LINUX:
85+
print(
86+
"Version-based installs are currently not supported for Linux. Please provide the full installation path with the -p option."
87+
)
88+
sys.exit(-1)
89+
90+
blender_path = compas_blender._get_default_blender_installation_path(version)
91+
92+
if not os.path.exists(blender_path):
93+
raise FileNotFoundError("Blender version folder not found.")
94+
95+
path, version = os.path.split(blender_path)
96+
97+
print("Installing COMPAS for Blender {}".format(version))
98+
99+
startup = os.path.join(blender_path, "scripts", "startup")
100+
101+
blenderpython_src = os.path.join(blender_path, "python")
102+
blenderpython_dst = os.path.join(blender_path, "original_python")
103+
compas_bootstrapper = os.path.join(startup, "compas_bootstrapper.py")
104+
105+
if os.path.exists(blenderpython_dst):
106+
print("Found existing installation, restoring bundled python installation...")
107+
if os.path.exists(blenderpython_src):
108+
remove_symlink(blenderpython_src)
109+
110+
print(
111+
" Renaming original_python back to bundled python folder: {} => {}".format(
112+
blenderpython_dst, blenderpython_src
113+
)
114+
)
115+
rename(blenderpython_dst, blenderpython_src)
116+
117+
if os.path.exists(compas_bootstrapper):
118+
print(" Removing compas bootstrapper...")
119+
remove(compas_bootstrapper)
120+
121+
# Install COMPAS by running a subprocess triggering pip
122+
blenderpython = os.path.join(blender_path, "python", "bin", "python.exe")
123+
124+
try:
125+
subprocess.run(
126+
[blenderpython, "-m", "pip", "install", "--upgrade", "pip"], check=True
127+
)
128+
except subprocess.CalledProcessError:
129+
print("Could not upgrade pip")
130+
sys.exit(-1)
131+
132+
try:
133+
args = [blenderpython, "-m", "pip", "install", "compas"]
134+
if packages:
135+
args += packages
136+
if force_reinstall:
137+
args.append("--force-reinstall")
138+
if no_deps:
139+
args.append("--no-deps")
140+
141+
subprocess.run(args, check=True)
142+
except subprocess.CalledProcessError:
143+
print("Could not install compas or some of the requested additional packages.")
144+
sys.exit(-1)
145+
146+
# # Take either the CONDA environment directory or the current Python executable's directory
147+
# python_directory = os.environ.get("CONDA_PREFIX", None) or os.path.dirname(
148+
# sys.executable
149+
# )
150+
# environment_name = os.environ.get("CONDA_DEFAULT_ENV", "")
151+
152+
# Get current sys.version value, we will override it inside Blender
153+
# because it seems Blender overrides it as well, but doing so breaks many things after having replaced the Python interpreter
154+
155+
# _handle, bootstrapper_temp_path = tempfile.mkstemp(suffix=".py", text=True)
156+
157+
# with open(bootstrapper_temp_path, "w") as f:
158+
# f.write(BOOTSTRAPPER_TEMPLATE.format(environment_name, python_directory))
159+
160+
# print(" Creating bootstrap script: {}".format(compas_bootstrapper))
161+
# copy(bootstrapper_temp_path, compas_bootstrapper)
162+
163+
print()
164+
print("COMPAS for Blender {} has been installed via pip.".format(version))
165+
print(
166+
"Note that functionaliy of conda-only packages has to be run via the command server (RPC)."
167+
)
168+
169+
170+
# ==============================================================================
171+
# Main
172+
# ==============================================================================
173+
174+
if __name__ == "__main__":
175+
176+
import argparse
177+
178+
parser = argparse.ArgumentParser()
179+
180+
parser.add_argument(
181+
"blenderpath",
182+
nargs="?",
183+
help="The path to the folder with the version number of Blender.",
184+
)
185+
parser.add_argument(
186+
"-v",
187+
"--version",
188+
choices=["2.83", "2.93", "3.1"],
189+
help="The version of Blender to install COMPAS in.",
190+
)
191+
parser.add_argument("-p", "--packages", nargs="+", help="The packages to install.")
192+
parser.add_argument(
193+
"--force-reinstall", dest="force_reinstall", default=False, action="store_true"
194+
)
195+
parser.add_argument("--no-deps", dest="no_deps", default=False, action="store_true")
196+
197+
args = parser.parse_args()
198+
199+
install_windows(
200+
args.blenderpath,
201+
version=args.version,
202+
packages=args.packages,
203+
force_reinstall=args.force_reinstall,
204+
no_deps=args.no_deps,
205+
)

0 commit comments

Comments
 (0)